diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2016-11-02 22:33:06 +0100 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2016-11-04 21:25:03 +0100 |
commit | 9fe69429509858d9db6ae123c4cb078351ec2623 (patch) | |
tree | 679a8a1b46ecbe049017a3a749d9c560312e8d9e /drivers/clk/pxa/clk-pxa27x.c | |
parent | clk: qcom: Add freq tables for a few rcgs (diff) | |
download | linux-9fe69429509858d9db6ae123c4cb078351ec2623.tar.xz linux-9fe69429509858d9db6ae123c4cb078351ec2623.zip |
clk: pxa: transfer CPU clock setting from pxa2xx-cpufreq
This is the initial stage to transfer the pxa25x and pxa27x CPU clocks
handling from cpufreq to the clock API. More precisely, the clocks
transferred are :
- cpll : core pll, known also as the CPU core turbo frequency
- core : core, known also as the CPU actual frequency, being either the
CPU core turbo frequency or the CPU core run frequency
This transfer is a prequel to shrink the code in pxa2xx-cpufreq.c, so
that it can become, at least in devicetree builds, the casual cpufreq-dt
driver.
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to '')
-rw-r--r-- | drivers/clk/pxa/clk-pxa27x.c | 144 |
1 files changed, 123 insertions, 21 deletions
diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c index 9fb40e884999..25a30194d27a 100644 --- a/drivers/clk/pxa/clk-pxa27x.c +++ b/drivers/clk/pxa/clk-pxa27x.c @@ -17,6 +17,8 @@ #include <linux/clkdev.h> #include <linux/of.h> +#include <mach/smemc.h> + #include <dt-bindings/clock/pxa-clock.h> #include "clk-pxa.h" @@ -45,11 +47,52 @@ enum { PXA_MEM_RUN, }; +#define PXA27x_CLKCFG(B, HT, T) \ + (CLKCFG_FCS | \ + ((B) ? CLKCFG_FASTBUS : 0) | \ + ((HT) ? CLKCFG_HALFTURBO : 0) | \ + ((T) ? CLKCFG_TURBO : 0)) +#define PXA27x_CCCR(A, L, N2) (A << 25 | N2 << 7 | L) + +#define MDCNFG_DRAC2(mdcnfg) (((mdcnfg) >> 21) & 0x3) +#define MDCNFG_DRAC0(mdcnfg) (((mdcnfg) >> 5) & 0x3) + +/* Define the refresh period in mSec for the SDRAM and the number of rows */ +#define SDRAM_TREF 64 /* standard 64ms SDRAM */ + static const char * const get_freq_khz[] = { "core", "run", "cpll", "memory", "system_bus" }; +static int get_sdram_rows(void) +{ + static int sdram_rows; + unsigned int drac2 = 0, drac0 = 0; + u32 mdcnfg; + + if (sdram_rows) + return sdram_rows; + + mdcnfg = readl_relaxed(MDCNFG); + + if (mdcnfg & (MDCNFG_DE2 | MDCNFG_DE3)) + drac2 = MDCNFG_DRAC2(mdcnfg); + + if (mdcnfg & (MDCNFG_DE0 | MDCNFG_DE1)) + drac0 = MDCNFG_DRAC0(mdcnfg); + + sdram_rows = 1 << (11 + max(drac0, drac2)); + return sdram_rows; +} + +static u32 mdrefr_dri(unsigned int freq_khz) +{ + u32 interval = freq_khz * SDRAM_TREF / get_sdram_rows(); + + return (interval - 31) / 32; +} + /* * Get the clock frequency as reflected by CCSR and the turbo flag. * We assume these values have been applied via a fcs. @@ -145,6 +188,42 @@ static struct desc_clk_cken pxa27x_clocks[] __initdata = { }; +/* + * PXA270 definitions + * + * For the PXA27x: + * Control variables are A, L, 2N for CCCR; B, HT, T for CLKCFG. + * + * A = 0 => memory controller clock from table 3-7, + * A = 1 => memory controller clock = system bus clock + * Run mode frequency = 13 MHz * L + * Turbo mode frequency = 13 MHz * L * N + * System bus frequency = 13 MHz * L / (B + 1) + * + * In CCCR: + * A = 1 + * L = 16 oscillator to run mode ratio + * 2N = 6 2 * (turbo mode to run mode ratio) + * + * In CCLKCFG: + * B = 1 Fast bus mode + * HT = 0 Half-Turbo mode + * T = 1 Turbo mode + * + * For now, just support some of the combinations in table 3-7 of + * PXA27x Processor Family Developer's Manual to simplify frequency + * change sequences. + */ +static struct pxa2xx_freq pxa27x_freqs[] = { + {104000000, 104000, PXA27x_CCCR(1, 8, 2), 0, PXA27x_CLKCFG(1, 0, 1) }, + {156000000, 104000, PXA27x_CCCR(1, 8, 3), 0, PXA27x_CLKCFG(1, 0, 1) }, + {208000000, 208000, PXA27x_CCCR(0, 16, 2), 1, PXA27x_CLKCFG(0, 0, 1) }, + {312000000, 208000, PXA27x_CCCR(1, 16, 3), 1, PXA27x_CLKCFG(1, 0, 1) }, + {416000000, 208000, PXA27x_CCCR(1, 16, 4), 1, PXA27x_CLKCFG(1, 0, 1) }, + {520000000, 208000, PXA27x_CCCR(1, 16, 5), 1, PXA27x_CLKCFG(1, 0, 1) }, + {624000000, 208000, PXA27x_CCCR(1, 16, 6), 1, PXA27x_CLKCFG(1, 0, 1) }, +}; + static unsigned long clk_pxa27x_cpll_get_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -164,8 +243,33 @@ static unsigned long clk_pxa27x_cpll_get_rate(struct clk_hw *hw, return N; } + +static int clk_pxa27x_cpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return pxa2xx_determine_rate(req, pxa27x_freqs, + ARRAY_SIZE(pxa27x_freqs)); +} + +static int clk_pxa27x_cpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int i; + + pr_debug("%s(rate=%lu parent_rate=%lu)\n", __func__, rate, parent_rate); + for (i = 0; i < ARRAY_SIZE(pxa27x_freqs); i++) + if (pxa27x_freqs[i].cpll == rate) + break; + + if (i >= ARRAY_SIZE(pxa27x_freqs)) + return -EINVAL; + + pxa2xx_cpll_change(&pxa27x_freqs[i], mdrefr_dri, MDREFR, CCCR); + return 0; +} + PARENTS(clk_pxa27x_cpll) = { "osc_13mhz" }; -RATE_RO_OPS(clk_pxa27x_cpll, "cpll"); +RATE_OPS(clk_pxa27x_cpll, "cpll"); static unsigned long clk_pxa27x_lcd_base_get_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -217,25 +321,6 @@ static void __init pxa27x_register_plls(void) clk_register_fixed_factor(NULL, "ppll_312mhz", "osc_13mhz", 0, 24, 1); } -static unsigned long clk_pxa27x_core_get_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - unsigned long clkcfg; - unsigned int ht, osc_forced; - unsigned long ccsr = readl(CCSR); - - osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); - asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); - ht = clkcfg & (1 << 2); - - if (osc_forced) - return parent_rate; - if (ht) - return parent_rate / 2; - else - return parent_rate; -} - static u8 clk_pxa27x_core_get_parent(struct clk_hw *hw) { unsigned long clkcfg; @@ -254,8 +339,25 @@ static u8 clk_pxa27x_core_get_parent(struct clk_hw *hw) return PXA_CORE_TURBO; return PXA_CORE_RUN; } + +static int clk_pxa27x_core_set_parent(struct clk_hw *hw, u8 index) +{ + if (index > PXA_CORE_TURBO) + return -EINVAL; + + pxa2xx_core_turbo_switch(index == PXA_CORE_TURBO); + + return 0; +} + +static int clk_pxa27x_core_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return __clk_mux_determine_rate(hw, req); +} + PARENTS(clk_pxa27x_core) = { "osc_13mhz", "run", "cpll" }; -MUX_RO_RATE_RO_OPS(clk_pxa27x_core, "core"); +MUX_OPS(clk_pxa27x_core, "core", CLK_SET_RATE_PARENT); static unsigned long clk_pxa27x_run_get_rate(struct clk_hw *hw, unsigned long parent_rate) |