diff --git a/arch/arm/boot/dts/omap3-evm-37xx.dts b/arch/arm/boot/dts/omap3-evm-37xx.dts index 4df68ad3736a..9cba94bed7ad 100644 --- a/arch/arm/boot/dts/omap3-evm-37xx.dts +++ b/arch/arm/boot/dts/omap3-evm-37xx.dts @@ -89,7 +89,16 @@ status = "disabled"; }; +&uart1 { + interrupts-extended = <&intc 72 &omap3_pmx_core OMAP3_UART1_RX>; +}; + +&uart2 { + interrupts-extended = <&intc 73 &omap3_pmx_core OMAP3_UART2_RX>; +}; + &uart3 { + interrupts-extended = <&intc 74 &omap3_pmx_core OMAP3_UART3_RX>; pinctrl-names = "default"; pinctrl-0 = <&uart3_pins>; }; diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts index 0abe986a4ecc..476ff158ddb3 100644 --- a/arch/arm/boot/dts/omap3-ldp.dts +++ b/arch/arm/boot/dts/omap3-ldp.dts @@ -234,6 +234,10 @@ }; }; +&uart3 { + interrupts-extended = <&intc 74 &omap3_pmx_core OMAP3_UART3_RX>; +}; + &usb_otg_hs { pinctrl-names = "default"; pinctrl-0 = <&musb_pins>; diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index 1a57b61f5e24..150ca097c02d 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -21,6 +21,17 @@ }; }; + leds { + compatible = "gpio-leds"; + heartbeat { + label = "debug::sleep"; + gpios = <&gpio6 2 GPIO_ACTIVE_HIGH>; /* gpio162 */ + linux,default-trigger = "default-on"; + pinctrl-names = "default"; + pinctrl-0 = <&debug_leds>; + }; + }; + memory { device_type = "memory"; reg = <0x80000000 0x10000000>; /* 256 MB */ @@ -130,6 +141,12 @@ >; }; + debug_leds: pinmux_debug_led_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2198, PIN_OUTPUT | MUX_MODE4) /* mcbsp1_clkx.gpio_162 */ + >; + }; + mmc1_pins: pinmux_mmc1_pins { pinctrl-single,pins = < 0x114 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk */ @@ -618,11 +635,13 @@ }; &uart2 { + interrupts-extended = <&intc 73 &omap3_pmx_core OMAP3_UART2_RX>; pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; }; &uart3 { + interrupts-extended = <&intc 74 &omap3_pmx_core OMAP3_UART3_RX>; pinctrl-names = "default"; pinctrl-0 = <&uart3_pins>; }; diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index acb9019dc437..8a0ce605fdd8 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -267,7 +267,7 @@ uart1: serial@4806a000 { compatible = "ti,omap3-uart"; reg = <0x4806a000 0x2000>; - interrupts = <72>; + interrupts-extended = <&intc 72>; dmas = <&sdma 49 &sdma 50>; dma-names = "tx", "rx"; ti,hwmods = "uart1"; @@ -277,7 +277,7 @@ uart2: serial@4806c000 { compatible = "ti,omap3-uart"; reg = <0x4806c000 0x400>; - interrupts = <73>; + interrupts-extended = <&intc 73>; dmas = <&sdma 51 &sdma 52>; dma-names = "tx", "rx"; ti,hwmods = "uart2"; @@ -287,7 +287,7 @@ uart3: serial@49020000 { compatible = "ti,omap3-uart"; reg = <0x49020000 0x400>; - interrupts = <74>; + interrupts-extended = <&intc 74>; dmas = <&sdma 53 &sdma 54>; dma-names = "tx", "rx"; ti,hwmods = "uart3"; diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi index d2c45bfaaa2c..8cfa3c8a72b0 100644 --- a/arch/arm/boot/dts/omap4-panda-common.dtsi +++ b/arch/arm/boot/dts/omap4-panda-common.dtsi @@ -481,6 +481,21 @@ usb-supply = <&vusb>; }; +&uart2 { + interrupts-extended = <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH + &omap4_pmx_core OMAP4_UART2_RX>; +}; + +&uart3 { + interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH + &omap4_pmx_core OMAP4_UART3_RX>; +}; + +&uart4 { + interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH + &omap4_pmx_core OMAP4_UART4_RX>; +}; + &usb_otg_hs { interface-type = <1>; mode = <3>; diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index 48983c8d56c2..3e1da43068f6 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -570,16 +570,22 @@ }; &uart2 { + interrupts-extended = <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH + &omap4_pmx_core OMAP4_UART2_RX>; pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; }; &uart3 { + interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH + &omap4_pmx_core OMAP4_UART3_RX>; pinctrl-names = "default"; pinctrl-0 = <&uart3_pins>; }; &uart4 { + interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH + &omap4_pmx_core OMAP4_UART4_RX>; pinctrl-names = "default"; pinctrl-0 = <&uart4_pins>; }; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 649b5cd38b40..b22664544a09 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -311,7 +311,7 @@ uart2: serial@4806c000 { compatible = "ti,omap4-uart"; reg = <0x4806c000 0x100>; - interrupts = ; + interrupts-extended = <&gic GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart2"; clock-frequency = <48000000>; }; @@ -319,7 +319,7 @@ uart3: serial@48020000 { compatible = "ti,omap4-uart"; reg = <0x48020000 0x100>; - interrupts = ; + interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart3"; clock-frequency = <48000000>; }; @@ -327,7 +327,7 @@ uart4: serial@4806e000 { compatible = "ti,omap4-uart"; reg = <0x4806e000 0x100>; - interrupts = ; + interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "uart4"; clock-frequency = <48000000>; }; diff --git a/arch/arm/boot/dts/twl4030_omap3.dtsi b/arch/arm/boot/dts/twl4030_omap3.dtsi index c353ef0a6ac7..3537ae5b2146 100644 --- a/arch/arm/boot/dts/twl4030_omap3.dtsi +++ b/arch/arm/boot/dts/twl4030_omap3.dtsi @@ -8,7 +8,7 @@ &twl { pinctrl-names = "default"; - pinctrl-0 = <&twl4030_pins>; + pinctrl-0 = <&twl4030_pins &twl4030_vpins>; }; &omap3_pmx_core { @@ -23,3 +23,20 @@ >; }; }; + +/* + * If your board is not using the I2C4 pins with twl4030, then don't include + * this file. For proper idle mode signaling with sys_clkreq and sys_off_mode + * pins we need to configure I2C4, or else use the legacy sys_nvmode1 and + * sys_nvmode2 signaling. + */ +&omap3_pmx_wkup { + twl4030_vpins: pinmux_twl4030_vpins { + pinctrl-single,pins = < + OMAP3_WKUP_IOPAD(0x2a00, PIN_INPUT | MUX_MODE0) /* i2c4_scl.i2c4_scl */ + OMAP3_WKUP_IOPAD(0x2a02, PIN_INPUT | MUX_MODE0) /* i2c4_sda.i2c4_sda */ + OMAP3_WKUP_IOPAD(0x2a06, PIN_OUTPUT | MUX_MODE0) /* sys_clkreq.sys_clkreq */ + OMAP3_WKUP_IOPAD(0x2a18, PIN_OUTPUT | MUX_MODE0) /* sys_off_mode.sys_off_mode */ + >; + }; +}; diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index a4e8d017f25b..28f3b6e3b589 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -21,6 +21,8 @@ CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_MULTI_V6=y +CONFIG_POWER_AVS_OMAP=y +CONFIG_POWER_AVS_OMAP_CLASS3=y CONFIG_OMAP_RESET_CLOCKS=y CONFIG_OMAP_MUX_DEBUG=y CONFIG_ARCH_OMAP2=y @@ -42,6 +44,7 @@ CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200" CONFIG_KEXEC=y CONFIG_FPE_NWFPE=y +CONFIG_CPU_IDLE=y CONFIG_BINFMT_MISC=y CONFIG_PM_DEBUG=y CONFIG_NET=y @@ -159,11 +162,14 @@ CONFIG_GPIO_SYSFS=y CONFIG_GPIO_TWL4030=y CONFIG_W1=y CONFIG_POWER_SUPPLY=y +CONFIG_POWER_AVS=y CONFIG_SENSORS_LM75=m CONFIG_THERMAL=y CONFIG_THERMAL_GOV_FAIR_SHARE=y CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_CPU_THERMAL=y CONFIG_TI_SOC_THERMAL=y +CONFIG_TI_THERMAL=y CONFIG_OMAP4_THERMAL=y CONFIG_OMAP5_THERMAL=y CONFIG_DRA752_THERMAL=y @@ -177,6 +183,7 @@ CONFIG_MFD_TPS65910=y CONFIG_TWL6040_CORE=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PALMAS=y +CONFIG_REGULATOR_TI_ABB=y CONFIG_REGULATOR_TPS65023=y CONFIG_REGULATOR_TPS6507X=y CONFIG_REGULATOR_TPS65217=y @@ -239,6 +246,7 @@ CONFIG_SDIO_UART=y CONFIG_MMC_OMAP=y CONFIG_MMC_OMAP_HS=y CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=y diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index 615e5b1fb025..6bf626700557 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -46,15 +46,8 @@ static bool is_offset_valid; static u8 smps_offset; -/* - * Flag to ensure Smartreflex bit in TWL - * being cleared in board file is not overwritten. - */ -static bool __initdata twl_sr_enable_autoinit; -#define TWL4030_DCDC_GLOBAL_CFG 0x06 #define REG_SMPS_OFFSET 0xE0 -#define SMARTREFLEX_ENABLE BIT(3) static unsigned long twl4030_vsel_to_uv(const u8 vsel) { @@ -251,18 +244,6 @@ int __init omap3_twl_init(void) if (!cpu_is_omap34xx()) return -ENODEV; - /* - * The smartreflex bit on twl4030 specifies if the setting of voltage - * is done over the I2C_SR path. Since this setting is independent of - * the actual usage of smartreflex AVS module, we enable TWL SR bit - * by default irrespective of whether smartreflex AVS module is enabled - * on the OMAP side or not. This is because without this bit enabled, - * the voltage scaling through vp forceupdate/bypass mechanism of - * voltage scaling will not function on TWL over I2C_SR. - */ - if (!twl_sr_enable_autoinit) - omap3_twl_set_sr_bit(true); - voltdm = voltdm_lookup("mpu_iva"); omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic); @@ -271,44 +252,3 @@ int __init omap3_twl_init(void) return 0; } - -/** - * omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL - * @enable: enable SR mode in twl or not - * - * If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure - * voltage scaling through OMAP SR works. Else, the smartreflex bit - * on twl4030 is cleared as there are platforms which use OMAP3 and T2 but - * use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct - * Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages, - * in those scenarios this bit is to be cleared (enable = false). - * - * Returns 0 on success, error is returned if I2C read/write fails. - */ -int __init omap3_twl_set_sr_bit(bool enable) -{ - u8 temp; - int ret; - if (twl_sr_enable_autoinit) - pr_warning("%s: unexpected multiple calls\n", __func__); - - ret = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp, - TWL4030_DCDC_GLOBAL_CFG); - if (ret) - goto err; - - if (enable) - temp |= SMARTREFLEX_ENABLE; - else - temp &= ~SMARTREFLEX_ENABLE; - - ret = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp, - TWL4030_DCDC_GLOBAL_CFG); - if (!ret) { - twl_sr_enable_autoinit = true; - return 0; - } -err: - pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret); - return ret; -} diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index dd31212d5e20..828aee9ea6a8 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -298,26 +298,22 @@ omap_postcore_initcall(omap2_common_pm_init); int __init omap2_common_pm_late_init(void) { - /* - * In the case of DT, the PMIC and SR initialization will be done using - * a completely different mechanism. - * Disable this part if a DT blob is available. - */ - if (!of_have_populated_dt()) { - - /* Init the voltage layer */ - omap_pmic_late_init(); - omap_voltage_late_init(); - - /* Initialize the voltages */ - omap3_init_voltages(); - omap4_init_voltages(); - - /* Smartreflex device init */ - omap_devinit_smartreflex(); - + if (of_have_populated_dt()) { + omap3_twl_init(); + omap4_twl_init(); } + /* Init the voltage layer */ + omap_pmic_late_init(); + omap_voltage_late_init(); + + /* Initialize the voltages */ + omap3_init_voltages(); + omap4_init_voltages(); + + /* Smartreflex device init */ + omap_devinit_smartreflex(); + /* cpufreq dummy device instantiation */ omap_init_cpufreq(); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 90ea2d3ab405..507d8eeaab95 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -50,6 +50,7 @@ #include "sdrc.h" #include "sram.h" #include "control.h" +#include "vc.h" /* pm34xx errata defined in pm.h */ u16 pm34xx_errata; @@ -288,6 +289,9 @@ void omap_sram_idle(void) } } + /* Configure PMIC signaling for I2C4 or sys_off_mode */ + omap3_vc_set_pmic_signaling(core_next_state); + omap3_intc_prepare_idle(); /* diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h index cebad565ed37..106132db532b 100644 --- a/arch/arm/mach-omap2/prm-regbits-34xx.h +++ b/arch/arm/mach-omap2/prm-regbits-34xx.h @@ -123,8 +123,15 @@ #define OMAP3430_GLOBAL_SW_RST_SHIFT 1 #define OMAP3430_GLOBAL_COLD_RST_SHIFT 0 #define OMAP3430_GLOBAL_COLD_RST_MASK (1 << 0) -#define OMAP3430_SEL_OFF_MASK (1 << 3) -#define OMAP3430_AUTO_OFF_MASK (1 << 2) +#define OMAP3430_PRM_VOLTCTRL_SEL_VMODE (1 << 4) +#define OMAP3430_PRM_VOLTCTRL_SEL_OFF (1 << 3) +#define OMAP3430_PRM_VOLTCTRL_AUTO_OFF (1 << 2) +#define OMAP3430_PRM_VOLTCTRL_AUTO_RET (1 << 1) +#define OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP (1 << 0) #define OMAP3430_SETUP_TIME2_MASK (0xffff << 16) #define OMAP3430_SETUP_TIME1_MASK (0xffff << 0) +#define OMAP3430_PRM_POLCTRL_OFFMODE_POL (1 << 3) +#define OMAP3430_PRM_POLCTRL_CLKOUT_POL (1 << 2) +#define OMAP3430_PRM_POLCTRL_CLKREQ_POL (1 << 1) +#define OMAP3430_PRM_POLCTRL_EXTVOL_POL (1 << 0) #endif diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 49ac7977e03e..0d1629c5f84e 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -220,10 +220,126 @@ static inline u32 omap_usec_to_32k(u32 usec) return DIV_ROUND_UP_ULL(32768ULL * (u64)usec, 1000000ULL); } -/* Set oscillator setup time for omap3 */ -static void omap3_set_clksetup(u32 usec, struct voltagedomain *voltdm) +struct omap3_vc_timings { + u32 voltsetup1; + u32 voltsetup2; +}; + +struct omap3_vc { + struct voltagedomain *vd; + u32 voltctrl; + u32 voltsetup1; + u32 voltsetup2; + struct omap3_vc_timings timings[2]; +}; +static struct omap3_vc vc; + +void omap3_vc_set_pmic_signaling(int core_next_state) { - voltdm->write(omap_usec_to_32k(usec), OMAP3_PRM_CLKSETUP_OFFSET); + struct voltagedomain *vd = vc.vd; + struct omap3_vc_timings *c = vc.timings; + u32 voltctrl, voltsetup1, voltsetup2; + + voltctrl = vc.voltctrl; + voltsetup1 = vc.voltsetup1; + voltsetup2 = vc.voltsetup2; + + switch (core_next_state) { + case PWRDM_POWER_OFF: + voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_RET | + OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP); + voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_OFF; + if (voltctrl & OMAP3430_PRM_VOLTCTRL_SEL_OFF) + voltsetup2 = c->voltsetup2; + else + voltsetup1 = c->voltsetup1; + break; + case PWRDM_POWER_RET: + default: + c++; + voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_OFF | + OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP); + voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_RET; + voltsetup1 = c->voltsetup1; + break; + } + + if (voltctrl != vc.voltctrl) { + vd->write(voltctrl, OMAP3_PRM_VOLTCTRL_OFFSET); + vc.voltctrl = voltctrl; + } + if (voltsetup1 != vc.voltsetup1) { + vd->write(c->voltsetup1, + OMAP3_PRM_VOLTSETUP1_OFFSET); + vc.voltsetup1 = voltsetup1; + } + if (voltsetup2 != vc.voltsetup2) { + vd->write(c->voltsetup2, + OMAP3_PRM_VOLTSETUP2_OFFSET); + vc.voltsetup2 = voltsetup2; + } +} + +#define PRM_POLCTRL_TWL_MASK (OMAP3430_PRM_POLCTRL_CLKREQ_POL | \ + OMAP3430_PRM_POLCTRL_CLKREQ_POL) +#define PRM_POLCTRL_TWL_VAL OMAP3430_PRM_POLCTRL_CLKREQ_POL + +/* + * Configure signal polarity for sys_clkreq and sys_off_mode pins + * as the default values are wrong and can cause the system to hang + * if any twl4030 scripts are loaded. + */ +static void __init omap3_vc_init_pmic_signaling(struct voltagedomain *voltdm) +{ + u32 val; + + if (vc.vd) + return; + + vc.vd = voltdm; + + val = voltdm->read(OMAP3_PRM_POLCTRL_OFFSET); + if (!(val & OMAP3430_PRM_POLCTRL_CLKREQ_POL) || + (val & OMAP3430_PRM_POLCTRL_CLKREQ_POL)) { + val |= OMAP3430_PRM_POLCTRL_CLKREQ_POL; + val &= ~OMAP3430_PRM_POLCTRL_OFFMODE_POL; + pr_debug("PM: fixing sys_clkreq and sys_off_mode polarity to 0x%x\n", + val); + voltdm->write(val, OMAP3_PRM_POLCTRL_OFFSET); + } + + /* + * By default let's use I2C4 signaling for retention idle + * and sys_off_mode pin signaling for off idle. This way we + * have sys_clk_req pin go down for retention and both + * sys_clk_req and sys_off_mode pins will go down for off + * idle. And we can also scale voltages to zero for off-idle. + * Note that no actual voltage scaling during off-idle will + * happen unless the board specific twl4030 PMIC scripts are + * loaded. + */ + val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); + if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) { + val |= OMAP3430_PRM_VOLTCTRL_SEL_OFF; + pr_debug("PM: setting voltctrl sys_off_mode signaling to 0x%x\n", + val); + voltdm->write(val, OMAP3_PRM_VOLTCTRL_OFFSET); + } + vc.voltctrl = val; + + omap3_vc_set_pmic_signaling(PWRDM_POWER_ON); +} + +static void omap3_init_voltsetup1(struct voltagedomain *voltdm, + struct omap3_vc_timings *c, u32 idle) +{ + unsigned long val; + + val = (voltdm->vc_param->on - idle) / voltdm->pmic->slew_rate; + val *= voltdm->sys_clk.rate / 8 / 1000000 + 1; + val <<= __ffs(voltdm->vfsm->voltsetup_mask); + c->voltsetup1 &= ~voltdm->vfsm->voltsetup_mask; + c->voltsetup1 |= val; } /** @@ -236,37 +352,21 @@ static void omap3_set_clksetup(u32 usec, struct voltagedomain *voltdm) * or retention. Off mode has additionally an option to use sys_off_mode * pad, which uses a global signal to program the whole power IC to * off-mode. + * + * Note that pmic is not controlling the voltage scaling during + * retention signaled over I2C4, so we can keep voltsetup2 as 0. + * And the oscillator is not shut off over I2C4, so no need to + * set clksetup. */ -static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode) +static void omap3_set_i2c_timings(struct voltagedomain *voltdm) { - unsigned long voltsetup1; - u32 tgt_volt; + struct omap3_vc_timings *c = vc.timings; - /* - * Oscillator is shut down only if we are using sys_off_mode pad, - * thus we set a minimal setup time here - */ - omap3_set_clksetup(1, voltdm); - - if (off_mode) - tgt_volt = voltdm->vc_param->off; - else - tgt_volt = voltdm->vc_param->ret; - - voltsetup1 = (voltdm->vc_param->on - tgt_volt) / - voltdm->pmic->slew_rate; - - voltsetup1 = voltsetup1 * voltdm->sys_clk.rate / 8 / 1000000 + 1; - - voltdm->rmw(voltdm->vfsm->voltsetup_mask, - voltsetup1 << __ffs(voltdm->vfsm->voltsetup_mask), - voltdm->vfsm->voltsetup_reg); - - /* - * pmic is not controlling the voltage scaling during retention, - * thus set voltsetup2 to 0 - */ - voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET); + /* Configure PRWDM_POWER_OFF over I2C4 */ + omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->off); + c++; + /* Configure PRWDM_POWER_RET over I2C4 */ + omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->ret); } /** @@ -275,69 +375,49 @@ static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode) * * Calculates and sets up off-mode timings for a channel. Off-mode * can use either I2C based voltage scaling, or alternatively - * sys_off_mode pad can be used to send a global command to power IC. - * This function first checks which mode is being used, and calls - * omap3_set_i2c_timings() if the system is using I2C control mode. + * sys_off_mode pad can be used to send a global command to power IC.n, * sys_off_mode has the additional benefit that voltages can be * scaled to zero volt level with TWL4030 / TWL5030, I2C can only * scale to 600mV. + * + * Note that omap is not controlling the voltage scaling during + * off idle signaled by sys_off_mode, so we can keep voltsetup1 + * as 0. */ static void omap3_set_off_timings(struct voltagedomain *voltdm) { - unsigned long clksetup; - unsigned long voltsetup2; - unsigned long voltsetup2_old; - u32 val; - u32 tstart, tshut; + struct omap3_vc_timings *c = vc.timings; + u32 tstart, tshut, clksetup, voltoffset; - /* check if sys_off_mode is used to control off-mode voltages */ - val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); - if (!(val & OMAP3430_SEL_OFF_MASK)) { - /* No, omap is controlling them over I2C */ - omap3_set_i2c_timings(voltdm, true); + if (c->voltsetup2) return; - } omap_pm_get_oscillator(&tstart, &tshut); - omap3_set_clksetup(tstart, voltdm); - - clksetup = voltdm->read(OMAP3_PRM_CLKSETUP_OFFSET); - - /* voltsetup 2 in us */ - voltsetup2 = voltdm->vc_param->on / voltdm->pmic->slew_rate; - - /* convert to 32k clk cycles */ - voltsetup2 = DIV_ROUND_UP(voltsetup2 * 32768, 1000000); - - voltsetup2_old = voltdm->read(OMAP3_PRM_VOLTSETUP2_OFFSET); + if (tstart == ULONG_MAX) { + pr_debug("PM: oscillator start-up time not initialized, using 10ms\n"); + clksetup = omap_usec_to_32k(10000); + } else { + clksetup = omap_usec_to_32k(tstart); + } /* - * Update voltsetup2 if higher than current value (needed because - * we have multiple channels with different ramp times), also - * update voltoffset always to value recommended by TRM + * For twl4030 errata 27, we need to allow minimum ~488.32 us wait to + * switch from HFCLKIN to internal oscillator. That means timings + * have voltoffset fixed to 0xa in rounded up 32 KiHz cycles. And + * that means we can calculate the value based on the oscillator + * start-up time since voltoffset2 = clksetup - voltoffset. */ - if (voltsetup2 > voltsetup2_old) { - voltdm->write(voltsetup2, OMAP3_PRM_VOLTSETUP2_OFFSET); - voltdm->write(clksetup - voltsetup2, - OMAP3_PRM_VOLTOFFSET_OFFSET); - } else - voltdm->write(clksetup - voltsetup2_old, - OMAP3_PRM_VOLTOFFSET_OFFSET); - - /* - * omap is not controlling voltage scaling during off-mode, - * thus set voltsetup1 to 0 - */ - voltdm->rmw(voltdm->vfsm->voltsetup_mask, 0, - voltdm->vfsm->voltsetup_reg); - - /* voltoffset must be clksetup minus voltsetup2 according to TRM */ - voltdm->write(clksetup - voltsetup2, OMAP3_PRM_VOLTOFFSET_OFFSET); + voltoffset = omap_usec_to_32k(488); + c->voltsetup2 = clksetup - voltoffset; + voltdm->write(clksetup, OMAP3_PRM_CLKSETUP_OFFSET); + voltdm->write(voltoffset, OMAP3_PRM_VOLTOFFSET_OFFSET); } static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) { + omap3_vc_init_pmic_signaling(voltdm); omap3_set_off_timings(voltdm); + omap3_set_i2c_timings(voltdm); } /** diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index 91c8d75bf2ea..cdbdd78e755e 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h @@ -117,6 +117,9 @@ extern struct omap_vc_param omap4_mpu_vc_data; extern struct omap_vc_param omap4_iva_vc_data; extern struct omap_vc_param omap4_core_vc_data; +void omap3_vc_set_pmic_signaling(int core_next_state); + + void omap_vc_init_channel(struct voltagedomain *voltdm); int omap_vc_pre_scale(struct voltagedomain *voltdm, unsigned long target_volt, diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index e87140bef667..db11b4f40611 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -98,7 +98,11 @@ #define TWL4030_BASEADD_BACKUP 0x0014 #define TWL4030_BASEADD_INT 0x002E #define TWL4030_BASEADD_PM_MASTER 0x0036 + #define TWL4030_BASEADD_PM_RECEIVER 0x005B +#define TWL4030_DCDC_GLOBAL_CFG 0x06 +#define SMARTREFLEX_ENABLE BIT(3) + #define TWL4030_BASEADD_RTC 0x001C #define TWL4030_BASEADD_SECURED_REG 0x0000 @@ -1204,6 +1208,11 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface. * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0, * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0. + * + * Also, always enable SmartReflex bit as that's needed for omaps to + * to do anything over I2C4 for voltage scaling even if SmartReflex + * is disabled. Without the SmartReflex bit omap sys_clkreq idle + * signal will never trigger for retention idle. */ if (twl_class_is_4030()) { u8 temp; @@ -1212,6 +1221,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \ I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU); twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); + + twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp, + TWL4030_DCDC_GLOBAL_CFG); + temp |= SMARTREFLEX_ENABLE; + twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp, + TWL4030_DCDC_GLOBAL_CFG); } if (node) { diff --git a/include/dt-bindings/pinctrl/omap.h b/include/dt-bindings/pinctrl/omap.h index b04528cd033c..404ba7ef7813 100644 --- a/include/dt-bindings/pinctrl/omap.h +++ b/include/dt-bindings/pinctrl/omap.h @@ -69,5 +69,17 @@ #define OMAP5_WKUP_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0xc840) (val) #define DRA7XX_CORE_IOPAD(pa, val) OMAP_IOPAD_OFFSET((pa), 0x3400) (val) +/* + * Define some commonly used pins configured by the boards. + * Note that some boards use alternative pins, so check + * the schematics before using these. + */ +#define OMAP3_UART1_RX 0x152 +#define OMAP3_UART2_RX 0x14a +#define OMAP3_UART3_RX 0x16e +#define OMAP4_UART2_RX 0xdc +#define OMAP4_UART3_RX 0x104 +#define OMAP4_UART4_RX 0x11c + #endif