diff --git a/[refs] b/[refs] index 74dbbe4f62ae..b50c7cef4bb2 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 8d61d7f94522a0c023ed79d4f690f2bfc8a41d96 +refs/heads/master: 088e8806c411f76216002a8b37c7eb8563614822 diff --git a/trunk/arch/arm/mach-omap2/am35xx-emac.c b/trunk/arch/arm/mach-omap2/am35xx-emac.c index a00d39107a21..af11dcdb7e2c 100644 --- a/trunk/arch/arm/mach-omap2/am35xx-emac.c +++ b/trunk/arch/arm/mach-omap2/am35xx-emac.c @@ -63,7 +63,7 @@ static int __init omap_davinci_emac_dev_init(struct omap_hwmod *oh, struct platform_device *pdev; pdev = omap_device_build(oh->class->name, 0, oh, pdata, pdata_len, - false); + NULL, 0, false); if (IS_ERR(pdev)) { WARN(1, "Can't build omap_device for %s:%s.\n", oh->class->name, oh->name); diff --git a/trunk/arch/arm/mach-omap2/cclock2420_data.c b/trunk/arch/arm/mach-omap2/cclock2420_data.c index 0f0a97c1fcc0..ab7e952d2070 100644 --- a/trunk/arch/arm/mach-omap2/cclock2420_data.c +++ b/trunk/arch/arm/mach-omap2/cclock2420_data.c @@ -622,10 +622,15 @@ static struct clk_hw_omap gpios_fck_hw = { DEFINE_STRUCT_CLK(gpios_fck, gpios_fck_parent_names, aes_ick_ops); +static struct clk wu_l4_ick; + +DEFINE_STRUCT_CLK_HW_OMAP(wu_l4_ick, "wkup_clkdm"); +DEFINE_STRUCT_CLK(wu_l4_ick, dpll_ck_parent_names, core_ck_ops); + static struct clk gpios_ick; static const char *gpios_ick_parent_names[] = { - "sys_ck", + "wu_l4_ick", }; static struct clk_hw_omap gpios_ick_hw = { @@ -1677,6 +1682,13 @@ static struct clk_hw_omap wdt1_ick_hw = { DEFINE_STRUCT_CLK(wdt1_ick, gpios_ick_parent_names, aes_ick_ops); +static struct clk wdt1_osc_ck; + +static const struct clk_ops wdt1_osc_ck_ops = {}; + +DEFINE_STRUCT_CLK_HW_OMAP(wdt1_osc_ck, NULL); +DEFINE_STRUCT_CLK(wdt1_osc_ck, sys_ck_parent_names, wdt1_osc_ck_ops); + static struct clk wdt3_fck; static struct clk_hw_omap wdt3_fck_hw = { @@ -1755,6 +1767,7 @@ static struct omap_clk omap2420_clks[] = { CLK(NULL, "func_96m_ck", &func_96m_ck, CK_242X), CLK(NULL, "func_48m_ck", &func_48m_ck, CK_242X), CLK(NULL, "func_12m_ck", &func_12m_ck, CK_242X), + CLK(NULL, "ck_wdt1_osc", &wdt1_osc_ck, CK_242X), CLK(NULL, "sys_clkout_src", &sys_clkout_src, CK_242X), CLK(NULL, "sys_clkout", &sys_clkout, CK_242X), CLK(NULL, "sys_clkout2_src", &sys_clkout2_src, CK_242X), @@ -1784,6 +1797,7 @@ static struct omap_clk omap2420_clks[] = { /* L4 domain clocks */ CLK(NULL, "l4_ck", &l4_ck, CK_242X), CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_242X), + CLK(NULL, "wu_l4_ick", &wu_l4_ick, CK_242X), /* virtual meta-group clock */ CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_242X), /* general l4 interface ck, multi-parent functional clk */ diff --git a/trunk/arch/arm/mach-omap2/cclock2430_data.c b/trunk/arch/arm/mach-omap2/cclock2430_data.c index aed8f74ca076..eb3dab68d536 100644 --- a/trunk/arch/arm/mach-omap2/cclock2430_data.c +++ b/trunk/arch/arm/mach-omap2/cclock2430_data.c @@ -601,10 +601,15 @@ static struct clk_hw_omap gpios_fck_hw = { DEFINE_STRUCT_CLK(gpios_fck, gpio5_fck_parent_names, aes_ick_ops); +static struct clk wu_l4_ick; + +DEFINE_STRUCT_CLK_HW_OMAP(wu_l4_ick, "wkup_clkdm"); +DEFINE_STRUCT_CLK(wu_l4_ick, dpll_ck_parent_names, core_ck_ops); + static struct clk gpios_ick; static const char *gpios_ick_parent_names[] = { - "sys_ck", + "wu_l4_ick", }; static struct clk_hw_omap gpios_ick_hw = { @@ -1806,6 +1811,13 @@ static struct clk_hw_omap wdt1_ick_hw = { DEFINE_STRUCT_CLK(wdt1_ick, gpios_ick_parent_names, aes_ick_ops); +static struct clk wdt1_osc_ck; + +static const struct clk_ops wdt1_osc_ck_ops = {}; + +DEFINE_STRUCT_CLK_HW_OMAP(wdt1_osc_ck, NULL); +DEFINE_STRUCT_CLK(wdt1_osc_ck, sys_ck_parent_names, wdt1_osc_ck_ops); + static struct clk wdt4_fck; static struct clk_hw_omap wdt4_fck_hw = { @@ -1857,6 +1869,7 @@ static struct omap_clk omap2430_clks[] = { CLK(NULL, "func_96m_ck", &func_96m_ck, CK_243X), CLK(NULL, "func_48m_ck", &func_48m_ck, CK_243X), CLK(NULL, "func_12m_ck", &func_12m_ck, CK_243X), + CLK(NULL, "ck_wdt1_osc", &wdt1_osc_ck, CK_243X), CLK(NULL, "sys_clkout_src", &sys_clkout_src, CK_243X), CLK(NULL, "sys_clkout", &sys_clkout, CK_243X), CLK(NULL, "emul_ck", &emul_ck, CK_243X), @@ -1885,6 +1898,7 @@ static struct omap_clk omap2430_clks[] = { /* L4 domain clocks */ CLK(NULL, "l4_ck", &l4_ck, CK_243X), CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_243X), + CLK(NULL, "wu_l4_ick", &wu_l4_ick, CK_243X), /* virtual meta-group clock */ CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_243X), /* general l4 interface ck, multi-parent functional clk */ diff --git a/trunk/arch/arm/mach-omap2/cclock44xx_data.c b/trunk/arch/arm/mach-omap2/cclock44xx_data.c index cebe2b31943e..a2cc046b47f4 100644 --- a/trunk/arch/arm/mach-omap2/cclock44xx_data.c +++ b/trunk/arch/arm/mach-omap2/cclock44xx_data.c @@ -16,10 +16,6 @@ * XXX Some of the ES1 clocks have been removed/changed; once support * is added for discriminating clocks by ES level, these should be added back * in. - * - * XXX All of the remaining MODULEMODE clock nodes should be removed - * once the drivers are updated to use pm_runtime or to use the appropriate - * upstream clock node for rate/parent selection. */ #include @@ -319,7 +315,7 @@ DEFINE_CLK_DIVIDER(dpll_abe_m2_ck, "dpll_abe_ck", &dpll_abe_ck, 0x0, OMAP4430_CM_DIV_M2_DPLL_ABE, OMAP4430_DPLL_CLKOUT_DIV_SHIFT, OMAP4430_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL); -static const struct clk_ops dpll_hsd_ops = { +static const struct clk_ops dmic_fck_ops = { .enable = &omap2_dflt_clk_enable, .disable = &omap2_dflt_clk_disable, .is_enabled = &omap2_dflt_clk_is_enabled, @@ -329,12 +325,6 @@ static const struct clk_ops dpll_hsd_ops = { .init = &omap2_init_clk_clkdm, }; -static const struct clk_ops func_dmic_abe_gfclk_ops = { - .recalc_rate = &omap2_clksel_recalc, - .get_parent = &omap2_clksel_find_parent_index, - .set_parent = &omap2_clksel_set_parent, -}; - static const char *dpll_core_m3x2_ck_parents[] = { "dpll_core_x2_ck", }; @@ -350,7 +340,7 @@ DEFINE_CLK_OMAP_MUX_GATE(dpll_core_m3x2_ck, NULL, dpll_core_m3x2_div, OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, OMAP4430_CM_DIV_M3_DPLL_CORE, OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL, - dpll_core_m3x2_ck_parents, dpll_hsd_ops); + dpll_core_m3x2_ck_parents, dmic_fck_ops); DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m7x2_ck, "dpll_core_x2_ck", &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M7_DPLL_CORE, @@ -557,7 +547,7 @@ DEFINE_CLK_OMAP_MUX_GATE(dpll_per_m3x2_ck, NULL, dpll_per_m3x2_div, OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, OMAP4430_CM_DIV_M3_DPLL_PER, OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL, - dpll_per_m3x2_ck_parents, dpll_hsd_ops); + dpll_per_m3x2_ck_parents, dmic_fck_ops); DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m4x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, 0x0, OMAP4430_CM_DIV_M4_DPLL_PER, @@ -759,6 +749,10 @@ DEFINE_CLK_GATE(aes2_fck, "l3_div_ck", &l3_div_ck, 0x0, OMAP4430_CM_L4SEC_AES2_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(aess_fck, "aess_fclk", &aess_fclk, 0x0, + OMAP4430_CM1_ABE_AESS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, + 0x0, NULL); + DEFINE_CLK_GATE(bandgap_fclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT, 0x0, NULL); @@ -780,6 +774,11 @@ DEFINE_CLK_GATE(bandgap_ts_fclk, "div_ts_ck", &div_ts_ck, 0x0, OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(des3des_fck, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L4SEC_DES3DES_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, + 0x0, NULL); + static const char *dmic_sync_mux_ck_parents[] = { "abe_24m_fclk", "syc_clk_div_ck", "func_24m_clk", }; @@ -796,13 +795,23 @@ static const struct clksel func_dmic_abe_gfclk_sel[] = { { .parent = NULL }, }; -static const char *func_dmic_abe_gfclk_parents[] = { +static const char *dmic_fck_parents[] = { "dmic_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -DEFINE_CLK_OMAP_MUX(func_dmic_abe_gfclk, "abe_clkdm", func_dmic_abe_gfclk_sel, - OMAP4430_CM1_ABE_DMIC_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK, - func_dmic_abe_gfclk_parents, func_dmic_abe_gfclk_ops); +/* Merged func_dmic_abe_gfclk into dmic */ +static struct clk dmic_fck; + +DEFINE_CLK_OMAP_MUX_GATE(dmic_fck, "abe_clkdm", func_dmic_abe_gfclk_sel, + OMAP4430_CM1_ABE_DMIC_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_MASK, + OMAP4430_CM1_ABE_DMIC_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + dmic_fck_parents, dmic_fck_ops); + +DEFINE_CLK_GATE(dsp_fck, "dpll_iva_m4x2_ck", &dpll_iva_m4x2_ck, 0x0, + OMAP4430_CM_TESLA_TESLA_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); DEFINE_CLK_GATE(dss_sys_clk, "syc_clk_div_ck", &syc_clk_div_ck, 0x0, OMAP4430_CM_DSS_DSS_CLKCTRL, @@ -824,57 +833,177 @@ DEFINE_CLK_GATE(dss_fck, "l3_div_ck", &l3_div_ck, 0x0, OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(efuse_ctrl_cust_fck, "sys_clkin_ck", &sys_clkin_ck, 0x0, + OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(emif1_fck, "ddrphy_ck", &ddrphy_ck, 0x0, + OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(emif2_fck, "ddrphy_ck", &ddrphy_ck, 0x0, + OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_DIVIDER(fdif_fck, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, 0x0, OMAP4430_CM_CAM_FDIF_CLKCTRL, OMAP4430_CLKSEL_FCLK_SHIFT, OMAP4430_CLKSEL_FCLK_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); +DEFINE_CLK_GATE(fpka_fck, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(gpio1_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_WKUP_GPIO1_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(gpio1_ick, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, 0x0, + OMAP4430_CM_WKUP_GPIO1_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(gpio2_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO2_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(gpio2_ick, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L4PER_GPIO2_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(gpio3_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO3_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(gpio3_ick, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L4PER_GPIO3_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(gpio4_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO4_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(gpio4_ick, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L4PER_GPIO4_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(gpio5_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO5_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(gpio5_ick, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L4PER_GPIO5_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(gpio6_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO6_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(gpio6_ick, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L4PER_GPIO6_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(gpmc_ick, "l3_div_ck", &l3_div_ck, 0x0, + OMAP4430_CM_L3_2_GPMC_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT, + 0x0, NULL); + static const struct clksel sgx_clk_mux_sel[] = { { .parent = &dpll_core_m7x2_ck, .rates = div_1_0_rates }, { .parent = &dpll_per_m7x2_ck, .rates = div_1_1_rates }, { .parent = NULL }, }; -static const char *sgx_clk_mux_parents[] = { +static const char *gpu_fck_parents[] = { "dpll_core_m7x2_ck", "dpll_per_m7x2_ck", }; -DEFINE_CLK_OMAP_MUX(sgx_clk_mux, "l3_gfx_clkdm", sgx_clk_mux_sel, - OMAP4430_CM_GFX_GFX_CLKCTRL, OMAP4430_CLKSEL_SGX_FCLK_MASK, - sgx_clk_mux_parents, func_dmic_abe_gfclk_ops); +/* Merged sgx_clk_mux into gpu */ +DEFINE_CLK_OMAP_MUX_GATE(gpu_fck, "l3_gfx_clkdm", sgx_clk_mux_sel, + OMAP4430_CM_GFX_GFX_CLKCTRL, + OMAP4430_CLKSEL_SGX_FCLK_MASK, + OMAP4430_CM_GFX_GFX_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + gpu_fck_parents, dmic_fck_ops); + +DEFINE_CLK_GATE(hdq1w_fck, "func_12m_fclk", &func_12m_fclk, 0x0, + OMAP4430_CM_L4PER_HDQ1W_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); DEFINE_CLK_DIVIDER(hsi_fck, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, 0x0, OMAP4430_CM_L3INIT_HSI_CLKCTRL, OMAP4430_CLKSEL_24_25_SHIFT, OMAP4430_CLKSEL_24_25_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); +DEFINE_CLK_GATE(i2c1_fck, "func_96m_fclk", &func_96m_fclk, 0x0, + OMAP4430_CM_L4PER_I2C1_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(i2c2_fck, "func_96m_fclk", &func_96m_fclk, 0x0, + OMAP4430_CM_L4PER_I2C2_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(i2c3_fck, "func_96m_fclk", &func_96m_fclk, 0x0, + OMAP4430_CM_L4PER_I2C3_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(i2c4_fck, "func_96m_fclk", &func_96m_fclk, 0x0, + OMAP4430_CM_L4PER_I2C4_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(ipu_fck, "ducati_clk_mux_ck", &ducati_clk_mux_ck, 0x0, + OMAP4430_CM_DUCATI_DUCATI_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(iss_ctrlclk, "func_96m_fclk", &func_96m_fclk, 0x0, OMAP4430_CM_CAM_ISS_CLKCTRL, OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(iss_fck, "ducati_clk_mux_ck", &ducati_clk_mux_ck, 0x0, + OMAP4430_CM_CAM_ISS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, + 0x0, NULL); + +DEFINE_CLK_GATE(iva_fck, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck, 0x0, + OMAP4430_CM_IVAHD_IVAHD_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(kbd_fck, "sys_32k_ck", &sys_32k_ck, 0x0, + OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +static struct clk l3_instr_ick; + +static const char *l3_instr_ick_parent_names[] = { + "l3_div_ck", +}; + +static const struct clk_ops l3_instr_ick_ops = { + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, + .init = &omap2_init_clk_clkdm, +}; + +static struct clk_hw_omap l3_instr_ick_hw = { + .hw = { + .clk = &l3_instr_ick, + }, + .enable_reg = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL, + .enable_bit = OMAP4430_MODULEMODE_HWCTRL_SHIFT, + .clkdm_name = "l3_instr_clkdm", +}; + +DEFINE_STRUCT_CLK(l3_instr_ick, l3_instr_ick_parent_names, l3_instr_ick_ops); + +static struct clk l3_main_3_ick; +static struct clk_hw_omap l3_main_3_ick_hw = { + .hw = { + .clk = &l3_main_3_ick, + }, + .enable_reg = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL, + .enable_bit = OMAP4430_MODULEMODE_HWCTRL_SHIFT, + .clkdm_name = "l3_instr_clkdm", +}; + +DEFINE_STRUCT_CLK(l3_main_3_ick, l3_instr_ick_parent_names, l3_instr_ick_ops); + DEFINE_CLK_MUX(mcasp_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, OMAP4430_CM1_ABE_MCASP_CLKCTRL, OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, @@ -887,13 +1016,17 @@ static const struct clksel func_mcasp_abe_gfclk_sel[] = { { .parent = NULL }, }; -static const char *func_mcasp_abe_gfclk_parents[] = { +static const char *mcasp_fck_parents[] = { "mcasp_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -DEFINE_CLK_OMAP_MUX(func_mcasp_abe_gfclk, "abe_clkdm", func_mcasp_abe_gfclk_sel, - OMAP4430_CM1_ABE_MCASP_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK, - func_mcasp_abe_gfclk_parents, func_dmic_abe_gfclk_ops); +/* Merged func_mcasp_abe_gfclk into mcasp */ +DEFINE_CLK_OMAP_MUX_GATE(mcasp_fck, "abe_clkdm", func_mcasp_abe_gfclk_sel, + OMAP4430_CM1_ABE_MCASP_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_MASK, + OMAP4430_CM1_ABE_MCASP_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + mcasp_fck_parents, dmic_fck_ops); DEFINE_CLK_MUX(mcbsp1_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, @@ -907,14 +1040,17 @@ static const struct clksel func_mcbsp1_gfclk_sel[] = { { .parent = NULL }, }; -static const char *func_mcbsp1_gfclk_parents[] = { +static const char *mcbsp1_fck_parents[] = { "mcbsp1_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -DEFINE_CLK_OMAP_MUX(func_mcbsp1_gfclk, "abe_clkdm", func_mcbsp1_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp1_gfclk_parents, - func_dmic_abe_gfclk_ops); +/* Merged func_mcbsp1_gfclk into mcbsp1 */ +DEFINE_CLK_OMAP_MUX_GATE(mcbsp1_fck, "abe_clkdm", func_mcbsp1_gfclk_sel, + OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_MASK, + OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + mcbsp1_fck_parents, dmic_fck_ops); DEFINE_CLK_MUX(mcbsp2_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, @@ -928,14 +1064,17 @@ static const struct clksel func_mcbsp2_gfclk_sel[] = { { .parent = NULL }, }; -static const char *func_mcbsp2_gfclk_parents[] = { +static const char *mcbsp2_fck_parents[] = { "mcbsp2_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -DEFINE_CLK_OMAP_MUX(func_mcbsp2_gfclk, "abe_clkdm", func_mcbsp2_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp2_gfclk_parents, - func_dmic_abe_gfclk_ops); +/* Merged func_mcbsp2_gfclk into mcbsp2 */ +DEFINE_CLK_OMAP_MUX_GATE(mcbsp2_fck, "abe_clkdm", func_mcbsp2_gfclk_sel, + OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_MASK, + OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + mcbsp2_fck_parents, dmic_fck_ops); DEFINE_CLK_MUX(mcbsp3_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, @@ -949,14 +1088,17 @@ static const struct clksel func_mcbsp3_gfclk_sel[] = { { .parent = NULL }, }; -static const char *func_mcbsp3_gfclk_parents[] = { +static const char *mcbsp3_fck_parents[] = { "mcbsp3_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -DEFINE_CLK_OMAP_MUX(func_mcbsp3_gfclk, "abe_clkdm", func_mcbsp3_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp3_gfclk_parents, - func_dmic_abe_gfclk_ops); +/* Merged func_mcbsp3_gfclk into mcbsp3 */ +DEFINE_CLK_OMAP_MUX_GATE(mcbsp3_fck, "abe_clkdm", func_mcbsp3_gfclk_sel, + OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_MASK, + OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + mcbsp3_fck_parents, dmic_fck_ops); static const char *mcbsp4_sync_mux_ck_parents[] = { "func_96m_fclk", "per_abe_nc_fclk", @@ -973,14 +1115,37 @@ static const struct clksel per_mcbsp4_gfclk_sel[] = { { .parent = NULL }, }; -static const char *per_mcbsp4_gfclk_parents[] = { +static const char *mcbsp4_fck_parents[] = { "mcbsp4_sync_mux_ck", "pad_clks_ck", }; -DEFINE_CLK_OMAP_MUX(per_mcbsp4_gfclk, "l4_per_clkdm", per_mcbsp4_gfclk_sel, - OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_24_24_MASK, per_mcbsp4_gfclk_parents, - func_dmic_abe_gfclk_ops); +/* Merged per_mcbsp4_gfclk into mcbsp4 */ +DEFINE_CLK_OMAP_MUX_GATE(mcbsp4_fck, "l4_per_clkdm", per_mcbsp4_gfclk_sel, + OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_24_24_MASK, + OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + mcbsp4_fck_parents, dmic_fck_ops); + +DEFINE_CLK_GATE(mcpdm_fck, "pad_clks_ck", &pad_clks_ck, 0x0, + OMAP4430_CM1_ABE_PDM_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, + 0x0, NULL); + +DEFINE_CLK_GATE(mcspi1_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_MCSPI1_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(mcspi2_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_MCSPI2_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(mcspi3_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_MCSPI3_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(mcspi4_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_MCSPI4_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); static const struct clksel hsmmc1_fclk_sel[] = { { .parent = &func_64m_fclk, .rates = div_1_0_rates }, @@ -988,22 +1153,69 @@ static const struct clksel hsmmc1_fclk_sel[] = { { .parent = NULL }, }; -static const char *hsmmc1_fclk_parents[] = { +static const char *mmc1_fck_parents[] = { "func_64m_fclk", "func_96m_fclk", }; -DEFINE_CLK_OMAP_MUX(hsmmc1_fclk, "l3_init_clkdm", hsmmc1_fclk_sel, - OMAP4430_CM_L3INIT_MMC1_CLKCTRL, OMAP4430_CLKSEL_MASK, - hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops); +/* Merged hsmmc1_fclk into mmc1 */ +DEFINE_CLK_OMAP_MUX_GATE(mmc1_fck, "l3_init_clkdm", hsmmc1_fclk_sel, + OMAP4430_CM_L3INIT_MMC1_CLKCTRL, OMAP4430_CLKSEL_MASK, + OMAP4430_CM_L3INIT_MMC1_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + mmc1_fck_parents, dmic_fck_ops); + +/* Merged hsmmc2_fclk into mmc2 */ +DEFINE_CLK_OMAP_MUX_GATE(mmc2_fck, "l3_init_clkdm", hsmmc1_fclk_sel, + OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK, + OMAP4430_CM_L3INIT_MMC2_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + mmc1_fck_parents, dmic_fck_ops); + +DEFINE_CLK_GATE(mmc3_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_MMCSD3_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(mmc4_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_MMCSD4_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(mmc5_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_MMCSD5_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(ocp2scp_usb_phy_phy_48m, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, + OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, 0x0, NULL); + +DEFINE_CLK_GATE(ocp2scp_usb_phy_ick, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, + OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); + +static struct clk ocp_wp_noc_ick; + +static struct clk_hw_omap ocp_wp_noc_ick_hw = { + .hw = { + .clk = &ocp_wp_noc_ick, + }, + .enable_reg = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL, + .enable_bit = OMAP4430_MODULEMODE_HWCTRL_SHIFT, + .clkdm_name = "l3_instr_clkdm", +}; + +DEFINE_STRUCT_CLK(ocp_wp_noc_ick, l3_instr_ick_parent_names, l3_instr_ick_ops); -DEFINE_CLK_OMAP_MUX(hsmmc2_fclk, "l3_init_clkdm", hsmmc1_fclk_sel, - OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK, - hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops); +DEFINE_CLK_GATE(rng_ick, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L4SEC_RNG_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT, + 0x0, NULL); DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0, OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(sl2if_ick, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck, 0x0, + OMAP4430_CM_IVAHD_SL2_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT, + 0x0, NULL); + DEFINE_CLK_GATE(slimbus1_fclk_1, "func_24m_clk", &func_24m_clk, 0x0, OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, OMAP4430_OPTFCLKEN_FCLK1_SHIFT, 0x0, NULL); @@ -1020,6 +1232,10 @@ DEFINE_CLK_GATE(slimbus1_slimbus_clk, "slimbus_clk", &slimbus_clk, 0x0, OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(slimbus1_fck, "ocp_abe_iclk", &ocp_abe_iclk, 0x0, + OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(slimbus2_fclk_1, "per_abe_24m_fclk", &per_abe_24m_fclk, 0x0, OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT, 0x0, NULL); @@ -1033,6 +1249,10 @@ DEFINE_CLK_GATE(slimbus2_slimbus_clk, "pad_slimbus_core_clks_ck", OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(slimbus2_fck, "l4_div_ck", &l4_div_ck, 0x0, + OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(smartreflex_core_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, 0x0, OMAP4430_CM_ALWON_SR_CORE_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); @@ -1051,35 +1271,52 @@ static const struct clksel dmt1_clk_mux_sel[] = { { .parent = NULL }, }; -DEFINE_CLK_OMAP_MUX(dmt1_clk_mux, "l4_wkup_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_WKUP_TIMER1_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm10_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm11_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm2_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm3_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(cm2_dm4_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); +/* Merged dmt1_clk_mux into timer1 */ +DEFINE_CLK_OMAP_MUX_GATE(timer1_fck, "l4_wkup_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_WKUP_TIMER1_CLKCTRL, OMAP4430_CLKSEL_MASK, + OMAP4430_CM_WKUP_TIMER1_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); + +/* Merged cm2_dm10_mux into timer10 */ +DEFINE_CLK_OMAP_MUX_GATE(timer10_fck, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, + OMAP4430_CLKSEL_MASK, + OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); + +/* Merged cm2_dm11_mux into timer11 */ +DEFINE_CLK_OMAP_MUX_GATE(timer11_fck, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, + OMAP4430_CLKSEL_MASK, + OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); + +/* Merged cm2_dm2_mux into timer2 */ +DEFINE_CLK_OMAP_MUX_GATE(timer2_fck, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, + OMAP4430_CLKSEL_MASK, + OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); + +/* Merged cm2_dm3_mux into timer3 */ +DEFINE_CLK_OMAP_MUX_GATE(timer3_fck, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, + OMAP4430_CLKSEL_MASK, + OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); + +/* Merged cm2_dm4_mux into timer4 */ +DEFINE_CLK_OMAP_MUX_GATE(timer4_fck, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, + OMAP4430_CLKSEL_MASK, + OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); static const struct clksel timer5_sync_mux_sel[] = { { .parent = &syc_clk_div_ck, .rates = div_1_0_rates }, @@ -1087,30 +1324,61 @@ static const struct clksel timer5_sync_mux_sel[] = { { .parent = NULL }, }; -static const char *timer5_sync_mux_parents[] = { +static const char *timer5_fck_parents[] = { "syc_clk_div_ck", "sys_32k_ck", }; -DEFINE_CLK_OMAP_MUX(timer5_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER5_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); - -DEFINE_CLK_OMAP_MUX(timer6_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER6_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); +/* Merged timer5_sync_mux into timer5 */ +DEFINE_CLK_OMAP_MUX_GATE(timer5_fck, "abe_clkdm", timer5_sync_mux_sel, + OMAP4430_CM1_ABE_TIMER5_CLKCTRL, OMAP4430_CLKSEL_MASK, + OMAP4430_CM1_ABE_TIMER5_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + timer5_fck_parents, dmic_fck_ops); + +/* Merged timer6_sync_mux into timer6 */ +DEFINE_CLK_OMAP_MUX_GATE(timer6_fck, "abe_clkdm", timer5_sync_mux_sel, + OMAP4430_CM1_ABE_TIMER6_CLKCTRL, OMAP4430_CLKSEL_MASK, + OMAP4430_CM1_ABE_TIMER6_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + timer5_fck_parents, dmic_fck_ops); + +/* Merged timer7_sync_mux into timer7 */ +DEFINE_CLK_OMAP_MUX_GATE(timer7_fck, "abe_clkdm", timer5_sync_mux_sel, + OMAP4430_CM1_ABE_TIMER7_CLKCTRL, OMAP4430_CLKSEL_MASK, + OMAP4430_CM1_ABE_TIMER7_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + timer5_fck_parents, dmic_fck_ops); + +/* Merged timer8_sync_mux into timer8 */ +DEFINE_CLK_OMAP_MUX_GATE(timer8_fck, "abe_clkdm", timer5_sync_mux_sel, + OMAP4430_CM1_ABE_TIMER8_CLKCTRL, OMAP4430_CLKSEL_MASK, + OMAP4430_CM1_ABE_TIMER8_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + timer5_fck_parents, dmic_fck_ops); + +/* Merged cm2_dm9_mux into timer9 */ +DEFINE_CLK_OMAP_MUX_GATE(timer9_fck, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, + OMAP4430_CLKSEL_MASK, + OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, + abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); + +DEFINE_CLK_GATE(uart1_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_UART1_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); -DEFINE_CLK_OMAP_MUX(timer7_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER7_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); +DEFINE_CLK_GATE(uart2_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_UART2_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); -DEFINE_CLK_OMAP_MUX(timer8_sync_mux, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER8_CLKCTRL, OMAP4430_CLKSEL_MASK, - timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); +DEFINE_CLK_GATE(uart3_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_UART3_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); -DEFINE_CLK_OMAP_MUX(cm2_dm9_mux, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, OMAP4430_CLKSEL_MASK, - abe_dpll_bypass_clk_mux_ck_parents, - func_dmic_abe_gfclk_ops); +DEFINE_CLK_GATE(uart4_fck, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L4PER_UART4_CLKCTRL, + OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); static struct clk usb_host_fs_fck; @@ -1244,6 +1512,18 @@ DEFINE_CLK_GATE(usim_fclk, "usim_ck", &usim_ck, 0x0, OMAP4430_CM_WKUP_USIM_CLKCTRL, OMAP4430_OPTFCLKEN_FCLK_SHIFT, 0x0, NULL); +DEFINE_CLK_GATE(usim_fck, "sys_32k_ck", &sys_32k_ck, 0x0, + OMAP4430_CM_WKUP_USIM_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT, + 0x0, NULL); + +DEFINE_CLK_GATE(wd_timer2_fck, "sys_32k_ck", &sys_32k_ck, 0x0, + OMAP4430_CM_WKUP_WDT2_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, + 0x0, NULL); + +DEFINE_CLK_GATE(wd_timer3_fck, "sys_32k_ck", &sys_32k_ck, 0x0, + OMAP4430_CM1_ABE_WDT3_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, + 0x0, NULL); + /* Remaining optional clocks */ static const char *pmd_stm_clock_mux_ck_parents[] = { "sys_clkin_ck", "dpll_core_m6x2_ck", "tie_low_clock_ck", @@ -1494,61 +1774,106 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "syc_clk_div_ck", &syc_clk_div_ck, CK_443X), CLK(NULL, "aes1_fck", &aes1_fck, CK_443X), CLK(NULL, "aes2_fck", &aes2_fck, CK_443X), + CLK(NULL, "aess_fck", &aess_fck, CK_443X), CLK(NULL, "bandgap_fclk", &bandgap_fclk, CK_443X), CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X), CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk, CK_446X), + CLK(NULL, "des3des_fck", &des3des_fck, CK_443X), CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X), - CLK(NULL, "func_dmic_abe_gfclk", &func_dmic_abe_gfclk, CK_443X), + CLK(NULL, "dmic_fck", &dmic_fck, CK_443X), + CLK(NULL, "dsp_fck", &dsp_fck, CK_443X), CLK(NULL, "dss_sys_clk", &dss_sys_clk, CK_443X), CLK(NULL, "dss_tv_clk", &dss_tv_clk, CK_443X), CLK(NULL, "dss_dss_clk", &dss_dss_clk, CK_443X), CLK(NULL, "dss_48mhz_clk", &dss_48mhz_clk, CK_443X), CLK(NULL, "dss_fck", &dss_fck, CK_443X), CLK("omapdss_dss", "ick", &dss_fck, CK_443X), + CLK(NULL, "efuse_ctrl_cust_fck", &efuse_ctrl_cust_fck, CK_443X), + CLK(NULL, "emif1_fck", &emif1_fck, CK_443X), + CLK(NULL, "emif2_fck", &emif2_fck, CK_443X), CLK(NULL, "fdif_fck", &fdif_fck, CK_443X), + CLK(NULL, "fpka_fck", &fpka_fck, CK_443X), CLK(NULL, "gpio1_dbclk", &gpio1_dbclk, CK_443X), + CLK(NULL, "gpio1_ick", &gpio1_ick, CK_443X), CLK(NULL, "gpio2_dbclk", &gpio2_dbclk, CK_443X), + CLK(NULL, "gpio2_ick", &gpio2_ick, CK_443X), CLK(NULL, "gpio3_dbclk", &gpio3_dbclk, CK_443X), + CLK(NULL, "gpio3_ick", &gpio3_ick, CK_443X), CLK(NULL, "gpio4_dbclk", &gpio4_dbclk, CK_443X), + CLK(NULL, "gpio4_ick", &gpio4_ick, CK_443X), CLK(NULL, "gpio5_dbclk", &gpio5_dbclk, CK_443X), + CLK(NULL, "gpio5_ick", &gpio5_ick, CK_443X), CLK(NULL, "gpio6_dbclk", &gpio6_dbclk, CK_443X), - CLK(NULL, "sgx_clk_mux", &sgx_clk_mux, CK_443X), + CLK(NULL, "gpio6_ick", &gpio6_ick, CK_443X), + CLK(NULL, "gpmc_ick", &gpmc_ick, CK_443X), + CLK(NULL, "gpu_fck", &gpu_fck, CK_443X), + CLK(NULL, "hdq1w_fck", &hdq1w_fck, CK_443X), CLK(NULL, "hsi_fck", &hsi_fck, CK_443X), + CLK(NULL, "i2c1_fck", &i2c1_fck, CK_443X), + CLK(NULL, "i2c2_fck", &i2c2_fck, CK_443X), + CLK(NULL, "i2c3_fck", &i2c3_fck, CK_443X), + CLK(NULL, "i2c4_fck", &i2c4_fck, CK_443X), + CLK(NULL, "ipu_fck", &ipu_fck, CK_443X), CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_443X), + CLK(NULL, "iss_fck", &iss_fck, CK_443X), + CLK(NULL, "iva_fck", &iva_fck, CK_443X), + CLK(NULL, "kbd_fck", &kbd_fck, CK_443X), + CLK(NULL, "l3_instr_ick", &l3_instr_ick, CK_443X), + CLK(NULL, "l3_main_3_ick", &l3_main_3_ick, CK_443X), CLK(NULL, "mcasp_sync_mux_ck", &mcasp_sync_mux_ck, CK_443X), - CLK(NULL, "func_mcasp_abe_gfclk", &func_mcasp_abe_gfclk, CK_443X), + CLK(NULL, "mcasp_fck", &mcasp_fck, CK_443X), CLK(NULL, "mcbsp1_sync_mux_ck", &mcbsp1_sync_mux_ck, CK_443X), - CLK(NULL, "func_mcbsp1_gfclk", &func_mcbsp1_gfclk, CK_443X), + CLK(NULL, "mcbsp1_fck", &mcbsp1_fck, CK_443X), CLK(NULL, "mcbsp2_sync_mux_ck", &mcbsp2_sync_mux_ck, CK_443X), - CLK(NULL, "func_mcbsp2_gfclk", &func_mcbsp2_gfclk, CK_443X), + CLK(NULL, "mcbsp2_fck", &mcbsp2_fck, CK_443X), CLK(NULL, "mcbsp3_sync_mux_ck", &mcbsp3_sync_mux_ck, CK_443X), - CLK(NULL, "func_mcbsp3_gfclk", &func_mcbsp3_gfclk, CK_443X), + CLK(NULL, "mcbsp3_fck", &mcbsp3_fck, CK_443X), CLK(NULL, "mcbsp4_sync_mux_ck", &mcbsp4_sync_mux_ck, CK_443X), - CLK(NULL, "per_mcbsp4_gfclk", &per_mcbsp4_gfclk, CK_443X), - CLK(NULL, "hsmmc1_fclk", &hsmmc1_fclk, CK_443X), - CLK(NULL, "hsmmc2_fclk", &hsmmc2_fclk, CK_443X), + CLK(NULL, "mcbsp4_fck", &mcbsp4_fck, CK_443X), + CLK(NULL, "mcpdm_fck", &mcpdm_fck, CK_443X), + CLK(NULL, "mcspi1_fck", &mcspi1_fck, CK_443X), + CLK(NULL, "mcspi2_fck", &mcspi2_fck, CK_443X), + CLK(NULL, "mcspi3_fck", &mcspi3_fck, CK_443X), + CLK(NULL, "mcspi4_fck", &mcspi4_fck, CK_443X), + CLK(NULL, "mmc1_fck", &mmc1_fck, CK_443X), + CLK(NULL, "mmc2_fck", &mmc2_fck, CK_443X), + CLK(NULL, "mmc3_fck", &mmc3_fck, CK_443X), + CLK(NULL, "mmc4_fck", &mmc4_fck, CK_443X), + CLK(NULL, "mmc5_fck", &mmc5_fck, CK_443X), + CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m, CK_443X), + CLK(NULL, "ocp2scp_usb_phy_ick", &ocp2scp_usb_phy_ick, CK_443X), + CLK(NULL, "ocp_wp_noc_ick", &ocp_wp_noc_ick, CK_443X), + CLK(NULL, "rng_ick", &rng_ick, CK_443X), + CLK("omap_rng", "ick", &rng_ick, CK_443X), CLK(NULL, "sha2md5_fck", &sha2md5_fck, CK_443X), + CLK(NULL, "sl2if_ick", &sl2if_ick, CK_443X), CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1, CK_443X), CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0, CK_443X), CLK(NULL, "slimbus1_fclk_2", &slimbus1_fclk_2, CK_443X), CLK(NULL, "slimbus1_slimbus_clk", &slimbus1_slimbus_clk, CK_443X), + CLK(NULL, "slimbus1_fck", &slimbus1_fck, CK_443X), CLK(NULL, "slimbus2_fclk_1", &slimbus2_fclk_1, CK_443X), CLK(NULL, "slimbus2_fclk_0", &slimbus2_fclk_0, CK_443X), CLK(NULL, "slimbus2_slimbus_clk", &slimbus2_slimbus_clk, CK_443X), + CLK(NULL, "slimbus2_fck", &slimbus2_fck, CK_443X), CLK(NULL, "smartreflex_core_fck", &smartreflex_core_fck, CK_443X), CLK(NULL, "smartreflex_iva_fck", &smartreflex_iva_fck, CK_443X), CLK(NULL, "smartreflex_mpu_fck", &smartreflex_mpu_fck, CK_443X), - CLK(NULL, "dmt1_clk_mux", &dmt1_clk_mux, CK_443X), - CLK(NULL, "cm2_dm10_mux", &cm2_dm10_mux, CK_443X), - CLK(NULL, "cm2_dm11_mux", &cm2_dm11_mux, CK_443X), - CLK(NULL, "cm2_dm2_mux", &cm2_dm2_mux, CK_443X), - CLK(NULL, "cm2_dm3_mux", &cm2_dm3_mux, CK_443X), - CLK(NULL, "cm2_dm4_mux", &cm2_dm4_mux, CK_443X), - CLK(NULL, "timer5_sync_mux", &timer5_sync_mux, CK_443X), - CLK(NULL, "timer6_sync_mux", &timer6_sync_mux, CK_443X), - CLK(NULL, "timer7_sync_mux", &timer7_sync_mux, CK_443X), - CLK(NULL, "timer8_sync_mux", &timer8_sync_mux, CK_443X), - CLK(NULL, "cm2_dm9_mux", &cm2_dm9_mux, CK_443X), + CLK(NULL, "timer1_fck", &timer1_fck, CK_443X), + CLK(NULL, "timer10_fck", &timer10_fck, CK_443X), + CLK(NULL, "timer11_fck", &timer11_fck, CK_443X), + CLK(NULL, "timer2_fck", &timer2_fck, CK_443X), + CLK(NULL, "timer3_fck", &timer3_fck, CK_443X), + CLK(NULL, "timer4_fck", &timer4_fck, CK_443X), + CLK(NULL, "timer5_fck", &timer5_fck, CK_443X), + CLK(NULL, "timer6_fck", &timer6_fck, CK_443X), + CLK(NULL, "timer7_fck", &timer7_fck, CK_443X), + CLK(NULL, "timer8_fck", &timer8_fck, CK_443X), + CLK(NULL, "timer9_fck", &timer9_fck, CK_443X), + CLK(NULL, "uart1_fck", &uart1_fck, CK_443X), + CLK(NULL, "uart2_fck", &uart2_fck, CK_443X), + CLK(NULL, "uart3_fck", &uart3_fck, CK_443X), + CLK(NULL, "uart4_fck", &uart4_fck, CK_443X), CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_443X), CLK("usbhs_omap", "fs_fck", &usb_host_fs_fck, CK_443X), CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X), @@ -1576,6 +1901,9 @@ static struct omap_clk omap44xx_clks[] = { CLK("usbhs_tll", "usbtll_ick", &usb_tll_hs_ick, CK_443X), CLK(NULL, "usim_ck", &usim_ck, CK_443X), CLK(NULL, "usim_fclk", &usim_fclk, CK_443X), + CLK(NULL, "usim_fck", &usim_fck, CK_443X), + CLK(NULL, "wd_timer2_fck", &wd_timer2_fck, CK_443X), + CLK(NULL, "wd_timer3_fck", &wd_timer3_fck, CK_443X), CLK(NULL, "pmd_stm_clock_mux_ck", &pmd_stm_clock_mux_ck, CK_443X), CLK(NULL, "pmd_trace_clk_mux_ck", &pmd_trace_clk_mux_ck, CK_443X), CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck, CK_443X), @@ -1652,6 +1980,15 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "cpufreq_ck", &dpll_mpu_ck, CK_443X), }; +static const char *enable_init_clks[] = { + "emif1_fck", + "emif2_fck", + "gpmc_ick", + "l3_instr_ick", + "l3_main_3_ick", + "ocp_wp_noc_ick", +}; + int __init omap4xxx_clk_init(void) { u32 cpu_clkflg; @@ -1682,6 +2019,9 @@ int __init omap4xxx_clk_init(void) omap2_clk_disable_autoidle_all(); + omap2_clk_enable_init_clocks(enable_init_clks, + ARRAY_SIZE(enable_init_clks)); + /* * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power * state when turning the ABE clock domain. Workaround this by diff --git a/trunk/arch/arm/mach-omap2/clockdomain.c b/trunk/arch/arm/mach-omap2/clockdomain.c index 2da3b5ec010c..7faf82d4e85c 100644 --- a/trunk/arch/arm/mach-omap2/clockdomain.c +++ b/trunk/arch/arm/mach-omap2/clockdomain.c @@ -92,6 +92,8 @@ static int _clkdm_register(struct clockdomain *clkdm) pwrdm_add_clkdm(pwrdm, clkdm); + spin_lock_init(&clkdm->lock); + pr_debug("clockdomain: registered %s\n", clkdm->name); return 0; @@ -120,7 +122,7 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, return cd; } -/** +/* * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store * @autodep: struct clkdm_autodep * to resolve * @@ -152,206 +154,88 @@ static void _autodep_lookup(struct clkdm_autodep *autodep) autodep->clkdm.ptr = clkdm; } -/** - * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms - * @clkdm: clockdomain that we are resolving dependencies for - * @clkdm_deps: ptr to array of struct clkdm_deps to resolve +/* + * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable + * @clkdm: struct clockdomain * * - * Iterates through @clkdm_deps, looking up the struct clockdomain named by - * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. - * No return value. - */ -static void _resolve_clkdm_deps(struct clockdomain *clkdm, - struct clkdm_dep *clkdm_deps) -{ - struct clkdm_dep *cd; - - for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { - if (cd->clkdm) - continue; - cd->clkdm = _clkdm_lookup(cd->clkdm_name); - - WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", - clkdm->name, cd->clkdm_name); - } -} - -/** - * _clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 (lockless) - * @clkdm1: wake this struct clockdomain * up (dependent) - * @clkdm2: when this struct clockdomain * wakes up (source) + * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' + * in hardware-supervised mode. Meant to be called from clock framework + * when a clock inside clockdomain 'clkdm' is enabled. No return value. * - * When the clockdomain represented by @clkdm2 wakes up, wake up - * @clkdm1. Implemented in hardware on the OMAP, this feature is - * designed to reduce wakeup latency of the dependent clockdomain @clkdm1. - * Returns -EINVAL if presented with invalid clockdomain pointers, - * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon - * success. + * XXX autodeps are deprecated and should be removed at the earliest + * opportunity */ -static int _clkdm_add_wkdep(struct clockdomain *clkdm1, - struct clockdomain *clkdm2) +void _clkdm_add_autodeps(struct clockdomain *clkdm) { - struct clkdm_dep *cd; - int ret = 0; - - if (!clkdm1 || !clkdm2) - return -EINVAL; - - cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); - if (IS_ERR(cd)) - ret = PTR_ERR(cd); + struct clkdm_autodep *autodep; - if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) - ret = -EINVAL; + if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) + return; - if (ret) { - pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", - clkdm1->name, clkdm2->name); - return ret; - } + for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { + if (IS_ERR(autodep->clkdm.ptr)) + continue; - cd->wkdep_usecount++; - if (cd->wkdep_usecount == 1) { - pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", - clkdm1->name, clkdm2->name); + pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n", + clkdm->name, autodep->clkdm.ptr->name); - ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); + clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); + clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); } - - return ret; } -/** - * _clkdm_del_wkdep - remove a wakeup dep from clkdm2 to clkdm1 (lockless) - * @clkdm1: wake this struct clockdomain * up (dependent) - * @clkdm2: when this struct clockdomain * wakes up (source) +/* + * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm + * @clkdm: struct clockdomain * * - * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2 - * wakes up. Returns -EINVAL if presented with invalid clockdomain - * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or - * 0 upon success. - */ -static int _clkdm_del_wkdep(struct clockdomain *clkdm1, - struct clockdomain *clkdm2) -{ - struct clkdm_dep *cd; - int ret = 0; - - if (!clkdm1 || !clkdm2) - return -EINVAL; - - cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); - if (IS_ERR(cd)) - ret = PTR_ERR(cd); - - if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) - ret = -EINVAL; - - if (ret) { - pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", - clkdm1->name, clkdm2->name); - return ret; - } - - cd->wkdep_usecount--; - if (cd->wkdep_usecount == 0) { - pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n", - clkdm1->name, clkdm2->name); - - ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); - } - - return ret; -} - -/** - * _clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 (lockless) - * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) - * @clkdm2: when this struct clockdomain * is active (source) + * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' + * in hardware-supervised mode. Meant to be called from clock framework + * when a clock inside clockdomain 'clkdm' is disabled. No return value. * - * Prevent @clkdm1 from automatically going inactive (and then to - * retention or off) if @clkdm2 is active. Returns -EINVAL if - * presented with invalid clockdomain pointers or called on a machine - * that does not support software-configurable hardware sleep - * dependencies, -ENOENT if the specified dependency cannot be set in - * hardware, or 0 upon success. + * XXX autodeps are deprecated and should be removed at the earliest + * opportunity */ -static int _clkdm_add_sleepdep(struct clockdomain *clkdm1, - struct clockdomain *clkdm2) +void _clkdm_del_autodeps(struct clockdomain *clkdm) { - struct clkdm_dep *cd; - int ret = 0; - - if (!clkdm1 || !clkdm2) - return -EINVAL; - - cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); - if (IS_ERR(cd)) - ret = PTR_ERR(cd); + struct clkdm_autodep *autodep; - if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) - ret = -EINVAL; + if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) + return; - if (ret) { - pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", - clkdm1->name, clkdm2->name); - return ret; - } + for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { + if (IS_ERR(autodep->clkdm.ptr)) + continue; - cd->sleepdep_usecount++; - if (cd->sleepdep_usecount == 1) { - pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", - clkdm1->name, clkdm2->name); + pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n", + clkdm->name, autodep->clkdm.ptr->name); - ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); + clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); + clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); } - - return ret; } /** - * _clkdm_del_sleepdep - remove a sleep dep from clkdm2 to clkdm1 (lockless) - * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) - * @clkdm2: when this struct clockdomain * is active (source) + * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms + * @clkdm: clockdomain that we are resolving dependencies for + * @clkdm_deps: ptr to array of struct clkdm_deps to resolve * - * Allow @clkdm1 to automatically go inactive (and then to retention or - * off), independent of the activity state of @clkdm2. Returns -EINVAL - * if presented with invalid clockdomain pointers or called on a machine - * that does not support software-configurable hardware sleep dependencies, - * -ENOENT if the specified dependency cannot be cleared in hardware, or - * 0 upon success. + * Iterates through @clkdm_deps, looking up the struct clockdomain named by + * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. + * No return value. */ -static int _clkdm_del_sleepdep(struct clockdomain *clkdm1, - struct clockdomain *clkdm2) +static void _resolve_clkdm_deps(struct clockdomain *clkdm, + struct clkdm_dep *clkdm_deps) { struct clkdm_dep *cd; - int ret = 0; - - if (!clkdm1 || !clkdm2) - return -EINVAL; - cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); - if (IS_ERR(cd)) - ret = PTR_ERR(cd); - - if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) - ret = -EINVAL; - - if (ret) { - pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", - clkdm1->name, clkdm2->name); - return ret; - } - - cd->sleepdep_usecount--; - if (cd->sleepdep_usecount == 0) { - pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n", - clkdm1->name, clkdm2->name); + for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { + if (cd->clkdm) + continue; + cd->clkdm = _clkdm_lookup(cd->clkdm_name); - ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); + WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", + clkdm->name, cd->clkdm_name); } - - return ret; } /* Public functions */ @@ -572,18 +456,30 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; - int ret; + int ret = 0; if (!clkdm1 || !clkdm2) return -EINVAL; cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); if (IS_ERR(cd)) - return PTR_ERR(cd); + ret = PTR_ERR(cd); - pwrdm_lock(cd->clkdm->pwrdm.ptr); - ret = _clkdm_add_wkdep(clkdm1, clkdm2); - pwrdm_unlock(cd->clkdm->pwrdm.ptr); + if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) + ret = -EINVAL; + + if (ret) { + pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", + clkdm1->name, clkdm2->name); + return ret; + } + + if (atomic_inc_return(&cd->wkdep_usecount) == 1) { + pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", + clkdm1->name, clkdm2->name); + + ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); + } return ret; } @@ -601,18 +497,30 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; - int ret; + int ret = 0; if (!clkdm1 || !clkdm2) return -EINVAL; cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); if (IS_ERR(cd)) - return PTR_ERR(cd); + ret = PTR_ERR(cd); - pwrdm_lock(cd->clkdm->pwrdm.ptr); - ret = _clkdm_del_wkdep(clkdm1, clkdm2); - pwrdm_unlock(cd->clkdm->pwrdm.ptr); + if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) + ret = -EINVAL; + + if (ret) { + pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", + clkdm1->name, clkdm2->name); + return ret; + } + + if (atomic_dec_return(&cd->wkdep_usecount) == 0) { + pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n", + clkdm1->name, clkdm2->name); + + ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); + } return ret; } @@ -652,7 +560,7 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return ret; } - /* XXX It's faster to return the wkdep_usecount */ + /* XXX It's faster to return the atomic wkdep_usecount */ return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2); } @@ -692,18 +600,30 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; - int ret; + int ret = 0; if (!clkdm1 || !clkdm2) return -EINVAL; - cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); if (IS_ERR(cd)) - return PTR_ERR(cd); + ret = PTR_ERR(cd); - pwrdm_lock(cd->clkdm->pwrdm.ptr); - ret = _clkdm_add_sleepdep(clkdm1, clkdm2); - pwrdm_unlock(cd->clkdm->pwrdm.ptr); + if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) + ret = -EINVAL; + + if (ret) { + pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", + clkdm1->name, clkdm2->name); + return ret; + } + + if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { + pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", + clkdm1->name, clkdm2->name); + + ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); + } return ret; } @@ -723,18 +643,30 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { struct clkdm_dep *cd; - int ret; + int ret = 0; if (!clkdm1 || !clkdm2) return -EINVAL; - cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); if (IS_ERR(cd)) - return PTR_ERR(cd); + ret = PTR_ERR(cd); - pwrdm_lock(cd->clkdm->pwrdm.ptr); - ret = _clkdm_del_sleepdep(clkdm1, clkdm2); - pwrdm_unlock(cd->clkdm->pwrdm.ptr); + if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) + ret = -EINVAL; + + if (ret) { + pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", + clkdm1->name, clkdm2->name); + return ret; + } + + if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { + pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n", + clkdm1->name, clkdm2->name); + + ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); + } return ret; } @@ -776,7 +708,7 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return ret; } - /* XXX It's faster to return the sleepdep_usecount */ + /* XXX It's faster to return the atomic sleepdep_usecount */ return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2); } @@ -802,17 +734,18 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) } /** - * clkdm_sleep_nolock - force clockdomain sleep transition (lockless) + * clkdm_sleep - force clockdomain sleep transition * @clkdm: struct clockdomain * * * Instruct the CM to force a sleep transition on the specified - * clockdomain @clkdm. Only for use by the powerdomain code. Returns - * -EINVAL if @clkdm is NULL or if clockdomain does not support - * software-initiated sleep; 0 upon success. + * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if + * clockdomain does not support software-initiated sleep; 0 upon + * success. */ -int clkdm_sleep_nolock(struct clockdomain *clkdm) +int clkdm_sleep(struct clockdomain *clkdm) { int ret; + unsigned long flags; if (!clkdm) return -EINVAL; @@ -828,45 +761,26 @@ int clkdm_sleep_nolock(struct clockdomain *clkdm) pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); + spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; ret = arch_clkdm->clkdm_sleep(clkdm); - ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); - + spin_unlock_irqrestore(&clkdm->lock, flags); return ret; } /** - * clkdm_sleep - force clockdomain sleep transition - * @clkdm: struct clockdomain * - * - * Instruct the CM to force a sleep transition on the specified - * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if - * clockdomain does not support software-initiated sleep; 0 upon - * success. - */ -int clkdm_sleep(struct clockdomain *clkdm) -{ - int ret; - - pwrdm_lock(clkdm->pwrdm.ptr); - ret = clkdm_sleep_nolock(clkdm); - pwrdm_unlock(clkdm->pwrdm.ptr); - - return ret; -} - -/** - * clkdm_wakeup_nolock - force clockdomain wakeup transition (lockless) + * clkdm_wakeup - force clockdomain wakeup transition * @clkdm: struct clockdomain * * * Instruct the CM to force a wakeup transition on the specified - * clockdomain @clkdm. Only for use by the powerdomain code. Returns - * -EINVAL if @clkdm is NULL or if the clockdomain does not support - * software-controlled wakeup; 0 upon success. + * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the + * clockdomain does not support software-controlled wakeup; 0 upon + * success. */ -int clkdm_wakeup_nolock(struct clockdomain *clkdm) +int clkdm_wakeup(struct clockdomain *clkdm) { int ret; + unsigned long flags; if (!clkdm) return -EINVAL; @@ -882,46 +796,28 @@ int clkdm_wakeup_nolock(struct clockdomain *clkdm) pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); + spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; ret = arch_clkdm->clkdm_wakeup(clkdm); - ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); - + ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); + spin_unlock_irqrestore(&clkdm->lock, flags); return ret; } /** - * clkdm_wakeup - force clockdomain wakeup transition - * @clkdm: struct clockdomain * - * - * Instruct the CM to force a wakeup transition on the specified - * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the - * clockdomain does not support software-controlled wakeup; 0 upon - * success. - */ -int clkdm_wakeup(struct clockdomain *clkdm) -{ - int ret; - - pwrdm_lock(clkdm->pwrdm.ptr); - ret = clkdm_wakeup_nolock(clkdm); - pwrdm_unlock(clkdm->pwrdm.ptr); - - return ret; -} - -/** - * clkdm_allow_idle_nolock - enable hwsup idle transitions for clkdm + * clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * * - * Allow the hardware to automatically switch the clockdomain @clkdm - * into active or idle states, as needed by downstream clocks. If the + * Allow the hardware to automatically switch the clockdomain @clkdm into + * active or idle states, as needed by downstream clocks. If the * clockdomain has any downstream clocks enabled in the clock * framework, wkdep/sleepdep autodependencies are added; this is so - * device drivers can read and write to the device. Only for use by - * the powerdomain code. No return value. + * device drivers can read and write to the device. No return value. */ -void clkdm_allow_idle_nolock(struct clockdomain *clkdm) +void clkdm_allow_idle(struct clockdomain *clkdm) { + unsigned long flags; + if (!clkdm) return; @@ -937,26 +833,11 @@ void clkdm_allow_idle_nolock(struct clockdomain *clkdm) pr_debug("clockdomain: enabling automatic idle transitions for %s\n", clkdm->name); + spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; arch_clkdm->clkdm_allow_idle(clkdm); - pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); -} - -/** - * clkdm_allow_idle - enable hwsup idle transitions for clkdm - * @clkdm: struct clockdomain * - * - * Allow the hardware to automatically switch the clockdomain @clkdm into - * active or idle states, as needed by downstream clocks. If the - * clockdomain has any downstream clocks enabled in the clock - * framework, wkdep/sleepdep autodependencies are added; this is so - * device drivers can read and write to the device. No return value. - */ -void clkdm_allow_idle(struct clockdomain *clkdm) -{ - pwrdm_lock(clkdm->pwrdm.ptr); - clkdm_allow_idle_nolock(clkdm); - pwrdm_unlock(clkdm->pwrdm.ptr); + pwrdm_state_switch(clkdm->pwrdm.ptr); + spin_unlock_irqrestore(&clkdm->lock, flags); } /** @@ -966,11 +847,12 @@ void clkdm_allow_idle(struct clockdomain *clkdm) * Prevent the hardware from automatically switching the clockdomain * @clkdm into inactive or idle states. If the clockdomain has * downstream clocks enabled in the clock framework, wkdep/sleepdep - * autodependencies are removed. Only for use by the powerdomain - * code. No return value. + * autodependencies are removed. No return value. */ -void clkdm_deny_idle_nolock(struct clockdomain *clkdm) +void clkdm_deny_idle(struct clockdomain *clkdm) { + unsigned long flags; + if (!clkdm) return; @@ -986,25 +868,11 @@ void clkdm_deny_idle_nolock(struct clockdomain *clkdm) pr_debug("clockdomain: disabling automatic idle transitions for %s\n", clkdm->name); + spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; arch_clkdm->clkdm_deny_idle(clkdm); - pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); -} - -/** - * clkdm_deny_idle - disable hwsup idle transitions for clkdm - * @clkdm: struct clockdomain * - * - * Prevent the hardware from automatically switching the clockdomain - * @clkdm into inactive or idle states. If the clockdomain has - * downstream clocks enabled in the clock framework, wkdep/sleepdep - * autodependencies are removed. No return value. - */ -void clkdm_deny_idle(struct clockdomain *clkdm) -{ - pwrdm_lock(clkdm->pwrdm.ptr); - clkdm_deny_idle_nolock(clkdm); - pwrdm_unlock(clkdm->pwrdm.ptr); + pwrdm_state_switch(clkdm->pwrdm.ptr); + spin_unlock_irqrestore(&clkdm->lock, flags); } /** @@ -1021,11 +889,14 @@ void clkdm_deny_idle(struct clockdomain *clkdm) bool clkdm_in_hwsup(struct clockdomain *clkdm) { bool ret; + unsigned long flags; if (!clkdm) return false; + spin_lock_irqsave(&clkdm->lock, flags); ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; + spin_unlock_irqrestore(&clkdm->lock, flags); return ret; } @@ -1047,91 +918,30 @@ bool clkdm_missing_idle_reporting(struct clockdomain *clkdm) return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false; } -/* Public autodep handling functions (deprecated) */ - -/** - * clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable - * @clkdm: struct clockdomain * - * - * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' - * in hardware-supervised mode. Meant to be called from clock framework - * when a clock inside clockdomain 'clkdm' is enabled. No return value. - * - * XXX autodeps are deprecated and should be removed at the earliest - * opportunity - */ -void clkdm_add_autodeps(struct clockdomain *clkdm) -{ - struct clkdm_autodep *autodep; - - if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) - return; - - for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { - if (IS_ERR(autodep->clkdm.ptr)) - continue; - - pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n", - clkdm->name, autodep->clkdm.ptr->name); - - _clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); - _clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); - } -} - -/** - * clkdm_del_autodeps - remove auto sleepdeps/wkdeps from clkdm - * @clkdm: struct clockdomain * - * - * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' - * in hardware-supervised mode. Meant to be called from clock framework - * when a clock inside clockdomain 'clkdm' is disabled. No return value. - * - * XXX autodeps are deprecated and should be removed at the earliest - * opportunity - */ -void clkdm_del_autodeps(struct clockdomain *clkdm) -{ - struct clkdm_autodep *autodep; - - if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) - return; - - for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { - if (IS_ERR(autodep->clkdm.ptr)) - continue; - - pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n", - clkdm->name, autodep->clkdm.ptr->name); - - _clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); - _clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); - } -} - /* Clockdomain-to-clock/hwmod framework interface code */ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) { + unsigned long flags; + if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) return -EINVAL; - pwrdm_lock(clkdm->pwrdm.ptr); + spin_lock_irqsave(&clkdm->lock, flags); /* * For arch's with no autodeps, clkcm_clk_enable * should be called for every clock instance or hwmod that is * enabled, so the clkdm can be force woken up. */ - clkdm->usecount++; - if (clkdm->usecount > 1 && autodeps) { - pwrdm_unlock(clkdm->pwrdm.ptr); + if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) { + spin_unlock_irqrestore(&clkdm->lock, flags); return 0; } arch_clkdm->clkdm_clk_enable(clkdm); - pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); - pwrdm_unlock(clkdm->pwrdm.ptr); + pwrdm_state_switch(clkdm->pwrdm.ptr); + spin_unlock_irqrestore(&clkdm->lock, flags); pr_debug("clockdomain: %s: enabled\n", clkdm->name); @@ -1180,34 +990,36 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) */ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) { + unsigned long flags; + if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) return -EINVAL; - pwrdm_lock(clkdm->pwrdm.ptr); + spin_lock_irqsave(&clkdm->lock, flags); /* corner case: disabling unused clocks */ - if ((__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0) + if ((__clk_get_enable_count(clk) == 0) && + (atomic_read(&clkdm->usecount) == 0)) goto ccd_exit; - if (clkdm->usecount == 0) { - pwrdm_unlock(clkdm->pwrdm.ptr); + if (atomic_read(&clkdm->usecount) == 0) { + spin_unlock_irqrestore(&clkdm->lock, flags); WARN_ON(1); /* underflow */ return -ERANGE; } - clkdm->usecount--; - if (clkdm->usecount > 0) { - pwrdm_unlock(clkdm->pwrdm.ptr); + if (atomic_dec_return(&clkdm->usecount) > 0) { + spin_unlock_irqrestore(&clkdm->lock, flags); return 0; } arch_clkdm->clkdm_clk_disable(clkdm); - pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); + pwrdm_state_switch(clkdm->pwrdm.ptr); pr_debug("clockdomain: %s: disabled\n", clkdm->name); ccd_exit: - pwrdm_unlock(clkdm->pwrdm.ptr); + spin_unlock_irqrestore(&clkdm->lock, flags); return 0; } @@ -1260,6 +1072,8 @@ int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh) */ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) { + unsigned long flags; + /* The clkdm attribute does not exist yet prior OMAP4 */ if (cpu_is_omap24xx() || cpu_is_omap34xx()) return 0; @@ -1272,23 +1086,22 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) return -EINVAL; - pwrdm_lock(clkdm->pwrdm.ptr); + spin_lock_irqsave(&clkdm->lock, flags); - if (clkdm->usecount == 0) { - pwrdm_unlock(clkdm->pwrdm.ptr); + if (atomic_read(&clkdm->usecount) == 0) { + spin_unlock_irqrestore(&clkdm->lock, flags); WARN_ON(1); /* underflow */ return -ERANGE; } - clkdm->usecount--; - if (clkdm->usecount > 0) { - pwrdm_unlock(clkdm->pwrdm.ptr); + if (atomic_dec_return(&clkdm->usecount) > 0) { + spin_unlock_irqrestore(&clkdm->lock, flags); return 0; } arch_clkdm->clkdm_clk_disable(clkdm); - pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); - pwrdm_unlock(clkdm->pwrdm.ptr); + pwrdm_state_switch(clkdm->pwrdm.ptr); + spin_unlock_irqrestore(&clkdm->lock, flags); pr_debug("clockdomain: %s: disabled\n", clkdm->name); diff --git a/trunk/arch/arm/mach-omap2/clockdomain.h b/trunk/arch/arm/mach-omap2/clockdomain.h index 2da37656a693..bc42446e23ab 100644 --- a/trunk/arch/arm/mach-omap2/clockdomain.h +++ b/trunk/arch/arm/mach-omap2/clockdomain.h @@ -15,6 +15,7 @@ #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H #include +#include #include "powerdomain.h" #include "clock.h" @@ -91,8 +92,8 @@ struct clkdm_autodep { struct clkdm_dep { const char *clkdm_name; struct clockdomain *clkdm; - s16 wkdep_usecount; - s16 sleepdep_usecount; + atomic_t wkdep_usecount; + atomic_t sleepdep_usecount; }; /* Possible flags for struct clockdomain._flags */ @@ -136,8 +137,9 @@ struct clockdomain { const u16 clkdm_offs; struct clkdm_dep *wkdep_srcs; struct clkdm_dep *sleepdep_srcs; - int usecount; + atomic_t usecount; struct list_head node; + spinlock_t lock; }; /** @@ -194,16 +196,12 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); -void clkdm_allow_idle_nolock(struct clockdomain *clkdm); void clkdm_allow_idle(struct clockdomain *clkdm); -void clkdm_deny_idle_nolock(struct clockdomain *clkdm); void clkdm_deny_idle(struct clockdomain *clkdm); bool clkdm_in_hwsup(struct clockdomain *clkdm); bool clkdm_missing_idle_reporting(struct clockdomain *clkdm); -int clkdm_wakeup_nolock(struct clockdomain *clkdm); int clkdm_wakeup(struct clockdomain *clkdm); -int clkdm_sleep_nolock(struct clockdomain *clkdm); int clkdm_sleep(struct clockdomain *clkdm); int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); @@ -216,9 +214,8 @@ extern void __init omap243x_clockdomains_init(void); extern void __init omap3xxx_clockdomains_init(void); extern void __init am33xx_clockdomains_init(void); extern void __init omap44xx_clockdomains_init(void); - -extern void clkdm_add_autodeps(struct clockdomain *clkdm); -extern void clkdm_del_autodeps(struct clockdomain *clkdm); +extern void _clkdm_add_autodeps(struct clockdomain *clkdm); +extern void _clkdm_del_autodeps(struct clockdomain *clkdm); extern struct clkdm_ops omap2_clkdm_operations; extern struct clkdm_ops omap3_clkdm_operations; diff --git a/trunk/arch/arm/mach-omap2/cm2xxx.c b/trunk/arch/arm/mach-omap2/cm2xxx.c index 6774a53a3874..db650690e9d0 100644 --- a/trunk/arch/arm/mach-omap2/cm2xxx.c +++ b/trunk/arch/arm/mach-omap2/cm2xxx.c @@ -273,6 +273,9 @@ int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm) { + if (atomic_read(&clkdm->usecount) > 0) + _clkdm_add_autodeps(clkdm); + omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); } @@ -281,6 +284,9 @@ static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm) { omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); + + if (atomic_read(&clkdm->usecount) > 0) + _clkdm_del_autodeps(clkdm); } static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) @@ -292,8 +298,18 @@ static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) - omap2xxx_clkdm_wakeup(clkdm); + + if (hwsup) { + /* Disable HW transitions when we are changing deps */ + omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + _clkdm_add_autodeps(clkdm); + omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + } else { + if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) + omap2xxx_clkdm_wakeup(clkdm); + } return 0; } @@ -308,8 +324,17 @@ static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm) hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_SLEEP) - omap2xxx_clkdm_sleep(clkdm); + if (hwsup) { + /* Disable HW transitions when we are changing deps */ + omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + _clkdm_del_autodeps(clkdm); + omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + } else { + if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP) + omap2xxx_clkdm_sleep(clkdm); + } return 0; } diff --git a/trunk/arch/arm/mach-omap2/cm3xxx.c b/trunk/arch/arm/mach-omap2/cm3xxx.c index 9061c307d915..c2086f2e86b6 100644 --- a/trunk/arch/arm/mach-omap2/cm3xxx.c +++ b/trunk/arch/arm/mach-omap2/cm3xxx.c @@ -186,7 +186,7 @@ static int omap3xxx_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) continue; /* only happens if data is erroneous */ mask |= 1 << cd->clkdm->dep_bit; - cd->sleepdep_usecount = 0; + atomic_set(&cd->sleepdep_usecount, 0); } omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, OMAP3430_CM_SLEEPDEP); @@ -209,8 +209,8 @@ static int omap3xxx_clkdm_wakeup(struct clockdomain *clkdm) static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm) { - if (clkdm->usecount > 0) - clkdm_add_autodeps(clkdm); + if (atomic_read(&clkdm->usecount) > 0) + _clkdm_add_autodeps(clkdm); omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); @@ -221,8 +221,8 @@ static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm) omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - if (clkdm->usecount > 0) - clkdm_del_autodeps(clkdm); + if (atomic_read(&clkdm->usecount) > 0) + _clkdm_del_autodeps(clkdm); } static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) @@ -250,7 +250,7 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) /* Disable HW transitions when we are changing deps */ omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - clkdm_add_autodeps(clkdm); + _clkdm_add_autodeps(clkdm); omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); } else { @@ -287,7 +287,7 @@ static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm) /* Disable HW transitions when we are changing deps */ omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - clkdm_del_autodeps(clkdm); + _clkdm_del_autodeps(clkdm); omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); } else { diff --git a/trunk/arch/arm/mach-omap2/cminst44xx.c b/trunk/arch/arm/mach-omap2/cminst44xx.c index f0290f5566fe..7f9a464f01e9 100644 --- a/trunk/arch/arm/mach-omap2/cminst44xx.c +++ b/trunk/arch/arm/mach-omap2/cminst44xx.c @@ -393,7 +393,7 @@ static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm) continue; /* only happens if data is erroneous */ mask |= 1 << cd->clkdm->dep_bit; - cd->wkdep_usecount = 0; + atomic_set(&cd->wkdep_usecount, 0); } omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition, diff --git a/trunk/arch/arm/mach-omap2/cpuidle34xx.c b/trunk/arch/arm/mach-omap2/cpuidle34xx.c index 80392fca86c6..22590dbe8f14 100644 --- a/trunk/arch/arm/mach-omap2/cpuidle34xx.c +++ b/trunk/arch/arm/mach-omap2/cpuidle34xx.c @@ -36,66 +36,40 @@ /* Mach specific information to be recorded in the C-state driver_data */ struct omap3_idle_statedata { - u8 mpu_state; - u8 core_state; - u8 per_min_state; - u8 flags; + u32 mpu_state; + u32 core_state; }; static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; -/* - * Possible flag bits for struct omap3_idle_statedata.flags: - * - * OMAP_CPUIDLE_CX_NO_CLKDM_IDLE: don't allow the MPU clockdomain to go - * inactive. This in turn prevents the MPU DPLL from entering autoidle - * mode, so wakeup latency is greatly reduced, at the cost of additional - * energy consumption. This also prevents the CORE clockdomain from - * entering idle. - */ -#define OMAP_CPUIDLE_CX_NO_CLKDM_IDLE BIT(0) - -/* - * Prevent PER OFF if CORE is not in RETention or OFF as this would - * disable PER wakeups completely. - */ static struct omap3_idle_statedata omap3_idle_data[] = { { .mpu_state = PWRDM_POWER_ON, .core_state = PWRDM_POWER_ON, - /* In C1 do not allow PER state lower than CORE state */ - .per_min_state = PWRDM_POWER_ON, - .flags = OMAP_CPUIDLE_CX_NO_CLKDM_IDLE, }, { .mpu_state = PWRDM_POWER_ON, .core_state = PWRDM_POWER_ON, - .per_min_state = PWRDM_POWER_RET, }, { .mpu_state = PWRDM_POWER_RET, .core_state = PWRDM_POWER_ON, - .per_min_state = PWRDM_POWER_RET, }, { .mpu_state = PWRDM_POWER_OFF, .core_state = PWRDM_POWER_ON, - .per_min_state = PWRDM_POWER_RET, }, { .mpu_state = PWRDM_POWER_RET, .core_state = PWRDM_POWER_RET, - .per_min_state = PWRDM_POWER_OFF, }, { .mpu_state = PWRDM_POWER_OFF, .core_state = PWRDM_POWER_RET, - .per_min_state = PWRDM_POWER_OFF, }, { .mpu_state = PWRDM_POWER_OFF, .core_state = PWRDM_POWER_OFF, - .per_min_state = PWRDM_POWER_OFF, }, }; @@ -106,25 +80,27 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, int index) { struct omap3_idle_statedata *cx = &omap3_idle_data[index]; + u32 mpu_state = cx->mpu_state, core_state = cx->core_state; local_fiq_disable(); + pwrdm_set_next_pwrst(mpu_pd, mpu_state); + pwrdm_set_next_pwrst(core_pd, core_state); + if (omap_irq_pending() || need_resched()) goto return_sleep_time; /* Deny idle for C1 */ - if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) { + if (index == 0) { clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]); - } else { - pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state); - pwrdm_set_next_pwrst(core_pd, cx->core_state); + clkdm_deny_idle(core_pd->pwrdm_clkdms[0]); } /* * Call idle CPU PM enter notifier chain so that * VFP context is saved. */ - if (cx->mpu_state == PWRDM_POWER_OFF) + if (mpu_state == PWRDM_POWER_OFF) cpu_pm_enter(); /* Execute ARM wfi */ @@ -134,15 +110,17 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, * Call idle CPU PM enter notifier chain to restore * VFP context. */ - if (cx->mpu_state == PWRDM_POWER_OFF && - pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF) + if (pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF) cpu_pm_exit(); /* Re-allow idle for C1 */ - if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) + if (index == 0) { clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]); + clkdm_allow_idle(core_pd->pwrdm_clkdms[0]); + } return_sleep_time: + local_fiq_enable(); return index; @@ -207,7 +185,7 @@ static int next_valid_state(struct cpuidle_device *dev, * Start search from the next (lower) state. */ for (idx = index - 1; idx >= 0; idx--) { - cx = &omap3_idle_data[idx]; + cx = &omap3_idle_data[idx]; if ((cx->mpu_state >= mpu_deepest_state) && (cx->core_state >= core_deepest_state)) { next_index = idx; @@ -231,9 +209,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - int new_state_idx, ret; - u8 per_next_state, per_saved_state; + int new_state_idx; + u32 core_next_state, per_next_state = 0, per_saved_state = 0; struct omap3_idle_statedata *cx; + int ret; /* * Use only C1 if CAM is active. @@ -254,13 +233,25 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, /* Program PER state */ cx = &omap3_idle_data[new_state_idx]; + core_next_state = cx->core_state; + per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); + if (new_state_idx == 0) { + /* In C1 do not allow PER state lower than CORE state */ + if (per_next_state < core_next_state) + per_next_state = core_next_state; + } else { + /* + * Prevent PER OFF if CORE is not in RETention or OFF as this + * would disable PER wakeups completely. + */ + if ((per_next_state == PWRDM_POWER_OFF) && + (core_next_state > PWRDM_POWER_RET)) + per_next_state = PWRDM_POWER_RET; + } - per_next_state = pwrdm_read_next_pwrst(per_pd); - per_saved_state = per_next_state; - if (per_next_state < cx->per_min_state) { - per_next_state = cx->per_min_state; + /* Are we changing PER target state? */ + if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_next_state); - } ret = omap3_enter_idle(dev, drv, new_state_idx); diff --git a/trunk/arch/arm/mach-omap2/devices.c b/trunk/arch/arm/mach-omap2/devices.c index d8a0cc3b9d2c..626f3ea3142f 100644 --- a/trunk/arch/arm/mach-omap2/devices.c +++ b/trunk/arch/arm/mach-omap2/devices.c @@ -61,7 +61,8 @@ static int __init omap3_l3_init(void) if (!oh) pr_err("could not look up %s\n", oh_name); - pdev = omap_device_build("omap_l3_smx", 0, oh, NULL, 0); + pdev = omap_device_build("omap_l3_smx", 0, oh, NULL, 0, + NULL, 0, 0); WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name); @@ -95,7 +96,8 @@ static int __init omap4_l3_init(void) pr_err("could not look up %s\n", oh_name); } - pdev = omap_device_build_ss("omap_l3_noc", 0, oh, 3, NULL, 0); + pdev = omap_device_build_ss("omap_l3_noc", 0, oh, 3, NULL, + 0, NULL, 0, 0); WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name); @@ -271,7 +273,7 @@ int __init omap4_keyboard_init(struct omap4_keypad_platform_data keypad_data = sdp4430_keypad_data; pdev = omap_device_build(name, id, oh, keypad_data, - sizeof(struct omap4_keypad_platform_data)); + sizeof(struct omap4_keypad_platform_data), NULL, 0, 0); if (IS_ERR(pdev)) { WARN(1, "Can't build omap_device for %s:%s.\n", @@ -295,7 +297,7 @@ static inline void __init omap_init_mbox(void) return; } - pdev = omap_device_build("omap-mailbox", -1, oh, NULL, 0); + pdev = omap_device_build("omap-mailbox", -1, oh, NULL, 0, NULL, 0, 0); WARN(IS_ERR(pdev), "%s: could not build device, err %ld\n", __func__, PTR_ERR(pdev)); } @@ -335,7 +337,7 @@ static void __init omap_init_mcpdm(void) return; } - pdev = omap_device_build("omap-mcpdm", -1, oh, NULL, 0); + pdev = omap_device_build("omap-mcpdm", -1, oh, NULL, 0, NULL, 0, 0); WARN(IS_ERR(pdev), "Can't build omap_device for omap-mcpdm.\n"); } #else @@ -356,7 +358,7 @@ static void __init omap_init_dmic(void) return; } - pdev = omap_device_build("omap-dmic", -1, oh, NULL, 0); + pdev = omap_device_build("omap-dmic", -1, oh, NULL, 0, NULL, 0, 0); WARN(IS_ERR(pdev), "Can't build omap_device for omap-dmic.\n"); } #else @@ -382,7 +384,8 @@ static void __init omap_init_hdmi_audio(void) return; } - pdev = omap_device_build("omap-hdmi-audio-dai", -1, oh, NULL, 0, 0); + pdev = omap_device_build("omap-hdmi-audio-dai", + -1, oh, NULL, 0, NULL, 0, 0); WARN(IS_ERR(pdev), "Can't build omap_device for omap-hdmi-audio-dai.\n"); @@ -426,7 +429,8 @@ static int __init omap_mcspi_init(struct omap_hwmod *oh, void *unused) } spi_num++; - pdev = omap_device_build(name, spi_num, oh, pdata, sizeof(*pdata)); + pdev = omap_device_build(name, spi_num, oh, pdata, + sizeof(*pdata), NULL, 0, 0); WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s\n", name, oh->name); kfree(pdata); @@ -456,7 +460,7 @@ static void omap_init_rng(void) if (!oh) return; - pdev = omap_device_build("omap_rng", -1, oh, NULL, 0); + pdev = omap_device_build("omap_rng", -1, oh, NULL, 0, NULL, 0, 0); WARN(IS_ERR(pdev), "Can't build omap_device for omap_rng\n"); } @@ -685,7 +689,8 @@ static void __init omap_init_ocp2scp(void) pdata->dev_cnt = dev_cnt; - pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(*pdata)); + pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(*pdata), NULL, + 0, false); if (IS_ERR(pdev)) { pr_err("Could not build omap_device for %s %s\n", name, oh_name); diff --git a/trunk/arch/arm/mach-omap2/display.c b/trunk/arch/arm/mach-omap2/display.c index ff37be1f6f93..cc75aaf6e764 100644 --- a/trunk/arch/arm/mach-omap2/display.c +++ b/trunk/arch/arm/mach-omap2/display.c @@ -226,7 +226,7 @@ static struct platform_device *create_dss_pdev(const char *pdev_name, dev_set_name(&pdev->dev, "%s", pdev->name); ohs[0] = oh; - od = omap_device_alloc(pdev, ohs, 1); + od = omap_device_alloc(pdev, ohs, 1, NULL, 0); if (IS_ERR(od)) { pr_err("Could not alloc omap_device for %s\n", pdev_name); r = -ENOMEM; diff --git a/trunk/arch/arm/mach-omap2/dma.c b/trunk/arch/arm/mach-omap2/dma.c index 491c5c8837fa..612b98249873 100644 --- a/trunk/arch/arm/mach-omap2/dma.c +++ b/trunk/arch/arm/mach-omap2/dma.c @@ -248,7 +248,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) p->errata = configure_dma_errata(); - pdev = omap_device_build(name, 0, oh, p, sizeof(*p)); + pdev = omap_device_build(name, 0, oh, p, sizeof(*p), NULL, 0, 0); kfree(p); if (IS_ERR(pdev)) { pr_err("%s: Can't build omap_device for %s:%s.\n", diff --git a/trunk/arch/arm/mach-omap2/drm.c b/trunk/arch/arm/mach-omap2/drm.c index 4d8d1a52ffe7..2a2cfa88ddbf 100644 --- a/trunk/arch/arm/mach-omap2/drm.c +++ b/trunk/arch/arm/mach-omap2/drm.c @@ -51,7 +51,8 @@ static int __init omap_init_drm(void) oh = omap_hwmod_lookup("dmm"); if (oh) { - pdev = omap_device_build(oh->name, -1, oh, NULL, 0); + pdev = omap_device_build(oh->name, -1, oh, NULL, 0, NULL, 0, + false); WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", oh->name); } diff --git a/trunk/arch/arm/mach-omap2/gpio.c b/trunk/arch/arm/mach-omap2/gpio.c index 482ade1923b0..399acabc3d0b 100644 --- a/trunk/arch/arm/mach-omap2/gpio.c +++ b/trunk/arch/arm/mach-omap2/gpio.c @@ -131,7 +131,8 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) pwrdm = omap_hwmod_get_pwrdm(oh); pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm); - pdev = omap_device_build(name, id - 1, oh, pdata, sizeof(*pdata)); + pdev = omap_device_build(name, id - 1, oh, pdata, + sizeof(*pdata), NULL, 0, false); kfree(pdata); if (IS_ERR(pdev)) { diff --git a/trunk/arch/arm/mach-omap2/gpmc.c b/trunk/arch/arm/mach-omap2/gpmc.c index bc0783364ad3..8033cb747c86 100644 --- a/trunk/arch/arm/mach-omap2/gpmc.c +++ b/trunk/arch/arm/mach-omap2/gpmc.c @@ -1220,7 +1220,7 @@ static int __init omap_gpmc_init(void) return -ENODEV; } - pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0); + pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0, NULL, 0, 0); WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name); return IS_ERR(pdev) ? PTR_ERR(pdev) : 0; diff --git a/trunk/arch/arm/mach-omap2/hdq1w.c b/trunk/arch/arm/mach-omap2/hdq1w.c index b7aa8ba2ccb2..ab7bf181a105 100644 --- a/trunk/arch/arm/mach-omap2/hdq1w.c +++ b/trunk/arch/arm/mach-omap2/hdq1w.c @@ -87,7 +87,7 @@ static int __init omap_init_hdq(void) if (!oh) return 0; - pdev = omap_device_build(devname, id, oh, NULL, 0); + pdev = omap_device_build(devname, id, oh, NULL, 0, NULL, 0, 0); WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s.\n", devname, oh->name); diff --git a/trunk/arch/arm/mach-omap2/hsmmc.c b/trunk/arch/arm/mach-omap2/hsmmc.c index 2ef1f8714fcf..4a964338992a 100644 --- a/trunk/arch/arm/mach-omap2/hsmmc.c +++ b/trunk/arch/arm/mach-omap2/hsmmc.c @@ -522,7 +522,7 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo, } dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); - od = omap_device_alloc(pdev, ohs, 1); + od = omap_device_alloc(pdev, ohs, 1, NULL, 0); if (IS_ERR(od)) { pr_err("Could not allocate od for %s\n", name); goto put_pdev; diff --git a/trunk/arch/arm/mach-omap2/hwspinlock.c b/trunk/arch/arm/mach-omap2/hwspinlock.c index c3688903f3d4..1df9b5feda16 100644 --- a/trunk/arch/arm/mach-omap2/hwspinlock.c +++ b/trunk/arch/arm/mach-omap2/hwspinlock.c @@ -46,7 +46,8 @@ static int __init hwspinlocks_init(void) return -EINVAL; pdev = omap_device_build(dev_name, 0, oh, &omap_hwspinlock_pdata, - sizeof(struct hwspinlock_pdata)); + sizeof(struct hwspinlock_pdata), + NULL, 0, false); if (IS_ERR(pdev)) { pr_err("Can't build omap_device for %s:%s\n", dev_name, oh_name); diff --git a/trunk/arch/arm/mach-omap2/i2c.c b/trunk/arch/arm/mach-omap2/i2c.c index c11a23fa9665..b9074dde3b9c 100644 --- a/trunk/arch/arm/mach-omap2/i2c.c +++ b/trunk/arch/arm/mach-omap2/i2c.c @@ -178,7 +178,8 @@ int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata, if (cpu_is_omap34xx()) pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; pdev = omap_device_build(name, bus_id, oh, pdata, - sizeof(struct omap_i2c_bus_platform_data)); + sizeof(struct omap_i2c_bus_platform_data), + NULL, 0, 0); WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", name); return PTR_RET(pdev); diff --git a/trunk/arch/arm/mach-omap2/mcbsp.c b/trunk/arch/arm/mach-omap2/mcbsp.c index 453580410ae0..df49f2a49461 100644 --- a/trunk/arch/arm/mach-omap2/mcbsp.c +++ b/trunk/arch/arm/mach-omap2/mcbsp.c @@ -101,7 +101,7 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused) count++; } pdev = omap_device_build_ss(name, id, oh_device, count, pdata, - sizeof(*pdata)); + sizeof(*pdata), NULL, 0, false); kfree(pdata); if (IS_ERR(pdev)) { pr_err("%s: Can't build omap_device for %s:%s.\n", __func__, diff --git a/trunk/arch/arm/mach-omap2/msdi.c b/trunk/arch/arm/mach-omap2/msdi.c index c52d8b4a3e91..aafdd4ca9f4f 100644 --- a/trunk/arch/arm/mach-omap2/msdi.c +++ b/trunk/arch/arm/mach-omap2/msdi.c @@ -150,7 +150,7 @@ void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data) return; } pdev = omap_device_build(dev_name, id, oh, mmc_data[0], - sizeof(struct omap_mmc_platform_data)); + sizeof(struct omap_mmc_platform_data), NULL, 0, 0); if (IS_ERR(pdev)) WARN(1, "Can'd build omap_device for %s:%s.\n", dev_name, oh->name); diff --git a/trunk/arch/arm/mach-omap2/omap-iommu.c b/trunk/arch/arm/mach-omap2/omap-iommu.c index f7f38c7fd5ff..6da4f7ae9d7f 100644 --- a/trunk/arch/arm/mach-omap2/omap-iommu.c +++ b/trunk/arch/arm/mach-omap2/omap-iommu.c @@ -41,7 +41,8 @@ static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused) pdata->deassert_reset = omap_device_deassert_hardreset; } - pdev = omap_device_build("omap-iommu", i, oh, pdata, sizeof(*pdata)); + pdev = omap_device_build("omap-iommu", i, oh, pdata, sizeof(*pdata), + NULL, 0, 0); kfree(pdata); diff --git a/trunk/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/trunk/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 8bcb64bcdcdb..aac46bfdbeb2 100644 --- a/trunk/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/trunk/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -86,6 +86,37 @@ static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 addr) __raw_writel(addr, pm_info->wkup_sar_addr); } +/* + * Set the CPUx powerdomain's previous power state + */ +static inline void set_cpu_next_pwrst(unsigned int cpu_id, + unsigned int power_state) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); +} + +/* + * Read CPU's previous power state + */ +static inline unsigned int read_cpu_prev_pwrst(unsigned int cpu_id) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + return pwrdm_read_prev_pwrst(pm_info->pwrdm); +} + +/* + * Clear the CPUx powerdomain's previous power state + */ +static inline void clear_cpu_prev_pwrst(unsigned int cpu_id) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); +} + /* * Store the SCU power status value to scratchpad memory */ @@ -199,7 +230,6 @@ static void save_l2x0_context(void) */ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { - struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); unsigned int save_state = 0; unsigned int wakeup_cpu; @@ -238,7 +268,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) save_state = 2; cpu_clear_prev_logic_pwrst(cpu); - pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); + set_cpu_next_pwrst(cpu, power_state); set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); scu_pwrst_prepare(cpu, power_state); l2x0_pwrst_prepare(cpu, save_state); @@ -256,7 +286,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) * domain transition */ wakeup_cpu = smp_processor_id(); - pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); + set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); pwrdm_post_transition(NULL); @@ -270,8 +300,8 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) */ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) { - struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); unsigned int cpu_state = 0; + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); if (omap_rev() == OMAP4430_REV_ES1_0) return -ENXIO; @@ -279,8 +309,8 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) if (power_state == PWRDM_POWER_OFF) cpu_state = 1; - pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); - pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); + clear_cpu_prev_pwrst(cpu); + set_cpu_next_pwrst(cpu, power_state); set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup)); scu_pwrst_prepare(cpu, power_state); @@ -291,7 +321,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) */ omap4_finish_suspend(cpu_state); - pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); + set_cpu_next_pwrst(cpu, PWRDM_POWER_ON); return 0; } diff --git a/trunk/arch/arm/mach-omap2/omap_device.c b/trunk/arch/arm/mach-omap2/omap_device.c index 6ee3ad3dd95a..e065daa537c0 100644 --- a/trunk/arch/arm/mach-omap2/omap_device.c +++ b/trunk/arch/arm/mach-omap2/omap_device.c @@ -17,15 +17,68 @@ * to control power management and interconnect properties of their * devices. * - * In the medium- to long-term, this code should be implemented as a - * proper omap_bus/omap_device in Linux, no more platform_data func - * pointers + * In the medium- to long-term, this code should either be + * a) implemented via arch-specific pointers in platform_data + * or + * b) implemented as a proper omap_bus/omap_device in Linux, no more + * platform_data func pointers * * + * Guidelines for usage by driver authors: + * + * 1. These functions are intended to be used by device drivers via + * function pointers in struct platform_data. As an example, + * omap_device_enable() should be passed to the driver as + * + * struct foo_driver_platform_data { + * ... + * int (*device_enable)(struct platform_device *pdev); + * ... + * } + * + * Note that the generic "device_enable" name is used, rather than + * "omap_device_enable". This is so other architectures can pass in their + * own enable/disable functions here. + * + * This should be populated during device setup: + * + * ... + * pdata->device_enable = omap_device_enable; + * ... + * + * 2. Drivers should first check to ensure the function pointer is not null + * before calling it, as in: + * + * if (pdata->device_enable) + * pdata->device_enable(pdev); + * + * This allows other architectures that don't use similar device_enable()/ + * device_shutdown() functions to execute normally. + * + * ... + * + * Suggested usage by device drivers: + * + * During device initialization: + * device_enable() + * + * During device idle: + * (save remaining device context if necessary) + * device_idle(); + * + * During device resume: + * device_enable(); + * (restore context if necessary) + * + * During device shutdown: + * device_shutdown() + * (device must be reinitialized at this point to use it again) + * */ #undef DEBUG #include +#include #include #include #include @@ -39,8 +92,155 @@ #include "omap_device.h" #include "omap_hwmod.h" +/* These parameters are passed to _omap_device_{de,}activate() */ +#define USE_WAKEUP_LAT 0 +#define IGNORE_WAKEUP_LAT 1 + +static int omap_early_device_register(struct platform_device *pdev); + +static struct omap_device_pm_latency omap_default_latency[] = { + { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + } +}; + /* Private functions */ +/** + * _omap_device_activate - increase device readiness + * @od: struct omap_device * + * @ignore_lat: increase to latency target (0) or full readiness (1)? + * + * Increase readiness of omap_device @od (thus decreasing device + * wakeup latency, but consuming more power). If @ignore_lat is + * IGNORE_WAKEUP_LAT, make the omap_device fully active. Otherwise, + * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup + * latency is greater than the requested maximum wakeup latency, step + * backwards in the omap_device_pm_latency table to ensure the + * device's maximum wakeup latency is less than or equal to the + * requested maximum wakeup latency. Returns 0. + */ +static int _omap_device_activate(struct omap_device *od, u8 ignore_lat) +{ + struct timespec a, b, c; + + dev_dbg(&od->pdev->dev, "omap_device: activating\n"); + + while (od->pm_lat_level > 0) { + struct omap_device_pm_latency *odpl; + unsigned long long act_lat = 0; + + od->pm_lat_level--; + + odpl = od->pm_lats + od->pm_lat_level; + + if (!ignore_lat && + (od->dev_wakeup_lat <= od->_dev_wakeup_lat_limit)) + break; + + read_persistent_clock(&a); + + /* XXX check return code */ + odpl->activate_func(od); + + read_persistent_clock(&b); + + c = timespec_sub(b, a); + act_lat = timespec_to_ns(&c); + + dev_dbg(&od->pdev->dev, + "omap_device: pm_lat %d: activate: elapsed time %llu nsec\n", + od->pm_lat_level, act_lat); + + if (act_lat > odpl->activate_lat) { + odpl->activate_lat_worst = act_lat; + if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) { + odpl->activate_lat = act_lat; + dev_dbg(&od->pdev->dev, + "new worst case activate latency %d: %llu\n", + od->pm_lat_level, act_lat); + } else + dev_warn(&od->pdev->dev, + "activate latency %d higher than expected. (%llu > %d)\n", + od->pm_lat_level, act_lat, + odpl->activate_lat); + } + + od->dev_wakeup_lat -= odpl->activate_lat; + } + + return 0; +} + +/** + * _omap_device_deactivate - decrease device readiness + * @od: struct omap_device * + * @ignore_lat: decrease to latency target (0) or full inactivity (1)? + * + * Decrease readiness of omap_device @od (thus increasing device + * wakeup latency, but conserving power). If @ignore_lat is + * IGNORE_WAKEUP_LAT, make the omap_device fully inactive. Otherwise, + * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup + * latency is less than the requested maximum wakeup latency, step + * forwards in the omap_device_pm_latency table to ensure the device's + * maximum wakeup latency is less than or equal to the requested + * maximum wakeup latency. Returns 0. + */ +static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat) +{ + struct timespec a, b, c; + + dev_dbg(&od->pdev->dev, "omap_device: deactivating\n"); + + while (od->pm_lat_level < od->pm_lats_cnt) { + struct omap_device_pm_latency *odpl; + unsigned long long deact_lat = 0; + + odpl = od->pm_lats + od->pm_lat_level; + + if (!ignore_lat && + ((od->dev_wakeup_lat + odpl->activate_lat) > + od->_dev_wakeup_lat_limit)) + break; + + read_persistent_clock(&a); + + /* XXX check return code */ + odpl->deactivate_func(od); + + read_persistent_clock(&b); + + c = timespec_sub(b, a); + deact_lat = timespec_to_ns(&c); + + dev_dbg(&od->pdev->dev, + "omap_device: pm_lat %d: deactivate: elapsed time %llu nsec\n", + od->pm_lat_level, deact_lat); + + if (deact_lat > odpl->deactivate_lat) { + odpl->deactivate_lat_worst = deact_lat; + if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) { + odpl->deactivate_lat = deact_lat; + dev_dbg(&od->pdev->dev, + "new worst case deactivate latency %d: %llu\n", + od->pm_lat_level, deact_lat); + } else + dev_warn(&od->pdev->dev, + "deactivate latency %d higher than expected. (%llu > %d)\n", + od->pm_lat_level, deact_lat, + odpl->deactivate_lat); + } + + od->dev_wakeup_lat += odpl->activate_lat; + + od->pm_lat_level++; + } + + return 0; +} + static void _add_clkdev(struct omap_device *od, const char *clk_alias, const char *clk_name) { @@ -115,6 +315,9 @@ static void _add_hwmod_clocks_clkdev(struct omap_device *od, * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata + * @pm_lats: pointer to a omap_device_pm_latency array for this device + * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats + * @is_early_device: should the device be registered as an early device or not * * Function for building an omap_device already registered from device-tree * @@ -153,7 +356,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev) hwmods[i] = oh; } - od = omap_device_alloc(pdev, hwmods, oh_cnt); + od = omap_device_alloc(pdev, hwmods, oh_cnt, NULL, 0); if (!od) { dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n", oh_name); @@ -204,39 +407,6 @@ static int _omap_device_notifier_call(struct notifier_block *nb, return NOTIFY_DONE; } -/** - * _omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods - * @od: struct omap_device *od - * - * Enable all underlying hwmods. Returns 0. - */ -static int _omap_device_enable_hwmods(struct omap_device *od) -{ - int i; - - for (i = 0; i < od->hwmods_cnt; i++) - omap_hwmod_enable(od->hwmods[i]); - - /* XXX pass along return value here? */ - return 0; -} - -/** - * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods - * @od: struct omap_device *od - * - * Idle all underlying hwmods. Returns 0. - */ -static int _omap_device_idle_hwmods(struct omap_device *od) -{ - int i; - - for (i = 0; i < od->hwmods_cnt; i++) - omap_hwmod_idle(od->hwmods[i]); - - /* XXX pass along return value here? */ - return 0; -} /* Public functions for use by core code */ @@ -356,14 +526,18 @@ static int _od_fill_dma_resources(struct omap_device *od, * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata + * @pm_lats: pointer to a omap_device_pm_latency array for this device + * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats * * Convenience function for allocating an omap_device structure and filling - * hwmods, and resources. + * hwmods, resources and pm_latency attributes. * * Returns an struct omap_device pointer or ERR_PTR() on error; */ struct omap_device *omap_device_alloc(struct platform_device *pdev, - struct omap_hwmod **ohs, int oh_cnt) + struct omap_hwmod **ohs, int oh_cnt, + struct omap_device_pm_latency *pm_lats, + int pm_lats_cnt) { int ret = -ENOMEM; struct omap_device *od; @@ -452,6 +626,18 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev, goto oda_exit3; have_everything: + if (!pm_lats) { + pm_lats = omap_default_latency; + pm_lats_cnt = ARRAY_SIZE(omap_default_latency); + } + + od->pm_lats_cnt = pm_lats_cnt; + od->pm_lats = kmemdup(pm_lats, + sizeof(struct omap_device_pm_latency) * pm_lats_cnt, + GFP_KERNEL); + if (!od->pm_lats) + goto oda_exit3; + pdev->archdata.od = od; for (i = 0; i < oh_cnt; i++) { @@ -477,6 +663,7 @@ void omap_device_delete(struct omap_device *od) return; od->pdev->archdata.od = NULL; + kfree(od->pm_lats); kfree(od->hwmods); kfree(od); } @@ -488,6 +675,9 @@ void omap_device_delete(struct omap_device *od) * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata + * @pm_lats: pointer to a omap_device_pm_latency array for this device + * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats + * @is_early_device: should the device be registered as an early device or not * * Convenience function for building and registering a single * omap_device record, which in turn builds and registers a @@ -495,10 +685,11 @@ void omap_device_delete(struct omap_device *od) * information. Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise, * passes along the return value of omap_device_build_ss(). */ -struct platform_device __init *omap_device_build(const char *pdev_name, - int pdev_id, - struct omap_hwmod *oh, - void *pdata, int pdata_len) +struct platform_device __init *omap_device_build(const char *pdev_name, int pdev_id, + struct omap_hwmod *oh, void *pdata, + int pdata_len, + struct omap_device_pm_latency *pm_lats, + int pm_lats_cnt, int is_early_device) { struct omap_hwmod *ohs[] = { oh }; @@ -506,7 +697,8 @@ struct platform_device __init *omap_device_build(const char *pdev_name, return ERR_PTR(-EINVAL); return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata, - pdata_len); + pdata_len, pm_lats, pm_lats_cnt, + is_early_device); } /** @@ -516,6 +708,9 @@ struct platform_device __init *omap_device_build(const char *pdev_name, * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata + * @pm_lats: pointer to a omap_device_pm_latency array for this device + * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats + * @is_early_device: should the device be registered as an early device or not * * Convenience function for building and registering an omap_device * subsystem record. Subsystem records consist of multiple @@ -523,11 +718,11 @@ struct platform_device __init *omap_device_build(const char *pdev_name, * platform_device record. Returns an ERR_PTR() on error, or passes * along the return value of omap_device_register(). */ -struct platform_device __init *omap_device_build_ss(const char *pdev_name, - int pdev_id, - struct omap_hwmod **ohs, - int oh_cnt, void *pdata, - int pdata_len) +struct platform_device __init *omap_device_build_ss(const char *pdev_name, int pdev_id, + struct omap_hwmod **ohs, int oh_cnt, + void *pdata, int pdata_len, + struct omap_device_pm_latency *pm_lats, + int pm_lats_cnt, int is_early_device) { int ret = -ENOMEM; struct platform_device *pdev; @@ -551,7 +746,7 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name, else dev_set_name(&pdev->dev, "%s", pdev->name); - od = omap_device_alloc(pdev, ohs, oh_cnt); + od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt); if (IS_ERR(od)) goto odbs_exit1; @@ -559,7 +754,10 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name, if (ret) goto odbs_exit2; - ret = omap_device_register(pdev); + if (is_early_device) + ret = omap_early_device_register(pdev); + else + ret = omap_device_register(pdev); if (ret) goto odbs_exit2; @@ -576,6 +774,24 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name, return ERR_PTR(ret); } +/** + * omap_early_device_register - register an omap_device as an early platform + * device. + * @od: struct omap_device * to register + * + * Register the omap_device structure. This currently just calls + * platform_early_add_device() on the underlying platform_device. + * Returns 0 by default. + */ +static int __init omap_early_device_register(struct platform_device *pdev) +{ + struct platform_device *devices[1]; + + devices[0] = pdev; + early_platform_add_devices(devices, 1); + return 0; +} + #ifdef CONFIG_PM_RUNTIME static int _od_runtime_suspend(struct device *dev) { @@ -686,9 +902,10 @@ int omap_device_register(struct platform_device *pdev) * to be accessible and ready to operate. This generally involves * enabling clocks, setting SYSCONFIG registers; and in the future may * involve remuxing pins. Device drivers should call this function - * indirectly via pm_runtime_get*(). Returns -EINVAL if called when - * the omap_device is already enabled, or passes along the return - * value of _omap_device_enable_hwmods(). + * (through platform_data function pointers) where they would normally + * enable clocks, etc. Returns -EINVAL if called when the omap_device + * is already enabled, or passes along the return value of + * _omap_device_activate(). */ int omap_device_enable(struct platform_device *pdev) { @@ -704,8 +921,14 @@ int omap_device_enable(struct platform_device *pdev) return -EINVAL; } - ret = _omap_device_enable_hwmods(od); + /* Enable everything if we're enabling this device from scratch */ + if (od->_state == OMAP_DEVICE_STATE_UNKNOWN) + od->pm_lat_level = od->pm_lats_cnt; + + ret = _omap_device_activate(od, IGNORE_WAKEUP_LAT); + od->dev_wakeup_lat = 0; + od->_dev_wakeup_lat_limit = UINT_MAX; od->_state = OMAP_DEVICE_STATE_ENABLED; return ret; @@ -715,10 +938,14 @@ int omap_device_enable(struct platform_device *pdev) * omap_device_idle - idle an omap_device * @od: struct omap_device * to idle * - * Idle omap_device @od. Device drivers call this function indirectly - * via pm_runtime_put*(). Returns -EINVAL if the omap_device is not + * Idle omap_device @od by calling as many .deactivate_func() entries + * in the omap_device's pm_lats table as is possible without exceeding + * the device's maximum wakeup latency limit, pm_lat_limit. Device + * drivers should call this function (through platform_data function + * pointers) where they would normally disable clocks after operations + * complete, etc.. Returns -EINVAL if the omap_device is not * currently enabled, or passes along the return value of - * _omap_device_idle_hwmods(). + * _omap_device_deactivate(). */ int omap_device_idle(struct platform_device *pdev) { @@ -734,13 +961,49 @@ int omap_device_idle(struct platform_device *pdev) return -EINVAL; } - ret = _omap_device_idle_hwmods(od); + ret = _omap_device_deactivate(od, USE_WAKEUP_LAT); od->_state = OMAP_DEVICE_STATE_IDLE; return ret; } +/** + * omap_device_shutdown - shut down an omap_device + * @od: struct omap_device * to shut down + * + * Shut down omap_device @od by calling all .deactivate_func() entries + * in the omap_device's pm_lats table and then shutting down all of + * the underlying omap_hwmods. Used when a device is being "removed" + * or a device driver is being unloaded. Returns -EINVAL if the + * omap_device is not currently enabled or idle, or passes along the + * return value of _omap_device_deactivate(). + */ +int omap_device_shutdown(struct platform_device *pdev) +{ + int ret, i; + struct omap_device *od; + + od = to_omap_device(pdev); + + if (od->_state != OMAP_DEVICE_STATE_ENABLED && + od->_state != OMAP_DEVICE_STATE_IDLE) { + dev_warn(&pdev->dev, + "omap_device: %s() called from invalid state %d\n", + __func__, od->_state); + return -EINVAL; + } + + ret = _omap_device_deactivate(od, IGNORE_WAKEUP_LAT); + + for (i = 0; i < od->hwmods_cnt; i++) + omap_hwmod_shutdown(od->hwmods[i]); + + od->_state = OMAP_DEVICE_STATE_SHUTDOWN; + + return ret; +} + /** * omap_device_assert_hardreset - set a device's hardreset line * @pdev: struct platform_device * to reset @@ -796,6 +1059,86 @@ int omap_device_deassert_hardreset(struct platform_device *pdev, return ret; } +/** + * omap_device_align_pm_lat - activate/deactivate device to match wakeup lat lim + * @od: struct omap_device * + * + * When a device's maximum wakeup latency limit changes, call some of + * the .activate_func or .deactivate_func function pointers in the + * omap_device's pm_lats array to ensure that the device's maximum + * wakeup latency is less than or equal to the new latency limit. + * Intended to be called by OMAP PM code whenever a device's maximum + * wakeup latency limit changes (e.g., via + * omap_pm_set_dev_wakeup_lat()). Returns 0 if nothing needs to be + * done (e.g., if the omap_device is not currently idle, or if the + * wakeup latency is already current with the new limit) or passes + * along the return value of _omap_device_deactivate() or + * _omap_device_activate(). + */ +int omap_device_align_pm_lat(struct platform_device *pdev, + u32 new_wakeup_lat_limit) +{ + int ret = -EINVAL; + struct omap_device *od; + + od = to_omap_device(pdev); + + if (new_wakeup_lat_limit == od->dev_wakeup_lat) + return 0; + + od->_dev_wakeup_lat_limit = new_wakeup_lat_limit; + + if (od->_state != OMAP_DEVICE_STATE_IDLE) + return 0; + else if (new_wakeup_lat_limit > od->dev_wakeup_lat) + ret = _omap_device_deactivate(od, USE_WAKEUP_LAT); + else if (new_wakeup_lat_limit < od->dev_wakeup_lat) + ret = _omap_device_activate(od, USE_WAKEUP_LAT); + + return ret; +} + +/** + * omap_device_get_pwrdm - return the powerdomain * associated with @od + * @od: struct omap_device * + * + * Return the powerdomain associated with the first underlying + * omap_hwmod for this omap_device. Intended for use by core OMAP PM + * code. Returns NULL on error or a struct powerdomain * upon + * success. + */ +struct powerdomain *omap_device_get_pwrdm(struct omap_device *od) +{ + /* + * XXX Assumes that all omap_hwmod powerdomains are identical. + * This may not necessarily be true. There should be a sanity + * check in here to WARN() if any difference appears. + */ + if (!od->hwmods_cnt) + return NULL; + + return omap_hwmod_get_pwrdm(od->hwmods[0]); +} + +/** + * omap_device_get_mpu_rt_va - return the MPU's virtual addr for the hwmod base + * @od: struct omap_device * + * + * Return the MPU's virtual address for the base of the hwmod, from + * the ioremap() that the hwmod code does. Only valid if there is one + * hwmod associated with this device. Returns NULL if there are zero + * or more than one hwmods associated with this omap_device; + * otherwise, passes along the return value from + * omap_hwmod_get_mpu_rt_va(). + */ +void __iomem *omap_device_get_rt_va(struct omap_device *od) +{ + if (od->hwmods_cnt != 1) + return NULL; + + return omap_hwmod_get_mpu_rt_va(od->hwmods[0]); +} + /** * omap_device_get_by_hwmod_name() - convert a hwmod name to * device pointer. @@ -830,6 +1173,82 @@ struct device *omap_device_get_by_hwmod_name(const char *oh_name) return &oh->od->pdev->dev; } +EXPORT_SYMBOL(omap_device_get_by_hwmod_name); + +/* + * Public functions intended for use in omap_device_pm_latency + * .activate_func and .deactivate_func function pointers + */ + +/** + * omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods + * @od: struct omap_device *od + * + * Enable all underlying hwmods. Returns 0. + */ +int omap_device_enable_hwmods(struct omap_device *od) +{ + int i; + + for (i = 0; i < od->hwmods_cnt; i++) + omap_hwmod_enable(od->hwmods[i]); + + /* XXX pass along return value here? */ + return 0; +} + +/** + * omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods + * @od: struct omap_device *od + * + * Idle all underlying hwmods. Returns 0. + */ +int omap_device_idle_hwmods(struct omap_device *od) +{ + int i; + + for (i = 0; i < od->hwmods_cnt; i++) + omap_hwmod_idle(od->hwmods[i]); + + /* XXX pass along return value here? */ + return 0; +} + +/** + * omap_device_disable_clocks - disable all main and interface clocks + * @od: struct omap_device *od + * + * Disable the main functional clock and interface clock for all of the + * omap_hwmods associated with the omap_device. Returns 0. + */ +int omap_device_disable_clocks(struct omap_device *od) +{ + int i; + + for (i = 0; i < od->hwmods_cnt; i++) + omap_hwmod_disable_clocks(od->hwmods[i]); + + /* XXX pass along return value here? */ + return 0; +} + +/** + * omap_device_enable_clocks - enable all main and interface clocks + * @od: struct omap_device *od + * + * Enable the main functional clock and interface clock for all of the + * omap_hwmods associated with the omap_device. Returns 0. + */ +int omap_device_enable_clocks(struct omap_device *od) +{ + int i; + + for (i = 0; i < od->hwmods_cnt; i++) + omap_hwmod_enable_clocks(od->hwmods[i]); + + /* XXX pass along return value here? */ + return 0; +} static struct notifier_block platform_nb = { .notifier_call = _omap_device_notifier_call, diff --git a/trunk/arch/arm/mach-omap2/omap_device.h b/trunk/arch/arm/mach-omap2/omap_device.h index 044c31d50e5b..0933c599bf89 100644 --- a/trunk/arch/arm/mach-omap2/omap_device.h +++ b/trunk/arch/arm/mach-omap2/omap_device.h @@ -13,12 +13,20 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * This type of functionality should be implemented as a proper - * omap_bus/omap_device in Linux. + * Eventually this type of functionality should either be + * a) implemented via arch-specific pointers in platform_device + * or + * b) implemented as a proper omap_bus/omap_device in Linux, no more + * platform_device * * omap_device differs from omap_hwmod in that it includes external * (e.g., board- and system-level) integration details. omap_hwmod * stores hardware data that is invariant for a given OMAP chip. + * + * To do: + * - GPIO integration + * - regulator integration + * */ #ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_DEVICE_H #define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_DEVICE_H @@ -37,14 +45,19 @@ extern struct dev_pm_domain omap_device_pm_domain; #define OMAP_DEVICE_STATE_SHUTDOWN 3 /* omap_device.flags values */ -#define OMAP_DEVICE_SUSPENDED BIT(0) -#define OMAP_DEVICE_NO_IDLE_ON_SUSPEND BIT(1) +#define OMAP_DEVICE_SUSPENDED BIT(0) +#define OMAP_DEVICE_NO_IDLE_ON_SUSPEND BIT(1) /** * struct omap_device - omap_device wrapper for platform_devices * @pdev: platform_device * @hwmods: (one .. many per omap_device) * @hwmods_cnt: ARRAY_SIZE() of @hwmods + * @pm_lats: ptr to an omap_device_pm_latency table + * @pm_lats_cnt: ARRAY_SIZE() of what is passed to @pm_lats + * @pm_lat_level: array index of the last odpl entry executed - -1 if never + * @dev_wakeup_lat: dev wakeup latency in nanoseconds + * @_dev_wakeup_lat_limit: dev wakeup latency limit in nsec - set by OMAP PM * @_state: one of OMAP_DEVICE_STATE_* (see above) * @flags: device flags * @_driver_status: one of BUS_NOTIFY_*_DRIVER from @@ -58,7 +71,12 @@ extern struct dev_pm_domain omap_device_pm_domain; struct omap_device { struct platform_device *pdev; struct omap_hwmod **hwmods; + struct omap_device_pm_latency *pm_lats; + u32 dev_wakeup_lat; + u32 _dev_wakeup_lat_limit; unsigned long _driver_status; + u8 pm_lats_cnt; + s8 pm_lat_level; u8 hwmods_cnt; u8 _state; u8 flags; @@ -68,25 +86,36 @@ struct omap_device { int omap_device_enable(struct platform_device *pdev); int omap_device_idle(struct platform_device *pdev); +int omap_device_shutdown(struct platform_device *pdev); /* Core code interface */ struct platform_device *omap_device_build(const char *pdev_name, int pdev_id, - struct omap_hwmod *oh, void *pdata, - int pdata_len); + struct omap_hwmod *oh, void *pdata, + int pdata_len, + struct omap_device_pm_latency *pm_lats, + int pm_lats_cnt, int is_early_device); struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id, struct omap_hwmod **oh, int oh_cnt, - void *pdata, int pdata_len); + void *pdata, int pdata_len, + struct omap_device_pm_latency *pm_lats, + int pm_lats_cnt, int is_early_device); struct omap_device *omap_device_alloc(struct platform_device *pdev, - struct omap_hwmod **ohs, int oh_cnt); + struct omap_hwmod **ohs, int oh_cnt, + struct omap_device_pm_latency *pm_lats, + int pm_lats_cnt); void omap_device_delete(struct omap_device *od); int omap_device_register(struct platform_device *pdev); +void __iomem *omap_device_get_rt_va(struct omap_device *od); struct device *omap_device_get_by_hwmod_name(const char *oh_name); /* OMAP PM interface */ +int omap_device_align_pm_lat(struct platform_device *pdev, + u32 new_wakeup_lat_limit); +struct powerdomain *omap_device_get_pwrdm(struct omap_device *od); int omap_device_get_context_loss_count(struct platform_device *pdev); /* Other */ @@ -95,6 +124,40 @@ int omap_device_assert_hardreset(struct platform_device *pdev, const char *name); int omap_device_deassert_hardreset(struct platform_device *pdev, const char *name); +int omap_device_idle_hwmods(struct omap_device *od); +int omap_device_enable_hwmods(struct omap_device *od); + +int omap_device_disable_clocks(struct omap_device *od); +int omap_device_enable_clocks(struct omap_device *od); + +/* + * Entries should be kept in latency order ascending + * + * deact_lat is the maximum number of microseconds required to complete + * deactivate_func() at the device's slowest OPP. + * + * act_lat is the maximum number of microseconds required to complete + * activate_func() at the device's slowest OPP. + * + * This will result in some suboptimal power management decisions at fast + * OPPs, but avoids having to recompute all device power management decisions + * if the system shifts from a fast OPP to a slow OPP (in order to meet + * latency requirements). + * + * XXX should deactivate_func/activate_func() take platform_device pointers + * rather than omap_device pointers? + */ +struct omap_device_pm_latency { + u32 deactivate_lat; + u32 deactivate_lat_worst; + int (*deactivate_func)(struct omap_device *od); + u32 activate_lat; + u32 activate_lat_worst; + int (*activate_func)(struct omap_device *od); + u32 flags; +}; + +#define OMAP_DEVICE_LATENCY_AUTO_ADJUST BIT(1) /* Get omap_device pointer from platform_device pointer */ static inline struct omap_device *to_omap_device(struct platform_device *pdev) diff --git a/trunk/arch/arm/mach-omap2/omap_hwmod.c b/trunk/arch/arm/mach-omap2/omap_hwmod.c index 6804d474a47d..4653efb87a27 100644 --- a/trunk/arch/arm/mach-omap2/omap_hwmod.c +++ b/trunk/arch/arm/mach-omap2/omap_hwmod.c @@ -139,8 +139,6 @@ #include #include -#include - #include "clock.h" #include "omap_hwmod.h" @@ -2136,8 +2134,6 @@ static int _enable(struct omap_hwmod *oh) _enable_clocks(oh); if (soc_ops.enable_module) soc_ops.enable_module(oh); - if (oh->flags & HWMOD_BLOCK_WFI) - disable_hlt(); if (soc_ops.update_context_lost) soc_ops.update_context_lost(oh); @@ -2199,8 +2195,6 @@ static int _idle(struct omap_hwmod *oh) _idle_sysc(oh); _del_initiator_dep(oh, mpu_oh); - if (oh->flags & HWMOD_BLOCK_WFI) - enable_hlt(); if (soc_ops.disable_module) soc_ops.disable_module(oh); @@ -2309,8 +2303,6 @@ static int _shutdown(struct omap_hwmod *oh) if (oh->_state == _HWMOD_STATE_ENABLED) { _del_initiator_dep(oh, mpu_oh); /* XXX what about the other system initiators here? dma, dsp */ - if (oh->flags & HWMOD_BLOCK_WFI) - enable_hlt(); if (soc_ops.disable_module) soc_ops.disable_module(oh); _disable_clocks(oh); diff --git a/trunk/arch/arm/mach-omap2/omap_hwmod.h b/trunk/arch/arm/mach-omap2/omap_hwmod.h index 80c00e706d69..3ae852a522f9 100644 --- a/trunk/arch/arm/mach-omap2/omap_hwmod.h +++ b/trunk/arch/arm/mach-omap2/omap_hwmod.h @@ -451,14 +451,6 @@ struct omap_hwmod_omap4_prcm { * enabled. This prevents the hwmod code from being able to * enable and reset the IP block early. XXX Eventually it should * be possible to query the clock framework for this information. - * HWMOD_BLOCK_WFI: Some OMAP peripherals apparently don't work - * correctly if the MPU is allowed to go idle while the - * peripherals are active. This is apparently true for the I2C on - * OMAP2420, and also the EMAC on AM3517/3505. It's unlikely that - * this is really true -- we're probably not configuring something - * correctly, or this is being abused to deal with some PM latency - * issues -- but we're currently suffering from a shortage of - * folks who are able to track these issues down properly. */ #define HWMOD_SWSUP_SIDLE (1 << 0) #define HWMOD_SWSUP_MSTANDBY (1 << 1) @@ -470,7 +462,6 @@ struct omap_hwmod_omap4_prcm { #define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7) #define HWMOD_16BIT_REG (1 << 8) #define HWMOD_EXT_OPT_MAIN_CLK (1 << 9) -#define HWMOD_BLOCK_WFI (1 << 10) /* * omap_hwmod._int_flags definitions diff --git a/trunk/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/trunk/arch/arm/mach-omap2/omap_hwmod_2420_data.c index 6a764af6c6d3..b5efe58c0be0 100644 --- a/trunk/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/trunk/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -121,12 +121,7 @@ static struct omap_hwmod omap2420_i2c1_hwmod = { }, .class = &i2c_class, .dev_attr = &i2c_dev_attr, - /* - * From mach-omap2/pm24xx.c: "Putting MPU into the WFI state - * while a transfer is active seems to cause the I2C block to - * timeout. Why? Good question." - */ - .flags = (HWMOD_16BIT_REG | HWMOD_BLOCK_WFI), + .flags = HWMOD_16BIT_REG, }; /* I2C2 */ diff --git a/trunk/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/trunk/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index a1849a883702..793f54ac7d14 100644 --- a/trunk/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/trunk/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -616,7 +616,7 @@ static struct omap_hwmod omap44xx_dmic_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_dmic_irqs, .sdma_reqs = omap44xx_dmic_sdma_reqs, - .main_clk = "func_dmic_abe_gfclk", + .main_clk = "dmic_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_DMIC_CLKCTRL_OFFSET, @@ -1161,7 +1161,7 @@ static struct omap_hwmod omap44xx_gpio1_hwmod = { .class = &omap44xx_gpio_hwmod_class, .clkdm_name = "l4_wkup_clkdm", .mpu_irqs = omap44xx_gpio1_irqs, - .main_clk = "l4_wkup_clk_mux_ck", + .main_clk = "gpio1_ick", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_WKUP_GPIO1_CLKCTRL_OFFSET, @@ -1190,7 +1190,7 @@ static struct omap_hwmod omap44xx_gpio2_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio2_irqs, - .main_clk = "l4_div_ck", + .main_clk = "gpio2_ick", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET, @@ -1219,7 +1219,7 @@ static struct omap_hwmod omap44xx_gpio3_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio3_irqs, - .main_clk = "l4_div_ck", + .main_clk = "gpio3_ick", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET, @@ -1248,7 +1248,7 @@ static struct omap_hwmod omap44xx_gpio4_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio4_irqs, - .main_clk = "l4_div_ck", + .main_clk = "gpio4_ick", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET, @@ -1277,7 +1277,7 @@ static struct omap_hwmod omap44xx_gpio5_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio5_irqs, - .main_clk = "l4_div_ck", + .main_clk = "gpio5_ick", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET, @@ -1306,7 +1306,7 @@ static struct omap_hwmod omap44xx_gpio6_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio6_irqs, - .main_clk = "l4_div_ck", + .main_clk = "gpio6_ick", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET, @@ -1405,7 +1405,7 @@ static struct omap_hwmod omap44xx_gpu_hwmod = { .class = &omap44xx_gpu_hwmod_class, .clkdm_name = "l3_gfx_clkdm", .mpu_irqs = omap44xx_gpu_irqs, - .main_clk = "sgx_clk_mux", + .main_clk = "gpu_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_GFX_GFX_CLKCTRL_OFFSET, @@ -1446,7 +1446,7 @@ static struct omap_hwmod omap44xx_hdq1w_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_INIT_NO_RESET, /* XXX temporary */ .mpu_irqs = omap44xx_hdq1w_irqs, - .main_clk = "func_12m_fclk", + .main_clk = "hdq1w_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_HDQ1W_CLKCTRL_OFFSET, @@ -1550,7 +1550,7 @@ static struct omap_hwmod omap44xx_i2c1_hwmod = { .flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_i2c1_irqs, .sdma_reqs = omap44xx_i2c1_sdma_reqs, - .main_clk = "func_96m_fclk", + .main_clk = "i2c1_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET, @@ -1580,7 +1580,7 @@ static struct omap_hwmod omap44xx_i2c2_hwmod = { .flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_i2c2_irqs, .sdma_reqs = omap44xx_i2c2_sdma_reqs, - .main_clk = "func_96m_fclk", + .main_clk = "i2c2_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET, @@ -1610,7 +1610,7 @@ static struct omap_hwmod omap44xx_i2c3_hwmod = { .flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_i2c3_irqs, .sdma_reqs = omap44xx_i2c3_sdma_reqs, - .main_clk = "func_96m_fclk", + .main_clk = "i2c3_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET, @@ -1640,7 +1640,7 @@ static struct omap_hwmod omap44xx_i2c4_hwmod = { .flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_i2c4_irqs, .sdma_reqs = omap44xx_i2c4_sdma_reqs, - .main_clk = "func_96m_fclk", + .main_clk = "i2c4_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET, @@ -1743,7 +1743,7 @@ static struct omap_hwmod omap44xx_iss_hwmod = { .clkdm_name = "iss_clkdm", .mpu_irqs = omap44xx_iss_irqs, .sdma_reqs = omap44xx_iss_sdma_reqs, - .main_clk = "ducati_clk_mux_ck", + .main_clk = "iss_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET, @@ -1785,7 +1785,7 @@ static struct omap_hwmod omap44xx_iva_hwmod = { .mpu_irqs = omap44xx_iva_irqs, .rst_lines = omap44xx_iva_resets, .rst_lines_cnt = ARRAY_SIZE(omap44xx_iva_resets), - .main_clk = "dpll_iva_m5x2_ck", + .main_clk = "iva_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_IVAHD_IVAHD_CLKCTRL_OFFSET, @@ -1829,7 +1829,7 @@ static struct omap_hwmod omap44xx_kbd_hwmod = { .class = &omap44xx_kbd_hwmod_class, .clkdm_name = "l4_wkup_clkdm", .mpu_irqs = omap44xx_kbd_irqs, - .main_clk = "sys_32k_ck", + .main_clk = "kbd_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_WKUP_KEYBOARD_CLKCTRL_OFFSET, @@ -1920,7 +1920,7 @@ static struct omap_hwmod omap44xx_mcasp_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_mcasp_irqs, .sdma_reqs = omap44xx_mcasp_sdma_reqs, - .main_clk = "func_mcasp_abe_gfclk", + .main_clk = "mcasp_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_MCASP_CLKCTRL_OFFSET, @@ -1972,7 +1972,7 @@ static struct omap_hwmod omap44xx_mcbsp1_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_mcbsp1_irqs, .sdma_reqs = omap44xx_mcbsp1_sdma_reqs, - .main_clk = "func_mcbsp1_gfclk", + .main_clk = "mcbsp1_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET, @@ -2007,7 +2007,7 @@ static struct omap_hwmod omap44xx_mcbsp2_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_mcbsp2_irqs, .sdma_reqs = omap44xx_mcbsp2_sdma_reqs, - .main_clk = "func_mcbsp2_gfclk", + .main_clk = "mcbsp2_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET, @@ -2042,7 +2042,7 @@ static struct omap_hwmod omap44xx_mcbsp3_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_mcbsp3_irqs, .sdma_reqs = omap44xx_mcbsp3_sdma_reqs, - .main_clk = "func_mcbsp3_gfclk", + .main_clk = "mcbsp3_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET, @@ -2077,7 +2077,7 @@ static struct omap_hwmod omap44xx_mcbsp4_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcbsp4_irqs, .sdma_reqs = omap44xx_mcbsp4_sdma_reqs, - .main_clk = "per_mcbsp4_gfclk", + .main_clk = "mcbsp4_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET, @@ -2140,7 +2140,7 @@ static struct omap_hwmod omap44xx_mcpdm_hwmod = { .flags = HWMOD_EXT_OPT_MAIN_CLK | HWMOD_SWSUP_SIDLE, .mpu_irqs = omap44xx_mcpdm_irqs, .sdma_reqs = omap44xx_mcpdm_sdma_reqs, - .main_clk = "pad_clks_ck", + .main_clk = "mcpdm_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_PDM_CLKCTRL_OFFSET, @@ -2201,7 +2201,7 @@ static struct omap_hwmod omap44xx_mcspi1_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcspi1_irqs, .sdma_reqs = omap44xx_mcspi1_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "mcspi1_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET, @@ -2237,7 +2237,7 @@ static struct omap_hwmod omap44xx_mcspi2_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcspi2_irqs, .sdma_reqs = omap44xx_mcspi2_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "mcspi2_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET, @@ -2273,7 +2273,7 @@ static struct omap_hwmod omap44xx_mcspi3_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcspi3_irqs, .sdma_reqs = omap44xx_mcspi3_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "mcspi3_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET, @@ -2307,7 +2307,7 @@ static struct omap_hwmod omap44xx_mcspi4_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcspi4_irqs, .sdma_reqs = omap44xx_mcspi4_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "mcspi4_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET, @@ -2363,7 +2363,7 @@ static struct omap_hwmod omap44xx_mmc1_hwmod = { .clkdm_name = "l3_init_clkdm", .mpu_irqs = omap44xx_mmc1_irqs, .sdma_reqs = omap44xx_mmc1_sdma_reqs, - .main_clk = "hsmmc1_fclk", + .main_clk = "mmc1_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET, @@ -2392,7 +2392,7 @@ static struct omap_hwmod omap44xx_mmc2_hwmod = { .clkdm_name = "l3_init_clkdm", .mpu_irqs = omap44xx_mmc2_irqs, .sdma_reqs = omap44xx_mmc2_sdma_reqs, - .main_clk = "hsmmc2_fclk", + .main_clk = "mmc2_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET, @@ -2420,7 +2420,7 @@ static struct omap_hwmod omap44xx_mmc3_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mmc3_irqs, .sdma_reqs = omap44xx_mmc3_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "mmc3_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET, @@ -2448,7 +2448,7 @@ static struct omap_hwmod omap44xx_mmc4_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mmc4_irqs, .sdma_reqs = omap44xx_mmc4_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "mmc4_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET, @@ -2476,7 +2476,7 @@ static struct omap_hwmod omap44xx_mmc5_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mmc5_irqs, .sdma_reqs = omap44xx_mmc5_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "mmc5_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET, @@ -2725,7 +2725,7 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = { .name = "ocp2scp_usb_phy", .class = &omap44xx_ocp2scp_hwmod_class, .clkdm_name = "l3_init_clkdm", - .main_clk = "func_48m_fclk", + .main_clk = "ocp2scp_usb_phy_phy_48m", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET, @@ -3162,7 +3162,7 @@ static struct omap_hwmod omap44xx_timer1_hwmod = { .clkdm_name = "l4_wkup_clkdm", .flags = HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_timer1_irqs, - .main_clk = "dmt1_clk_mux", + .main_clk = "timer1_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_WKUP_TIMER1_CLKCTRL_OFFSET, @@ -3185,7 +3185,7 @@ static struct omap_hwmod omap44xx_timer2_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_timer2_irqs, - .main_clk = "cm2_dm2_mux", + .main_clk = "timer2_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER2_CLKCTRL_OFFSET, @@ -3206,7 +3206,7 @@ static struct omap_hwmod omap44xx_timer3_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_timer3_irqs, - .main_clk = "cm2_dm3_mux", + .main_clk = "timer3_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER3_CLKCTRL_OFFSET, @@ -3227,7 +3227,7 @@ static struct omap_hwmod omap44xx_timer4_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_timer4_irqs, - .main_clk = "cm2_dm4_mux", + .main_clk = "timer4_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER4_CLKCTRL_OFFSET, @@ -3248,7 +3248,7 @@ static struct omap_hwmod omap44xx_timer5_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_timer5_irqs, - .main_clk = "timer5_sync_mux", + .main_clk = "timer5_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_TIMER5_CLKCTRL_OFFSET, @@ -3270,7 +3270,8 @@ static struct omap_hwmod omap44xx_timer6_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_timer6_irqs, - .main_clk = "timer6_sync_mux", + + .main_clk = "timer6_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_TIMER6_CLKCTRL_OFFSET, @@ -3292,7 +3293,7 @@ static struct omap_hwmod omap44xx_timer7_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_timer7_irqs, - .main_clk = "timer7_sync_mux", + .main_clk = "timer7_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_TIMER7_CLKCTRL_OFFSET, @@ -3314,7 +3315,7 @@ static struct omap_hwmod omap44xx_timer8_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_timer8_irqs, - .main_clk = "timer8_sync_mux", + .main_clk = "timer8_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_TIMER8_CLKCTRL_OFFSET, @@ -3336,7 +3337,7 @@ static struct omap_hwmod omap44xx_timer9_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_timer9_irqs, - .main_clk = "cm2_dm9_mux", + .main_clk = "timer9_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER9_CLKCTRL_OFFSET, @@ -3359,7 +3360,7 @@ static struct omap_hwmod omap44xx_timer10_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_timer10_irqs, - .main_clk = "cm2_dm10_mux", + .main_clk = "timer10_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER10_CLKCTRL_OFFSET, @@ -3381,7 +3382,7 @@ static struct omap_hwmod omap44xx_timer11_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_timer11_irqs, - .main_clk = "cm2_dm11_mux", + .main_clk = "timer11_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER11_CLKCTRL_OFFSET, @@ -3432,7 +3433,7 @@ static struct omap_hwmod omap44xx_uart1_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_uart1_irqs, .sdma_reqs = omap44xx_uart1_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "uart1_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET, @@ -3460,7 +3461,7 @@ static struct omap_hwmod omap44xx_uart2_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_uart2_irqs, .sdma_reqs = omap44xx_uart2_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "uart2_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET, @@ -3489,7 +3490,7 @@ static struct omap_hwmod omap44xx_uart3_hwmod = { .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET, .mpu_irqs = omap44xx_uart3_irqs, .sdma_reqs = omap44xx_uart3_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "uart3_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET, @@ -3517,7 +3518,7 @@ static struct omap_hwmod omap44xx_uart4_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_uart4_irqs, .sdma_reqs = omap44xx_uart4_sdma_reqs, - .main_clk = "func_48m_fclk", + .main_clk = "uart4_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET, @@ -3796,7 +3797,7 @@ static struct omap_hwmod omap44xx_wd_timer2_hwmod = { .class = &omap44xx_wd_timer_hwmod_class, .clkdm_name = "l4_wkup_clkdm", .mpu_irqs = omap44xx_wd_timer2_irqs, - .main_clk = "sys_32k_ck", + .main_clk = "wd_timer2_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_WKUP_WDT2_CLKCTRL_OFFSET, @@ -3817,7 +3818,7 @@ static struct omap_hwmod omap44xx_wd_timer3_hwmod = { .class = &omap44xx_wd_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_wd_timer3_irqs, - .main_clk = "sys_32k_ck", + .main_clk = "wd_timer3_fck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET, diff --git a/trunk/arch/arm/mach-omap2/pm-debug.c b/trunk/arch/arm/mach-omap2/pm-debug.c index 6db89ae92389..e2c291f52f92 100644 --- a/trunk/arch/arm/mach-omap2/pm-debug.c +++ b/trunk/arch/arm/mach-omap2/pm-debug.c @@ -83,8 +83,10 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) strncmp(clkdm->name, "dpll", 4) == 0) return 0; - seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name, - clkdm->usecount); + seq_printf(s, "%s->%s (%d)", clkdm->name, + clkdm->pwrdm.ptr->name, + atomic_read(&clkdm->usecount)); + seq_printf(s, "\n"); return 0; } diff --git a/trunk/arch/arm/mach-omap2/pm.c b/trunk/arch/arm/mach-omap2/pm.c index 9a9be3c9f208..f4b3143a8b1d 100644 --- a/trunk/arch/arm/mach-omap2/pm.c +++ b/trunk/arch/arm/mach-omap2/pm.c @@ -32,6 +32,8 @@ #include "pm.h" #include "twl-common.h" +static struct omap_device_pm_latency *pm_lats; + /* * omap_pm_suspend: points to a function that does the SoC-specific * suspend work @@ -80,7 +82,7 @@ static int __init _init_omap_device(char *name) __func__, name)) return -ENODEV; - pdev = omap_device_build(oh->name, 0, oh, NULL, 0); + pdev = omap_device_build(oh->name, 0, oh, NULL, 0, pm_lats, 0, false); if (WARN(IS_ERR(pdev), "%s: could not build omap_device for %s\n", __func__, name)) return -ENODEV; @@ -106,18 +108,79 @@ static void __init omap2_init_processor_devices(void) } } +/* Types of sleep_switch used in omap_set_pwrdm_state */ +#define FORCEWAKEUP_SWITCH 0 +#define LOWPOWERSTATE_SWITCH 1 + int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused) { - /* XXX The usecount test is racy */ if ((clkdm->flags & CLKDM_CAN_ENABLE_AUTO) && !(clkdm->flags & CLKDM_MISSING_IDLE_REPORTING)) clkdm_allow_idle(clkdm); else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && - clkdm->usecount == 0) + atomic_read(&clkdm->usecount) == 0) clkdm_sleep(clkdm); return 0; } +/* + * This sets pwrdm state (other than mpu & core. Currently only ON & + * RET are supported. + */ +int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst) +{ + u8 curr_pwrst, next_pwrst; + int sleep_switch = -1, ret = 0, hwsup = 0; + + if (!pwrdm || IS_ERR(pwrdm)) + return -EINVAL; + + while (!(pwrdm->pwrsts & (1 << pwrst))) { + if (pwrst == PWRDM_POWER_OFF) + return ret; + pwrst--; + } + + next_pwrst = pwrdm_read_next_pwrst(pwrdm); + if (next_pwrst == pwrst) + return ret; + + curr_pwrst = pwrdm_read_pwrst(pwrdm); + if (curr_pwrst < PWRDM_POWER_ON) { + if ((curr_pwrst > pwrst) && + (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { + sleep_switch = LOWPOWERSTATE_SWITCH; + } else { + hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); + clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); + sleep_switch = FORCEWAKEUP_SWITCH; + } + } + + ret = pwrdm_set_next_pwrst(pwrdm, pwrst); + if (ret) + pr_err("%s: unable to set power state of powerdomain: %s\n", + __func__, pwrdm->name); + + switch (sleep_switch) { + case FORCEWAKEUP_SWITCH: + if (hwsup) + clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); + else + clkdm_sleep(pwrdm->pwrdm_clkdms[0]); + break; + case LOWPOWERSTATE_SWITCH: + pwrdm_set_lowpwrstchange(pwrdm); + pwrdm_wait_transition(pwrdm); + pwrdm_state_switch(pwrdm); + break; + } + + return ret; +} + + + /* * This API is to be called during init to set the various voltage * domains to the voltage as per the opp table. Typically we boot up diff --git a/trunk/arch/arm/mach-omap2/pm.h b/trunk/arch/arm/mach-omap2/pm.h index 7bdd22afce69..c22503b17abd 100644 --- a/trunk/arch/arm/mach-omap2/pm.h +++ b/trunk/arch/arm/mach-omap2/pm.h @@ -33,6 +33,7 @@ static inline int omap4_idle_init(void) extern void *omap3_secure_ram_storage; extern void omap3_pm_off_mode_enable(int); extern void omap_sram_idle(void); +extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state); extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused); extern int (*omap_pm_suspend)(void); diff --git a/trunk/arch/arm/mach-omap2/pm24xx.c b/trunk/arch/arm/mach-omap2/pm24xx.c index b2a4df623545..8914b9e32ee7 100644 --- a/trunk/arch/arm/mach-omap2/pm24xx.c +++ b/trunk/arch/arm/mach-omap2/pm24xx.c @@ -54,7 +54,6 @@ #include "powerdomain.h" #include "clockdomain.h" -static void (*omap2_sram_idle)(void); static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl, void __iomem *sdrc_power); @@ -90,7 +89,11 @@ static int omap2_enter_full_retention(void) omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); - pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET); + /* + * Set MPU powerdomain's next power state to RETENTION; + * preserve logic state during retention + */ + pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); /* Workaround to kill USB */ @@ -133,12 +136,17 @@ static int omap2_enter_full_retention(void) /* Mask future PRCM-to-MPU interrupts */ omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); - pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON); - return 0; } +static int omap2_i2c_active(void) +{ + u32 l; + + l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); + return l & (OMAP2420_EN_I2C2_MASK | OMAP2420_EN_I2C1_MASK); +} + static int sti_console_enabled; static int omap2_allow_mpu_retention(void) @@ -163,6 +171,13 @@ static int omap2_allow_mpu_retention(void) static void omap2_enter_mpu_retention(void) { + const int zero = 0; + + /* Putting MPU into the WFI state while a transfer is active + * seems to cause the I2C block to timeout. Why? Good question. */ + if (omap2_i2c_active()) + return; + /* The peripherals seem not to be able to wake up the MPU when * it is in retention mode. */ if (omap2_allow_mpu_retention()) { @@ -172,16 +187,18 @@ static void omap2_enter_mpu_retention(void) omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); /* Try to enter MPU retention */ - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); - + omap2_prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) | + OMAP_LOGICRETSTATE_MASK, + MPU_MOD, OMAP2_PM_PWSTCTRL); } else { /* Block MPU retention */ - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); - } - omap2_sram_idle(); + omap2_prm_write_mod_reg(OMAP_LOGICRETSTATE_MASK, MPU_MOD, + OMAP2_PM_PWSTCTRL); + } - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); + /* WFI */ + asm("mcr p15, 0, %0, c7, c0, 4" : : "r" (zero) : "memory", "cc"); } static int omap2_can_sleep(void) @@ -236,17 +253,25 @@ static void __init prcm_setup_regs(void) for (i = 0; i < num_mem_banks; i++) pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET); - pwrdm_set_logic_retst(core_pwrdm, PWRDM_POWER_RET); + /* Set CORE powerdomain's next power state to RETENTION */ + pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET); + /* + * Set MPU powerdomain's next power state to RETENTION; + * preserve logic state during retention + */ pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); + pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); /* Force-power down DSP, GFX powerdomains */ pwrdm = clkdm_get_pwrdm(dsp_clkdm); pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); + clkdm_sleep(dsp_clkdm); pwrdm = clkdm_get_pwrdm(gfx_clkdm); pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); + clkdm_sleep(gfx_clkdm); /* Enable hardware-supervised idle for all clkdms */ clkdm_for_each(omap_pm_clkdms_setup, NULL); @@ -333,11 +358,9 @@ int __init omap2_pm_init(void) /* * We copy the assembler sleep/wakeup routines to SRAM. * These routines need to be in SRAM as that's the only - * memory the MPU can see when it wakes up. + * memory the MPU can see when it wakes up after the entire + * chip enters idle. */ - omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, - omap24xx_idle_loop_suspend_sz); - omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, omap24xx_cpu_suspend_sz); diff --git a/trunk/arch/arm/mach-omap2/pmu.c b/trunk/arch/arm/mach-omap2/pmu.c index 0ef4d6aa758e..eb78ae7a3464 100644 --- a/trunk/arch/arm/mach-omap2/pmu.c +++ b/trunk/arch/arm/mach-omap2/pmu.c @@ -48,7 +48,8 @@ static int __init omap2_init_pmu(unsigned oh_num, char *oh_names[]) } } - omap_pmu_dev = omap_device_build_ss(dev_name, -1, oh, oh_num, NULL, 0); + omap_pmu_dev = omap_device_build_ss(dev_name, -1, oh, oh_num, NULL, 0, + NULL, 0, 0); WARN(IS_ERR(omap_pmu_dev), "Can't build omap_device for %s.\n", dev_name); diff --git a/trunk/arch/arm/mach-omap2/powerdomain.c b/trunk/arch/arm/mach-omap2/powerdomain.c index 8e61d80bf6b3..dea62a9aad07 100644 --- a/trunk/arch/arm/mach-omap2/powerdomain.c +++ b/trunk/arch/arm/mach-omap2/powerdomain.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "cm2xxx_3xxx.h" @@ -43,16 +42,6 @@ enum { PWRDM_STATE_PREV, }; -/* - * Types of sleep_switch used internally in omap_set_pwrdm_state() - * and its associated static functions - * - * XXX Better documentation is needed here - */ -#define ALREADYACTIVE_SWITCH 0 -#define FORCEWAKEUP_SWITCH 1 -#define LOWPOWERSTATE_SWITCH 2 -#define ERROR_SWITCH 3 /* pwrdm_list contains all registered struct powerdomains */ static LIST_HEAD(pwrdm_list); @@ -112,7 +101,6 @@ static int _pwrdm_register(struct powerdomain *pwrdm) pwrdm->voltdm.ptr = voltdm; INIT_LIST_HEAD(&pwrdm->voltdm_node); voltdm_add_pwrdm(voltdm, pwrdm); - spin_lock_init(&pwrdm->_lock); list_add(&pwrdm->node, &pwrdm_list); @@ -124,7 +112,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm) for (i = 0; i < pwrdm->banks; i++) pwrdm->ret_mem_off_counter[i] = 0; - arch_pwrdm->pwrdm_wait_transition(pwrdm); + pwrdm_wait_transition(pwrdm); pwrdm->state = pwrdm_read_pwrst(pwrdm); pwrdm->state_counter[pwrdm->state] = 1; @@ -155,7 +143,7 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm) static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) { - int prev, next, state, trace_state = 0; + int prev, state, trace_state = 0; if (pwrdm == NULL) return -EINVAL; @@ -176,10 +164,9 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) * If the power domain did not hit the desired state, * generate a trace event with both the desired and hit states */ - next = pwrdm_read_next_pwrst(pwrdm); - if (next != prev) { + if (state != prev) { trace_state = (PWRDM_TRACE_STATES_FLAG | - ((next & OMAP_POWERSTATE_MASK) << 8) | + ((state & OMAP_POWERSTATE_MASK) << 8) | ((prev & OMAP_POWERSTATE_MASK) << 0)); trace_power_domain_target(pwrdm->name, trace_state, smp_processor_id()); @@ -212,80 +199,6 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) return 0; } -/** - * _pwrdm_save_clkdm_state_and_activate - prepare for power state change - * @pwrdm: struct powerdomain * to operate on - * @curr_pwrst: current power state of @pwrdm - * @pwrst: power state to switch to - * @hwsup: ptr to a bool to return whether the clkdm is hardware-supervised - * - * Determine whether the powerdomain needs to be turned on before - * attempting to switch power states. Called by - * omap_set_pwrdm_state(). NOTE that if the powerdomain contains - * multiple clockdomains, this code assumes that the first clockdomain - * supports software-supervised wakeup mode - potentially a problem. - * Returns the power state switch mode currently in use (see the - * "Types of sleep_switch" comment above). - */ -static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm, - u8 curr_pwrst, u8 pwrst, - bool *hwsup) -{ - u8 sleep_switch; - - if (curr_pwrst < 0) { - WARN_ON(1); - sleep_switch = ERROR_SWITCH; - } else if (curr_pwrst < PWRDM_POWER_ON) { - if (curr_pwrst > pwrst && - pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && - arch_pwrdm->pwrdm_set_lowpwrstchange) { - sleep_switch = LOWPOWERSTATE_SWITCH; - } else { - *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); - clkdm_wakeup_nolock(pwrdm->pwrdm_clkdms[0]); - sleep_switch = FORCEWAKEUP_SWITCH; - } - } else { - sleep_switch = ALREADYACTIVE_SWITCH; - } - - return sleep_switch; -} - -/** - * _pwrdm_restore_clkdm_state - restore the clkdm hwsup state after pwrst change - * @pwrdm: struct powerdomain * to operate on - * @sleep_switch: return value from _pwrdm_save_clkdm_state_and_activate() - * @hwsup: should @pwrdm's first clockdomain be set to hardware-supervised mode? - * - * Restore the clockdomain state perturbed by - * _pwrdm_save_clkdm_state_and_activate(), and call the power state - * bookkeeping code. Called by omap_set_pwrdm_state(). NOTE that if - * the powerdomain contains multiple clockdomains, this assumes that - * the first associated clockdomain supports either - * hardware-supervised idle control in the register, or - * software-supervised sleep. No return value. - */ -static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm, - u8 sleep_switch, bool hwsup) -{ - switch (sleep_switch) { - case FORCEWAKEUP_SWITCH: - if (hwsup) - clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]); - else - clkdm_sleep_nolock(pwrdm->pwrdm_clkdms[0]); - break; - case LOWPOWERSTATE_SWITCH: - if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && - arch_pwrdm->pwrdm_set_lowpwrstchange) - arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); - pwrdm_state_switch_nolock(pwrdm); - break; - } -} - /* Public functions */ /** @@ -361,30 +274,6 @@ int pwrdm_complete_init(void) return 0; } -/** - * pwrdm_lock - acquire a Linux spinlock on a powerdomain - * @pwrdm: struct powerdomain * to lock - * - * Acquire the powerdomain spinlock on @pwrdm. No return value. - */ -void pwrdm_lock(struct powerdomain *pwrdm) - __acquires(&pwrdm->_lock) -{ - spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags); -} - -/** - * pwrdm_unlock - release a Linux spinlock on a powerdomain - * @pwrdm: struct powerdomain * to unlock - * - * Release the powerdomain spinlock on @pwrdm. No return value. - */ -void pwrdm_unlock(struct powerdomain *pwrdm) - __releases(&pwrdm->_lock) -{ - spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags); -} - /** * pwrdm_lookup - look up a powerdomain by name, return a pointer * @name: name of powerdomain @@ -1031,27 +920,65 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm) return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0; } -int pwrdm_state_switch_nolock(struct powerdomain *pwrdm) +/** + * pwrdm_set_lowpwrstchange - Request a low power state change + * @pwrdm: struct powerdomain * + * + * Allows a powerdomain to transtion to a lower power sleep state + * from an existing sleep state without waking up the powerdomain. + * Returns -EINVAL if the powerdomain pointer is null or if the + * powerdomain does not support LOWPOWERSTATECHANGE, or returns 0 + * upon success. + */ +int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) { - int ret; + int ret = -EINVAL; + + if (!pwrdm) + return -EINVAL; - if (!pwrdm || !arch_pwrdm) + if (!(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) return -EINVAL; - ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); - if (!ret) - ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); + pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n", + pwrdm->name); + + if (arch_pwrdm && arch_pwrdm->pwrdm_set_lowpwrstchange) + ret = arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); + + return ret; +} + +/** + * pwrdm_wait_transition - wait for powerdomain power transition to finish + * @pwrdm: struct powerdomain * to wait for + * + * If the powerdomain @pwrdm is in the process of a state transition, + * spin until it completes the power transition, or until an iteration + * bailout value is reached. Returns -EINVAL if the powerdomain + * pointer is null, -EAGAIN if the bailout value was reached, or + * returns 0 upon success. + */ +int pwrdm_wait_transition(struct powerdomain *pwrdm) +{ + int ret = -EINVAL; + + if (!pwrdm) + return -EINVAL; + + if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition) + ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); return ret; } -int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm) +int pwrdm_state_switch(struct powerdomain *pwrdm) { int ret; - pwrdm_lock(pwrdm); - ret = pwrdm_state_switch_nolock(pwrdm); - pwrdm_unlock(pwrdm); + ret = pwrdm_wait_transition(pwrdm); + if (!ret) + ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); return ret; } @@ -1076,61 +1003,6 @@ int pwrdm_post_transition(struct powerdomain *pwrdm) return 0; } -/** - * omap_set_pwrdm_state - change a powerdomain's current power state - * @pwrdm: struct powerdomain * to change the power state of - * @pwrst: power state to change to - * - * Change the current hardware power state of the powerdomain - * represented by @pwrdm to the power state represented by @pwrst. - * Returns -EINVAL if @pwrdm is null or invalid or if the - * powerdomain's current power state could not be read, or returns 0 - * upon success or if @pwrdm does not support @pwrst or any - * lower-power state. XXX Should not return 0 if the @pwrdm does not - * support @pwrst or any lower-power state: this should be an error. - */ -int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst) -{ - u8 curr_pwrst, next_pwrst, sleep_switch; - int ret = 0; - bool hwsup = false; - - if (!pwrdm || IS_ERR(pwrdm)) - return -EINVAL; - - while (!(pwrdm->pwrsts & (1 << pwrst))) { - if (pwrst == PWRDM_POWER_OFF) - return ret; - pwrst--; - } - - pwrdm_lock(pwrdm); - - curr_pwrst = pwrdm_read_pwrst(pwrdm); - next_pwrst = pwrdm_read_next_pwrst(pwrdm); - if (curr_pwrst == pwrst && next_pwrst == pwrst) - goto osps_out; - - sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst, - pwrst, &hwsup); - if (sleep_switch == ERROR_SWITCH) { - ret = -EINVAL; - goto osps_out; - } - - ret = pwrdm_set_next_pwrst(pwrdm, pwrst); - if (ret) - pr_err("%s: unable to set power state of powerdomain: %s\n", - __func__, pwrdm->name); - - _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup); - -osps_out: - pwrdm_unlock(pwrdm); - - return ret; -} - /** * pwrdm_get_context_loss_count - get powerdomain's context loss count * @pwrdm: struct powerdomain * to wait for diff --git a/trunk/arch/arm/mach-omap2/powerdomain.h b/trunk/arch/arm/mach-omap2/powerdomain.h index 140c36074fed..5277d56eb37f 100644 --- a/trunk/arch/arm/mach-omap2/powerdomain.h +++ b/trunk/arch/arm/mach-omap2/powerdomain.h @@ -19,7 +19,8 @@ #include #include -#include + +#include #include "voltage.h" @@ -43,20 +44,18 @@ #define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON) -/* - * Powerdomain flags (struct powerdomain.flags) - * - * PWRDM_HAS_HDWR_SAR - powerdomain has hardware save-and-restore support - * - * PWRDM_HAS_MPU_QUIRK - MPU pwr domain has MEM bank 0 bits in MEM - * bank 1 position. This is true for OMAP3430 - * - * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state - * to a lower sleep state without waking up the powerdomain - */ -#define PWRDM_HAS_HDWR_SAR BIT(0) -#define PWRDM_HAS_MPU_QUIRK BIT(1) -#define PWRDM_HAS_LOWPOWERSTATECHANGE BIT(2) +/* Powerdomain flags */ +#define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */ +#define PWRDM_HAS_MPU_QUIRK (1 << 1) /* MPU pwr domain has MEM bank 0 bits + * in MEM bank 1 position. This is + * true for OMAP3430 + */ +#define PWRDM_HAS_LOWPOWERSTATECHANGE (1 << 2) /* + * support to transition from a + * sleep state to a lower sleep + * state without waking up the + * powerdomain + */ /* * Number of memory banks that are power-controllable. On OMAP4430, the @@ -104,8 +103,6 @@ struct powerdomain; * @state_counter: * @timer: * @state_timer: - * @_lock: spinlock used to serialize powerdomain and some clockdomain ops - * @_lock_flags: stored flags when @_lock is taken * * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. */ @@ -130,8 +127,7 @@ struct powerdomain { unsigned state_counter[PWRDM_MAX_PWRSTS]; unsigned ret_logic_off_counter; unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; - spinlock_t _lock; - unsigned long _lock_flags; + const u8 pwrstctrl_offs; const u8 pwrstst_offs; const u32 logicretstate_mask; @@ -166,16 +162,6 @@ struct powerdomain { * @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd * @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep * @pwrdm_wait_transition: Wait for a pd state transition to complete - * - * Regarding @pwrdm_set_lowpwrstchange: On the OMAP2 and 3-family - * chips, a powerdomain's power state is not allowed to directly - * transition from one low-power state (e.g., CSWR) to another - * low-power state (e.g., OFF) without first waking up the - * powerdomain. This wastes energy. So OMAP4 chips support the - * ability to transition a powerdomain power state directly from one - * low-power state to another. The function pointed to by - * @pwrdm_set_lowpwrstchange is intended to configure the OMAP4 - * hardware powerdomain state machine to enable this feature. */ struct pwrdm_ops { int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst); @@ -239,15 +225,15 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm); int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); -int pwrdm_state_switch_nolock(struct powerdomain *pwrdm); +int pwrdm_wait_transition(struct powerdomain *pwrdm); + int pwrdm_state_switch(struct powerdomain *pwrdm); int pwrdm_pre_transition(struct powerdomain *pwrdm); int pwrdm_post_transition(struct powerdomain *pwrdm); +int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); -extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state); - extern void omap242x_powerdomains_init(void); extern void omap243x_powerdomains_init(void); extern void omap3xxx_powerdomains_init(void); @@ -267,7 +253,5 @@ extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank); extern struct powerdomain wkup_omap2_pwrdm; extern struct powerdomain gfx_omap2_pwrdm; -extern void pwrdm_lock(struct powerdomain *pwrdm); -extern void pwrdm_unlock(struct powerdomain *pwrdm); #endif diff --git a/trunk/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c b/trunk/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c index 7b946f1005b1..d3a5399091ad 100644 --- a/trunk/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c +++ b/trunk/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c @@ -54,12 +54,12 @@ struct powerdomain gfx_omap2_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; struct powerdomain wkup_omap2_pwrdm = { .name = "wkup_pwrdm", .prcm_offs = WKUP_MOD, .pwrsts = PWRSTS_ON, - .voltdm = { .name = "wakeup" }, + .voltdm = { .name = "wakeup" }, }; diff --git a/trunk/arch/arm/mach-omap2/powerdomains2xxx_data.c b/trunk/arch/arm/mach-omap2/powerdomains2xxx_data.c index 578eef86fcf2..ba520d4f7c7b 100644 --- a/trunk/arch/arm/mach-omap2/powerdomains2xxx_data.c +++ b/trunk/arch/arm/mach-omap2/powerdomains2xxx_data.c @@ -38,7 +38,7 @@ static struct powerdomain dsp_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain mpu_24xx_pwrdm = { @@ -53,14 +53,13 @@ static struct powerdomain mpu_24xx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain core_24xx_pwrdm = { .name = "core_pwrdm", .prcm_offs = CORE_MOD, .pwrsts = PWRSTS_OFF_RET_ON, - .pwrsts_logic_ret = PWRSTS_RET, .banks = 3, .pwrsts_mem_ret = { [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */ @@ -72,7 +71,7 @@ static struct powerdomain core_24xx_pwrdm = { [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; @@ -94,7 +93,7 @@ static struct powerdomain mdm_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; /* diff --git a/trunk/arch/arm/mach-omap2/powerdomains3xxx_data.c b/trunk/arch/arm/mach-omap2/powerdomains3xxx_data.c index f0e14e9efe5a..8b23d234fb55 100644 --- a/trunk/arch/arm/mach-omap2/powerdomains3xxx_data.c +++ b/trunk/arch/arm/mach-omap2/powerdomains3xxx_data.c @@ -50,7 +50,7 @@ static struct powerdomain iva2_pwrdm = { [2] = PWRSTS_OFF_ON, [3] = PWRSTS_ON, }, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain mpu_3xxx_pwrdm = { @@ -66,7 +66,7 @@ static struct powerdomain mpu_3xxx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_OFF_ON, }, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain mpu_am35x_pwrdm = { @@ -82,7 +82,7 @@ static struct powerdomain mpu_am35x_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, }, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; /* @@ -109,7 +109,7 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = { [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain core_3xxx_es3_1_pwrdm = { @@ -131,7 +131,7 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = { [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain core_am35x_pwrdm = { @@ -148,7 +148,7 @@ static struct powerdomain core_am35x_pwrdm = { [0] = PWRSTS_ON, /* MEM1ONSTATE */ [1] = PWRSTS_ON, /* MEM2ONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dss_pwrdm = { @@ -163,7 +163,7 @@ static struct powerdomain dss_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dss_am35x_pwrdm = { @@ -178,7 +178,7 @@ static struct powerdomain dss_am35x_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; /* @@ -199,7 +199,7 @@ static struct powerdomain sgx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain sgx_am35x_pwrdm = { @@ -214,7 +214,7 @@ static struct powerdomain sgx_am35x_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain cam_pwrdm = { @@ -229,7 +229,7 @@ static struct powerdomain cam_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain per_pwrdm = { @@ -244,7 +244,7 @@ static struct powerdomain per_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain per_am35x_pwrdm = { @@ -259,13 +259,13 @@ static struct powerdomain per_am35x_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain emu_pwrdm = { .name = "emu_pwrdm", .prcm_offs = OMAP3430_EMU_MOD, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain neon_pwrdm = { @@ -273,7 +273,7 @@ static struct powerdomain neon_pwrdm = { .prcm_offs = OMAP3430_NEON_MOD, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_RET, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain neon_am35x_pwrdm = { @@ -281,7 +281,7 @@ static struct powerdomain neon_am35x_pwrdm = { .prcm_offs = OMAP3430_NEON_MOD, .pwrsts = PWRSTS_ON, .pwrsts_logic_ret = PWRSTS_ON, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain usbhost_pwrdm = { @@ -303,37 +303,37 @@ static struct powerdomain usbhost_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dpll1_pwrdm = { .name = "dpll1_pwrdm", .prcm_offs = MPU_MOD, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain dpll2_pwrdm = { .name = "dpll2_pwrdm", .prcm_offs = OMAP3430_IVA2_MOD, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain dpll3_pwrdm = { .name = "dpll3_pwrdm", .prcm_offs = PLL_MOD, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dpll4_pwrdm = { .name = "dpll4_pwrdm", .prcm_offs = PLL_MOD, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dpll5_pwrdm = { .name = "dpll5_pwrdm", .prcm_offs = PLL_MOD, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; /* As powerdomains are added or removed above, this list must also be changed */ diff --git a/trunk/arch/arm/mach-omap2/prm2xxx_3xxx.c b/trunk/arch/arm/mach-omap2/prm2xxx_3xxx.c index 947f6adfed0c..a3e121f94a86 100644 --- a/trunk/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/trunk/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -210,7 +210,6 @@ int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1, PM_WKDEP, (1 << clkdm2->dep_bit)); } -/* XXX Caller must hold the clkdm's powerdomain lock */ int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) { struct clkdm_dep *cd; @@ -222,7 +221,7 @@ int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) /* PRM accesses are slow, so minimize them */ mask |= 1 << cd->clkdm->dep_bit; - cd->wkdep_usecount = 0; + atomic_set(&cd->wkdep_usecount, 0); } omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, diff --git a/trunk/arch/arm/mach-omap2/serial.c b/trunk/arch/arm/mach-omap2/serial.c index d01c373cbbef..04fdbc4c499b 100644 --- a/trunk/arch/arm/mach-omap2/serial.c +++ b/trunk/arch/arm/mach-omap2/serial.c @@ -316,7 +316,8 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, if (WARN_ON(!oh)) return; - pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size); + pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size, + NULL, 0, false); if (IS_ERR(pdev)) { WARN(1, "Could not build omap_device for %s: %s.\n", name, oh->name); diff --git a/trunk/arch/arm/mach-omap2/sleep24xx.S b/trunk/arch/arm/mach-omap2/sleep24xx.S index ce0ccd26efbd..1d3cb25c9629 100644 --- a/trunk/arch/arm/mach-omap2/sleep24xx.S +++ b/trunk/arch/arm/mach-omap2/sleep24xx.S @@ -36,25 +36,6 @@ .text -/* - * Forces OMAP into idle state - * - * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI - * for normal idles. - * - * Note: This code get's copied to internal SRAM at boot. When the OMAP - * wakes up it continues execution at the point it went to sleep. - */ - .align 3 -ENTRY(omap24xx_idle_loop_suspend) - stmfd sp!, {r0, lr} @ save registers on stack - mov r0, #0 @ clear for mcr setup - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt - ldmfd sp!, {r0, pc} @ restore regs and return - -ENTRY(omap24xx_idle_loop_suspend_sz) - .word . - omap24xx_idle_loop_suspend - /* * omap24xx_cpu_suspend() - Forces OMAP into deep sleep state by completing * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore diff --git a/trunk/arch/arm/mach-omap2/sr_device.c b/trunk/arch/arm/mach-omap2/sr_device.c index bb829e065400..b9753fe27232 100644 --- a/trunk/arch/arm/mach-omap2/sr_device.c +++ b/trunk/arch/arm/mach-omap2/sr_device.c @@ -152,7 +152,8 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user) sr_data->enable_on_init = sr_enable_on_init; - pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data), 0); + pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data), + NULL, 0, 0); if (IS_ERR(pdev)) pr_warning("%s: Could not build omap_device for %s: %s.\n\n", __func__, name, oh->name); diff --git a/trunk/arch/arm/mach-omap2/timer.c b/trunk/arch/arm/mach-omap2/timer.c index 63e5fb017fd8..b8ad6e632bb8 100644 --- a/trunk/arch/arm/mach-omap2/timer.c +++ b/trunk/arch/arm/mach-omap2/timer.c @@ -702,7 +702,8 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) pdata->timer_errata = omap_dm_timer_get_errata(); pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; - pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata)); + pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata), + NULL, 0, 0); if (IS_ERR(pdev)) { pr_err("%s: Can't build omap_device for %s: %s.\n", diff --git a/trunk/arch/arm/mach-omap2/usb-host.c b/trunk/arch/arm/mach-omap2/usb-host.c index 99f04deb4c7f..2e44e8a22884 100644 --- a/trunk/arch/arm/mach-omap2/usb-host.c +++ b/trunk/arch/arm/mach-omap2/usb-host.c @@ -42,6 +42,14 @@ static struct usbtll_omap_platform_data usbtll_data; static struct ehci_hcd_omap_platform_data ehci_data; static struct ohci_hcd_omap_platform_data ohci_data; +static struct omap_device_pm_latency omap_uhhtll_latency[] = { + { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + /* MUX settings for EHCI pins */ /* * setup_ehci_io_mux - initialize IO pad mux for USBHOST @@ -522,7 +530,9 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) } pdev = omap_device_build(OMAP_USBTLL_DEVICE, bus_id, tll_hwm, - &usbtll_data, sizeof(usbtll_data)); + &usbtll_data, sizeof(usbtll_data), + omap_uhhtll_latency, + ARRAY_SIZE(omap_uhhtll_latency), false); if (IS_ERR(pdev)) { pr_err("Could not build hwmod device %s\n", USBHS_TLL_HWMODNAME); @@ -530,7 +540,9 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) } pdev = omap_device_build(OMAP_USBHS_DEVICE, bus_id, uhh_hwm, - &usbhs_data, sizeof(usbhs_data)); + &usbhs_data, sizeof(usbhs_data), + omap_uhhtll_latency, + ARRAY_SIZE(omap_uhhtll_latency), false); if (IS_ERR(pdev)) { pr_err("Could not build hwmod devices %s\n", USBHS_UHH_HWMODNAME); diff --git a/trunk/arch/arm/mach-omap2/usb-musb.c b/trunk/arch/arm/mach-omap2/usb-musb.c index 8c4de2708cf2..7b33b375fe77 100644 --- a/trunk/arch/arm/mach-omap2/usb-musb.c +++ b/trunk/arch/arm/mach-omap2/usb-musb.c @@ -102,7 +102,7 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data) return; pdev = omap_device_build(name, bus_id, oh, &musb_plat, - sizeof(musb_plat)); + sizeof(musb_plat), NULL, 0, false); if (IS_ERR(pdev)) { pr_err("Could not build omap_device for %s %s\n", name, oh_name); diff --git a/trunk/arch/arm/mach-omap2/wd_timer.c b/trunk/arch/arm/mach-omap2/wd_timer.c index 910243f54a05..7c2b4ed38f02 100644 --- a/trunk/arch/arm/mach-omap2/wd_timer.c +++ b/trunk/arch/arm/mach-omap2/wd_timer.c @@ -124,7 +124,8 @@ static int __init omap_init_wdt(void) pdata.read_reset_sources = prm_read_reset_sources; pdev = omap_device_build(dev_name, id, oh, &pdata, - sizeof(struct omap_wd_timer_platform_data)); + sizeof(struct omap_wd_timer_platform_data), + NULL, 0, 0); WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s.\n", dev_name, oh->name); return 0;