diff options
| author | Andrii Tseglytskyi <andrii.tseglytskyi@ti.com> | 2013-05-20 22:42:08 +0000 | 
|---|---|---|
| committer | Tom Rini <trini@ti.com> | 2013-06-10 08:43:09 -0400 | 
| commit | 4d0df9c1e94f32a9695be352fead3167fb5135c7 (patch) | |
| tree | f1295abc801b55014db970ee1727d8ae206bc232 | |
| parent | a662e0c345b4cd9f4c2d51796154ad4a345a72a5 (diff) | |
| download | olio-uboot-2014.01-4d0df9c1e94f32a9695be352fead3167fb5135c7.tar.xz olio-uboot-2014.01-4d0df9c1e94f32a9695be352fead3167fb5135c7.zip | |
OMAP3+: introduce generic ABB support
Adaptive Body Biasing (ABB) modulates transistor bias voltages
dynamically in order to optimize switching speed versus leakage.
Adaptive Body-Bias ldos are present for some voltage domains
starting with OMAP3630. There are three modes of operation:
* Bypass - the default, it just follows the vdd voltage
* Foward Body-Bias - applies voltage bias to increase transistor
  performance at the cost of power.  Used to operate safely at high
  OPPs.
* Reverse Body-Bias - applies voltage bias to decrease leakage and
  save power.  Used to save power at lower OPPs.
