diff options
author | Rajendra Nayak <rnayak@ti.com> | 2011-06-20 18:44:14 +0530 |
---|---|---|
committer | Nishanth Menon <nm@ti.com> | 2011-06-21 19:35:03 -0500 |
commit | 2a5d74c4a4f21babff12ae800c044f4cb7ad6ad8 (patch) | |
tree | 6b9cadb17fb625092e495665f3d72ab4d530bb42 /arch/arm/mach-omap2/clock44xx_data.c | |
parent | c47435d66cdc612f489cd8e0b613543bea722f86 (diff) | |
download | kernel_samsung_tuna-2a5d74c4a4f21babff12ae800c044f4cb7ad6ad8.zip kernel_samsung_tuna-2a5d74c4a4f21babff12ae800c044f4cb7ad6ad8.tar.gz kernel_samsung_tuna-2a5d74c4a4f21babff12ae800c044f4cb7ad6ad8.tar.bz2 |
OMAP4: clock: Define a virtual clock node to do l3 scaling
Scaling L3 as part of DVFS on OMAP4 involves multiple CORE DPLL
post dividers to be changed, and some in PER DPLL as well.
Hide all these from the DVFS/OPP layer by creating a
virtual clock node to handle all this internally as part
of the clock framework.
Also update the OMAP4 OPP table with the name of the virtual
clock.
Acked-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/clock44xx_data.c')
-rw-r--r-- | arch/arm/mach-omap2/clock44xx_data.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 85c551c..d332e7b 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -42,6 +42,10 @@ #define OMAP4430_MODULEMODE_HWCTRL 0 #define OMAP4430_MODULEMODE_SWCTRL 1 +static int omap4_virt_l3_set_rate(struct clk *clk, unsigned long rate); +static long omap4_virt_l3_round_rate(struct clk *clk, unsigned long rate); +static unsigned long omap4_virt_l3_recalc(struct clk *clk); + /* Root clocks */ static struct clk extalt_clkin_ck = { @@ -524,6 +528,15 @@ static struct clk dpll_core_m5x2_ck = { .set_rate = &omap2_clksel_set_rate, }; +static struct clk virt_l3_ck = { + .name = "virt_l3_ck", + .parent = &dpll_core_m5x2_ck, + .ops = &clkops_null, + .set_rate = &omap4_virt_l3_set_rate, + .recalc = &omap4_virt_l3_recalc, + .round_rate = &omap4_virt_l3_round_rate, +}; + static const struct clksel div_core_div[] = { { .parent = &dpll_core_m5x2_ck, .rates = div2_1to2_rates }, { .parent = NULL }, @@ -3208,6 +3221,7 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "dpll_core_m2_ck", &dpll_core_m2_ck, CK_44XX), CLK(NULL, "ddrphy_ck", &ddrphy_ck, CK_44XX), CLK(NULL, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, CK_44XX), + CLK(NULL, "virt_l3_ck", &virt_l3_ck, CK_44XX), CLK(NULL, "div_core_ck", &div_core_ck, CK_44XX), CLK(NULL, "div_iva_hs_clk", &div_iva_hs_clk, CK_44XX), CLK(NULL, "div_mpu_hs_clk", &div_mpu_hs_clk, CK_44XX), @@ -3452,6 +3466,106 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "smp_twd", &smp_twd, CK_44XX), }; +#define L3_OPP50_RATE 100000000 +#define DPLL_CORE_M3_OPP50_RATE 200000000 +#define DPLL_CORE_M3_OPP100_RATE 320000000 +#define DPLL_CORE_M6_OPP50_RATE 200000000 +#define DPLL_CORE_M6_OPP100_RATE 266600000 +#define DPLL_CORE_M7_OPP50_RATE 133333333 +#define DPLL_CORE_M7_OPP100_RATE 266666666 +#define DPLL_PER_M3_OPP50_RATE 192000000 +#define DPLL_PER_M3_OPP100_RATE 256000000 +#define DPLL_PER_M6_OPP50_RATE 192000000 +#define DPLL_PER_M6_OPP100_RATE 384000000 + +static long omap4_virt_l3_round_rate(struct clk *clk, unsigned long rate) +{ + long parent_rate; + + if (!clk || !clk->parent) + return 0; + + if (clk->parent->round_rate) { + parent_rate = clk->parent->round_rate(clk, rate * 2); + if (parent_rate) + return parent_rate / 2; + } + return 0; +} + +static unsigned long omap4_virt_l3_recalc(struct clk *clk) +{ + if (!clk || !clk->parent) + return 0; + + return clk->parent->rate / 2; +} + +static int omap4_clksel_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EINVAL; + + if (!clk->set_rate || !clk->round_rate) + return ret; + + rate = clk->round_rate(clk, rate); + if (rate) { + ret = clk->set_rate(clk, rate); + if (!ret) + propagate_rate(clk); + } + return ret; +} + +struct virt_l3_ck_deps { + unsigned long core_m3_rate; + unsigned long core_m6_rate; + unsigned long core_m7_rate; + unsigned long per_m3_rate; + unsigned long per_m6_rate; +}; + +#define NO_OF_L3_OPPS 2 +#define L3_OPP_50_INDEX 0 +#define L3_OPP_100_INDEX 1 + +static struct virt_l3_ck_deps omap4_virt_l3_clk_deps[NO_OF_L3_OPPS] = { + { /* OPP 50 */ + .core_m3_rate = DPLL_CORE_M3_OPP50_RATE, + .core_m6_rate = DPLL_CORE_M6_OPP50_RATE, + .core_m7_rate = DPLL_CORE_M7_OPP50_RATE, + .per_m3_rate = DPLL_PER_M3_OPP50_RATE, + .per_m6_rate = DPLL_PER_M6_OPP50_RATE, + }, + { /* OPP 100 */ + .core_m3_rate = DPLL_CORE_M3_OPP100_RATE, + .core_m6_rate = DPLL_CORE_M3_OPP100_RATE, + .core_m7_rate = DPLL_CORE_M7_OPP100_RATE, + .per_m3_rate = DPLL_PER_M3_OPP100_RATE, + .per_m6_rate = DPLL_PER_M6_OPP100_RATE, + }, +}; + +static int omap4_virt_l3_set_rate(struct clk *clk, unsigned long rate) +{ + struct virt_l3_ck_deps *l3_deps; + + if (rate <= L3_OPP50_RATE) + l3_deps = &omap4_virt_l3_clk_deps[L3_OPP_50_INDEX]; + else + l3_deps = &omap4_virt_l3_clk_deps[L3_OPP_100_INDEX]; + + omap4_clksel_set_rate(&dpll_core_m3x2_ck, l3_deps->core_m3_rate); + omap4_clksel_set_rate(&dpll_core_m6x2_ck, l3_deps->core_m6_rate); + omap4_clksel_set_rate(&dpll_core_m7x2_ck, l3_deps->core_m7_rate); + omap4_clksel_set_rate(&dpll_per_m3x2_ck, l3_deps->per_m3_rate); + omap4_clksel_set_rate(&dpll_per_m6x2_ck, l3_deps->per_m6_rate); + omap4_clksel_set_rate(&dpll_core_m5x2_ck, rate * 2); + + clk->rate = rate; + return 0; +} + int __init omap4xxx_clk_init(void) { struct omap_clk *c; |