Signed-off-by: Andrii Tseglytskyi <andrii.tseglytskyi@ti.com>
Acked-by: Nishanth Menon <nm@ti.com>
| -rw-r--r-- | arch/arm/cpu/armv7/omap-common/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/cpu/armv7/omap-common/abb.c | 137 | ||||
| -rw-r--r-- | arch/arm/cpu/armv7/omap5/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/cpu/armv7/omap5/abb.c | 67 | ||||
| -rw-r--r-- | arch/arm/include/asm/arch-omap3/omap3.h | 7 | ||||
| -rw-r--r-- | arch/arm/include/asm/arch-omap4/omap.h | 8 | ||||
| -rw-r--r-- | arch/arm/include/asm/arch-omap5/omap.h | 13 | ||||
| -rw-r--r-- | arch/arm/include/asm/omap_common.h | 22 | 
8 files changed, 256 insertions, 0 deletions
| diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile index 55e82ba36..c4b9809ad 100644 --- a/arch/arm/cpu/armv7/omap-common/Makefile +++ b/arch/arm/cpu/armv7/omap-common/Makefile @@ -34,6 +34,7 @@ COBJS	+= hwinit-common.o  COBJS	+= clocks-common.o  COBJS	+= emif-common.o  COBJS	+= vc.o +COBJS	+= abb.o  endif  ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TI814X),) diff --git a/arch/arm/cpu/armv7/omap-common/abb.c b/arch/arm/cpu/armv7/omap-common/abb.c new file mode 100644 index 000000000..87d1fb82e --- /dev/null +++ b/arch/arm/cpu/armv7/omap-common/abb.c @@ -0,0 +1,137 @@ +/* + * + * Adaptive Body Bias programming sequence for OMAP family + * + * (C) Copyright 2013 + * Texas Instruments, <www.ti.com> + * + * Andrii Tseglytskyi <andrii.tseglytskyi@ti.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/omap_common.h> +#include <asm/io.h> +#include <asm/arch/sys_proto.h> + +__weak s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb) +{ +	return -1; +} + +static void abb_setup_timings(u32 setup) +{ +	u32 sys_rate, sr2_cnt, clk_cycles; + +	/* +	 * SR2_WTCNT_VALUE is the settling time for the ABB ldo after a +	 * transition and must be programmed with the correct time at boot. +	 * The value programmed into the register is the number of SYS_CLK +	 * clock cycles that match a given wall time profiled for the ldo. +	 * This value depends on: +	 * settling time of ldo in micro-seconds (varies per OMAP family), +	 * of clock cycles per SYS_CLK period (varies per OMAP family), +	 * the SYS_CLK frequency in MHz (varies per board) +	 * The formula is: +	 * +	 *		       ldo settling time (in micro-seconds) +	 * SR2_WTCNT_VALUE = ------------------------------------------ +	 *		    (# system clock cycles) * (sys_clk period) +	 * +	 * Put another way: +	 * +	 * SR2_WTCNT_VALUE = settling time / (# SYS_CLK cycles / SYS_CLK rate)) +	 * +	 * To avoid dividing by zero multiply both "# clock cycles" and +	 * "settling time" by 10 such that the final result is the one we want. +	 */ + +	/* calculate SR2_WTCNT_VALUE */ +	sys_rate = DIV_ROUND(V_OSCK, 1000000); +	clk_cycles = DIV_ROUND(OMAP_ABB_CLOCK_CYCLES * 10, sys_rate); +	sr2_cnt = DIV_ROUND(OMAP_ABB_SETTLING_TIME * 10, clk_cycles); + +	setbits_le32(setup, +		     sr2_cnt << (ffs(OMAP_ABB_SETUP_SR2_WTCNT_VALUE_MASK) - 1)); +} + +void abb_setup(u32 fuse, u32 ldovbb, u32 setup, u32 control, +	       u32 txdone, u32 txdone_mask, u32 opp) +{ +	u32 abb_type_mask, opp_sel_mask; + +	/* sanity check */ +	if (!setup || !control || !txdone) +		return; + +	/* setup ABB only in case of Fast or Slow OPP */ +	switch (opp) { +	case OMAP_ABB_FAST_OPP: +		abb_type_mask = OMAP_ABB_SETUP_ACTIVE_FBB_SEL_MASK; +		opp_sel_mask = OMAP_ABB_CONTROL_FAST_OPP_SEL_MASK; +		break; +	case OMAP_ABB_SLOW_OPP: +		abb_type_mask = OMAP_ABB_SETUP_ACTIVE_RBB_SEL_MASK; +		opp_sel_mask = OMAP_ABB_CONTROL_SLOW_OPP_SEL_MASK; +		break; +	default: +	       return; +	} + +	/* +	 * For some OMAP silicons additional setup for LDOVBB register is +	 * required. This is determined by data retrieved from corresponding +	 * OPP EFUSE register. Data, which is retrieved from EFUSE - is +	 * ABB enable/disable flag and VSET value, which must be copied +	 * to LDOVBB register. If function call fails - return quietly, +	 * it means no ABB is required for such silicon. +	 * +	 * For silicons, which don't require LDOVBB setup "fuse" and +	 * "ldovbb" offsets are not defined. ABB will be initialized in +	 * the common way for them. +	 */ +	if (fuse && ldovbb) { +		if (abb_setup_ldovbb(fuse, ldovbb)) +			return; +	} + +	/* clear ABB registers */ +	writel(0, setup); +	writel(0, control); + +	/* configure timings, based on oscillator value */ +	abb_setup_timings(setup); + +	/* clear pending interrupts before setup */ +	setbits_le32(txdone, txdone_mask); + +	/* select ABB type */ +	setbits_le32(setup, abb_type_mask | OMAP_ABB_SETUP_SR2EN_MASK); + +	/* initiate ABB ldo change */ +	setbits_le32(control, opp_sel_mask | OMAP_ABB_CONTROL_OPP_CHANGE_MASK); + +	/* wait until transition complete */ +	if (!wait_on_value(txdone_mask, txdone_mask, (void *)txdone, LDELAY)) +		puts("Error: ABB txdone is not set\n"); + +	/* clear ABB tranxdone */ +	setbits_le32(txdone, txdone_mask); +} diff --git a/arch/arm/cpu/armv7/omap5/Makefile b/arch/arm/cpu/armv7/omap5/Makefile index ce00e2c3c..6ff8dbb4e 100644 --- a/arch/arm/cpu/armv7/omap5/Makefile +++ b/arch/arm/cpu/armv7/omap5/Makefile @@ -30,6 +30,7 @@ COBJS	+= emif.o  COBJS	+= sdram.o  COBJS	+= prcm-regs.o  COBJS	+= hw_data.o +COBJS	+= abb.o  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS)) diff --git a/arch/arm/cpu/armv7/omap5/abb.c b/arch/arm/cpu/armv7/omap5/abb.c new file mode 100644 index 000000000..92470becc --- /dev/null +++ b/arch/arm/cpu/armv7/omap5/abb.c @@ -0,0 +1,67 @@ +/* + * + * Adaptive Body Bias programming sequence for OMAP5 family + * + * (C) Copyright 2013 + * Texas Instruments, <www.ti.com> + * + * Andrii Tseglytskyi <andrii.tseglytskyi@ti.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/omap_common.h> +#include <asm/io.h> + +/* + * Setup LDOVBB for OMAP5. + * On OMAP5+ some ABB settings are fused. They are handled + * in the following way: + * + * 1. corresponding EFUSE register contains ABB enable bit + *    and VSET value + * 2. If ABB enable bit is set to 1, than ABB should be + *    enabled, otherwise ABB should be disabled + * 3. If ABB is enabled, than VSET value should be copied + *    to corresponding MUX control register + */ +s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb) +{ +	u32 vset; + +	/* +	 * ABB parameters must be properly fused +	 * otherwise ABB should be disabled +	 */ +	vset = readl(fuse); +	if (!(vset & OMAP5_ABB_FUSE_ENABLE_MASK)) +		return -1; + +	/* prepare VSET value for LDOVBB mux register */ +	vset &= OMAP5_ABB_FUSE_VSET_MASK; +	vset >>= ffs(OMAP5_ABB_FUSE_VSET_MASK) - 1; +	vset <<= ffs(OMAP5_ABB_LDOVBBMPU_VSET_OUT_MASK) - 1; +	vset |= OMAP5_ABB_LDOVBBMPU_MUX_CTRL_MASK; + +	/* setup LDOVBB using fused value */ +	clrsetbits_le32(ldovbb,  OMAP5_ABB_LDOVBBMPU_VSET_OUT_MASK, vset); + +	return 0; +} diff --git a/arch/arm/include/asm/arch-omap3/omap3.h b/arch/arm/include/asm/arch-omap3/omap3.h index 2b5e9aeae..c57599a93 100644 --- a/arch/arm/include/asm/arch-omap3/omap3.h +++ b/arch/arm/include/asm/arch-omap3/omap3.h @@ -253,4 +253,11 @@ struct gpio {  #define OMAP3_EMU_HAL_START_HAL_CRITICAL	4 +/* ABB settings */ +#define OMAP_ABB_SETTLING_TIME		30 +#define OMAP_ABB_CLOCK_CYCLES		8 + +/* ABB tranxdone mask */ +#define OMAP_ABB_MPU_TXDONE_MASK	(0x1 << 26) +  #endif diff --git a/arch/arm/include/asm/arch-omap4/omap.h b/arch/arm/include/asm/arch-omap4/omap.h index e9a6ffeb8..55a07605b 100644 --- a/arch/arm/include/asm/arch-omap4/omap.h +++ b/arch/arm/include/asm/arch-omap4/omap.h @@ -143,4 +143,12 @@ struct s32ktimer {  #define NON_SECURE_SRAM_END	0x4030E000	/* Not inclusive */  /* base address for indirect vectors (internal boot mode) */  #define SRAM_ROM_VECT_BASE	0x4030D000 + +/* ABB settings */ +#define OMAP_ABB_SETTLING_TIME		50 +#define OMAP_ABB_CLOCK_CYCLES		16 + +/* ABB tranxdone mask */ +#define OMAP_ABB_MPU_TXDONE_MASK	(0x1 << 7) +  #endif diff --git a/arch/arm/include/asm/arch-omap5/omap.h b/arch/arm/include/asm/arch-omap5/omap.h index 4f43a903d..1c1a64bd2 100644 --- a/arch/arm/include/asm/arch-omap5/omap.h +++ b/arch/arm/include/asm/arch-omap5/omap.h @@ -215,6 +215,19 @@ struct s32ktimer {  #define SRCODE_OVERRIDE_SEL_XS_SHIFT	0  #define SRCODE_OVERRIDE_SEL_XS_MASK	(1 << 0) +/* ABB settings */ +#define OMAP_ABB_SETTLING_TIME		50 +#define OMAP_ABB_CLOCK_CYCLES		16 + +/* ABB tranxdone mask */ +#define OMAP_ABB_MPU_TXDONE_MASK		(0x1 << 7) + +/* ABB efuse masks */ +#define OMAP5_ABB_FUSE_VSET_MASK		(0x1F << 24) +#define OMAP5_ABB_FUSE_ENABLE_MASK		(0x1 << 29) +#define OMAP5_ABB_LDOVBBMPU_MUX_CTRL_MASK	(0x1 << 10) +#define OMAP5_ABB_LDOVBBMPU_VSET_OUT_MASK	(0x1f << 0) +  #ifndef __ASSEMBLY__  struct srcomp_params {  	s8 divide_factor; diff --git a/arch/arm/include/asm/omap_common.h b/arch/arm/include/asm/omap_common.h index ee7b188d3..f8f3719bd 100644 --- a/arch/arm/include/asm/omap_common.h +++ b/arch/arm/include/asm/omap_common.h @@ -242,6 +242,8 @@ struct prcm_regs {  	u32 cm_l3init_fsusb_clkctrl;  	u32 cm_l3init_ocp2scp1_clkctrl; +	u32 prm_irqstatus_mpu_2; +  	/* cm2.l4per */  	u32 cm_l4per_clkstctrl;  	u32 cm_l4per_dynamicdep; @@ -328,6 +330,8 @@ struct prcm_regs {  	u32 prm_sldo_mpu_ctrl;  	u32 prm_sldo_mm_setup;  	u32 prm_sldo_mm_ctrl; +	u32 prm_abbldo_mpu_setup; +	u32 prm_abbldo_mpu_ctrl;  	u32 cm_div_m4_dpll_core;  	u32 cm_div_m5_dpll_core; @@ -350,6 +354,7 @@ struct prcm_regs {  struct omap_sys_ctrl_regs {  	u32 control_status; +	u32 control_std_fuse_opp_vdd_mpu_2;  	u32 control_core_mmr_lock1;  	u32 control_core_mmr_lock2;  	u32 control_core_mmr_lock3; @@ -419,6 +424,7 @@ struct omap_sys_ctrl_regs {  	u32 control_port_emif2_sdram_config;  	u32 control_emif1_sdram_config_ext;  	u32 control_emif2_sdram_config_ext; +	u32 control_wkup_ldovbb_mpu_voltage_ctrl;  	u32 control_smart1nopmio_padconf_0;  	u32 control_smart1nopmio_padconf_1;  	u32 control_padconf_mode; @@ -545,6 +551,9 @@ void enable_non_essential_clocks(void);  void scale_vcores(struct vcores_data const *);  u32 get_offset_code(u32 volt_offset, struct pmic_data *pmic);  void do_scale_vcore(u32 vcore_reg, u32 volt_mv, struct pmic_data *pmic); +void abb_setup(u32 fuse, u32 ldovbb, u32 setup, u32 control, +	       u32 txdone, u32 txdone_mask, u32 opp); +s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb);  /* Max value for DPLL multiplier M */  #define OMAP_DPLL_MAX_N	127 @@ -555,6 +564,19 @@ void do_scale_vcore(u32 vcore_reg, u32 volt_mv, struct pmic_data *pmic);  #define OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL	2  #define OMAP_INIT_CONTEXT_UBOOT_AFTER_CH	3 +/* ABB */ +#define OMAP_ABB_NOMINAL_OPP		0 +#define OMAP_ABB_FAST_OPP		1 +#define OMAP_ABB_SLOW_OPP		3 +#define OMAP_ABB_CONTROL_FAST_OPP_SEL_MASK		(0x1 << 0) +#define OMAP_ABB_CONTROL_SLOW_OPP_SEL_MASK		(0x1 << 1) +#define OMAP_ABB_CONTROL_OPP_CHANGE_MASK		(0x1 << 2) +#define OMAP_ABB_CONTROL_SR2_IN_TRANSITION_MASK		(0x1 << 6) +#define OMAP_ABB_SETUP_SR2EN_MASK			(0x1 << 0) +#define OMAP_ABB_SETUP_ACTIVE_FBB_SEL_MASK		(0x1 << 2) +#define OMAP_ABB_SETUP_ACTIVE_RBB_SEL_MASK		(0x1 << 1) +#define OMAP_ABB_SETUP_SR2_WTCNT_VALUE_MASK		(0xff << 8) +  static inline u32 omap_revision(void)  {  	extern u32 *const omap_si_rev; |