diff options
author | Mattias Nilsson <mattias.i.nilsson@stericsson.com> | 2011-09-12 11:49:13 +0200 |
---|---|---|
committer | Rabin Vincent <rabin.vincent@stericsson.com> | 2011-09-22 15:41:13 +0530 |
commit | eec1ebb3331e143ed552dba57baedb4c2bde3c78 (patch) | |
tree | 0db06235ad142b03a4417b4d53089d33399d5fe7 | |
parent | 4ec93058a619acfafcb3ed307b04a21bf8fdaa09 (diff) |
u8500: change clk_get_rate for prcmu clocks
This patch changes the implementation of clk_get_rate for
PRCMU clocks, so that it returns a rate according to the
hardware settings instead of a hardcoded value.
ST Ericsson ID: 343004, 359227
ST Ericsson FOSS-OUT ID: trivial
ST Ericsson Linux next: -
Change-Id: I28c050f3263cf013bb7b7730a9affe66229e9180
Signed-off-by: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30744
Reviewed-by: QABUILD
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
-rw-r--r-- | arch/arm/mach-ux500/clock-db5500.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-ux500/clock-db8500.c | 49 | ||||
-rw-r--r-- | arch/arm/mach-ux500/clock.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/prcmu-db5500.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/prcmu.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-ux500/prcmu-db8500.c | 168 | ||||
-rw-r--r-- | arch/arm/mach-ux500/prcmu-regs-db8500.h | 25 |
7 files changed, 194 insertions, 67 deletions
diff --git a/arch/arm/mach-ux500/clock-db5500.c b/arch/arm/mach-ux500/clock-db5500.c index ae499aa8999..f61ed18e65b 100644 --- a/arch/arm/mach-ux500/clock-db5500.c +++ b/arch/arm/mach-ux500/clock-db5500.c @@ -802,6 +802,7 @@ int __init db5500_clk_init(void) prcc_kclk_ops.enable = NULL; prcc_kclk_ops.disable = NULL; } + prcmu_clk_ops.get_rate = NULL; if (cpu_is_u5500v1()) p1_sdi0_kclk.parent = &sdmmcclk; diff --git a/arch/arm/mach-ux500/clock-db8500.c b/arch/arm/mach-ux500/clock-db8500.c index 8683ee63d45..f26958689b4 100644 --- a/arch/arm/mach-ux500/clock-db8500.c +++ b/arch/arm/mach-ux500/clock-db8500.c @@ -33,13 +33,6 @@ #include "pins-db8500.h" #include "product.h" -#define PRCM_SDMMCCLK_MGT 0x024 -#define PRCM_TCR 0x1C8 -#define PRCM_TCR_STOPPED (1 << 16) -#define PRCM_TCR_DOZE_MODE (1 << 17) -#define SD_CLK_DIV_MASK 0x1F -#define SD_CLK_DIV_VAL 8 - static DEFINE_MUTEX(soc1_pll_mutex); static DEFINE_MUTEX(sysclk_mutex); static DEFINE_MUTEX(ab_ulpclk_mutex); @@ -50,20 +43,13 @@ static struct delayed_work sysclk_disable_work; /* PLL operations. */ -static int clk_pllsrc_enable(struct clk *clk) -{ - /* To enable pll */ - return 0; -} - -static void clk_pllsrc_disable(struct clk *clk) +static unsigned long pll_get_rate(struct clk *clk) { - /* To disable pll */ + return prcmu_clock_rate(clk->cg_sel); } -static struct clkops pll_clk_ops = { - .enable = clk_pllsrc_enable, - .disable = clk_pllsrc_disable, +static struct clkops pll_ops = { + .get_rate = pll_get_rate, }; /* SysClk operations. */ @@ -405,19 +391,12 @@ static struct clkops clkout1_ops = { #define DEF_PER6_KCLK(_cg_bit, _name, _parent) \ DEF_PRCC_KCLK(_name, U8500_CLKRST6_BASE, _cg_bit, _parent, &per6clk) -#define DEF_MTU_CLK(_cg_sel, _name, _bus_parent) \ - struct clk _name = { \ - .name = #_name, \ - .ops = &mtu_clk_ops, \ - .cg_sel = _cg_sel, \ - .bus_parent = _bus_parent, \ - } - /* Clock sources. */ static struct clk soc0_pll = { .name = "soc0_pll", - .ops = &pll_clk_ops, + .ops = &pll_ops, + .cg_sel = PRCMU_PLLSOC0, }; static struct clk soc1_pll = { @@ -429,11 +408,13 @@ static struct clk soc1_pll = { static struct clk ddr_pll = { .name = "ddr_pll", - .ops = &pll_clk_ops, + .ops = &pll_ops, + .cg_sel = PRCMU_PLLDDR, }; static struct clk ulp38m4 = { .name = "ulp38m4", + .rate = 38400000, }; static struct clk sysclk = { @@ -447,6 +428,7 @@ static struct clk sysclk2 = { .name = "sysclk2", .ops = &sysclk_ops, .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, + .rate = 38400000, .mutex = &sysclk_mutex, }; @@ -454,6 +436,7 @@ static struct clk sysclk3 = { .name = "sysclk3", .ops = &sysclk_ops, .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, + .rate = 38400000, .mutex = &sysclk_mutex, }; @@ -461,6 +444,7 @@ static struct clk sysclk4 = { .name = "sysclk4", .ops = &sysclk_ops, .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, + .rate = 38400000, .mutex = &sysclk_mutex, }; @@ -773,21 +757,24 @@ static int clk_show_print(struct seq_file *s, void *p) int i; int enabled_only = (int)s->private; - seq_printf(s, "\n%-20s %s\n", "name", "enabled (kernel + debug)"); + seq_printf(s, "\n%-20s %10s %s\n", "name", "rate", + "enabled (kernel + debug)"); for (i = 0; i < ARRAY_SIZE(dbg_clks); i++) { if (enabled_only && !dbg_clks[i].clk->enabled) continue; if (dbg_clks[i].name) seq_printf(s, - "%-20s %5d + %d\n", + "%-20s %10lu %5d + %d\n", dbg_clks[i].name, + clk_get_rate(dbg_clks[i].clk), dbg_clks[i].clk->enabled - !!dbg_clks[i].enabled, dbg_clks[i].enabled); else seq_printf(s, - "%-20s %5d + %d\n", + "%-20s %10lu %5d + %d\n", dbg_clks[i].clk->name, + clk_get_rate(dbg_clks[i].clk), dbg_clks[i].clk->enabled - !!dbg_clks[i].enabled, dbg_clks[i].enabled); diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 90897c697f1..ce167af6def 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -303,14 +303,21 @@ out_error: pr_err("clock: %s failed to disable %s.\n", __func__, clk->name); } +static unsigned long prcmu_clk_get_rate(struct clk *clk) +{ + return prcmu_clock_rate(clk->cg_sel); +} + struct clkops prcmu_clk_ops = { .enable = prcmu_clk_enable, .disable = prcmu_clk_disable, + .get_rate = prcmu_clk_get_rate, }; struct clkops prcmu_opp100_clk_ops = { .enable = prcmu_opp100_clk_enable, .disable = prcmu_opp100_clk_disable, + .get_rate = prcmu_clk_get_rate, }; /* PRCC clock operations. */ diff --git a/arch/arm/mach-ux500/include/mach/prcmu-db5500.h b/arch/arm/mach-ux500/include/mach/prcmu-db5500.h index ae76fef0e44..6b0efb088d9 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu-db5500.h +++ b/arch/arm/mach-ux500/include/mach/prcmu-db5500.h @@ -15,6 +15,11 @@ int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); int db5500_prcmu_request_clock(u8 clock, bool enable); +static inline unsigned long prcmu_clock_rate(u8 clock) +{ + return 0; +} + int prcmu_resetout(u8 resoutn, u8 state); unsigned int prcmu_get_ddr_freq(void); diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h index 5638b970752..3b4c52cfdb0 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu.h +++ b/arch/arm/mach-ux500/include/mach/prcmu.h @@ -273,6 +273,7 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); int prcmu_config_clkout(u8 clkout, u8 source, u8 div); int prcmu_request_clock(u8 clock, bool enable); +unsigned long prcmu_clock_rate(u8 clock); int prcmu_set_ape_opp(u8 opp); int prcmu_get_ape_opp(void); @@ -333,6 +334,11 @@ static inline int prcmu_request_clock(u8 clock, bool enable) return 0; } +static inline unsigned long prcmu_clock_rate(u8 clock) +{ + return 0; +} + static inline int prcmu_set_ape_opp(u8 opp) { return 0; diff --git a/arch/arm/mach-ux500/prcmu-db8500.c b/arch/arm/mach-ux500/prcmu-db8500.c index 5c7c7b71adc..c12ced614f1 100644 --- a/arch/arm/mach-ux500/prcmu-db8500.c +++ b/arch/arm/mach-ux500/prcmu-db8500.c @@ -429,41 +429,50 @@ static __iomem void *tcdm_base; struct clk_mgt { unsigned int offset; u32 pllsw; + int branch; + bool clk38div; +}; + +enum { + PLL_RAW, + PLL_FIX, + PLL_DIV }; static DEFINE_SPINLOCK(clk_mgt_lock); -#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT), 0 } +#define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \ + { (PRCM_##_name##_MGT), 0 , _branch, _clk38div} struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { - CLK_MGT_ENTRY(SGACLK), - CLK_MGT_ENTRY(UARTCLK), - CLK_MGT_ENTRY(MSP02CLK), - CLK_MGT_ENTRY(MSP1CLK), - CLK_MGT_ENTRY(I2CCLK), - CLK_MGT_ENTRY(SDMMCCLK), - CLK_MGT_ENTRY(SLIMCLK), - CLK_MGT_ENTRY(PER1CLK), - CLK_MGT_ENTRY(PER2CLK), - CLK_MGT_ENTRY(PER3CLK), - CLK_MGT_ENTRY(PER5CLK), - CLK_MGT_ENTRY(PER6CLK), - CLK_MGT_ENTRY(PER7CLK), - CLK_MGT_ENTRY(LCDCLK), - CLK_MGT_ENTRY(BMLCLK), - CLK_MGT_ENTRY(HSITXCLK), - CLK_MGT_ENTRY(HSIRXCLK), - CLK_MGT_ENTRY(HDMICLK), - CLK_MGT_ENTRY(APEATCLK), - CLK_MGT_ENTRY(APETRACECLK), - CLK_MGT_ENTRY(MCDECLK), - CLK_MGT_ENTRY(IPI2CCLK), - CLK_MGT_ENTRY(DSIALTCLK), - CLK_MGT_ENTRY(DMACLK), - CLK_MGT_ENTRY(B2R2CLK), - CLK_MGT_ENTRY(TVCLK), - CLK_MGT_ENTRY(SSPCLK), - CLK_MGT_ENTRY(RNGCLK), - CLK_MGT_ENTRY(UICCCLK), + CLK_MGT_ENTRY(SGACLK, PLL_DIV, false), + CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true), + CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true), + CLK_MGT_ENTRY(MSP1CLK, PLL_FIX, true), + CLK_MGT_ENTRY(I2CCLK, PLL_FIX, true), + CLK_MGT_ENTRY(SDMMCCLK, PLL_DIV, true), + CLK_MGT_ENTRY(SLIMCLK, PLL_FIX, true), + CLK_MGT_ENTRY(PER1CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER2CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER3CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER5CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true), + CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true), + CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true), + CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true), + CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true), + CLK_MGT_ENTRY(HDMICLK, PLL_FIX, false), + CLK_MGT_ENTRY(APEATCLK, PLL_DIV, true), + CLK_MGT_ENTRY(APETRACECLK, PLL_DIV, true), + CLK_MGT_ENTRY(MCDECLK, PLL_DIV, true), + CLK_MGT_ENTRY(IPI2CCLK, PLL_FIX, true), + CLK_MGT_ENTRY(DSIALTCLK, PLL_FIX, false), + CLK_MGT_ENTRY(DMACLK, PLL_DIV, true), + CLK_MGT_ENTRY(B2R2CLK, PLL_DIV, true), + CLK_MGT_ENTRY(TVCLK, PLL_FIX, false), + CLK_MGT_ENTRY(SSPCLK, PLL_FIX, true), + CLK_MGT_ENTRY(RNGCLK, PLL_FIX, true), + CLK_MGT_ENTRY(UICCCLK, PLL_FIX, false), }; /* @@ -1467,7 +1476,7 @@ static int request_timclk(bool enable) return 0; } -static int request_reg_clock(u8 clock, bool enable) +static int request_clock(u8 clock, bool enable) { u32 val; unsigned long flags; @@ -1506,7 +1515,7 @@ static int request_sga_clock(u8 clock, bool enable) _PRCMU_BASE + PRCM_CGATING_BYPASS); } - ret = request_reg_clock(clock, enable); + ret = request_clock(clock, enable); if (!ret && !enable) { val = readl(_PRCMU_BASE + PRCM_CGATING_BYPASS); @@ -1530,7 +1539,7 @@ int prcmu_request_clock(u8 clock, bool enable) if (clock == PRCMU_SGACLK) return request_sga_clock(clock, enable); else if (clock < PRCMU_NUM_REG_CLOCKS) - return request_reg_clock(clock, enable); + return request_clock(clock, enable); else if (clock == PRCMU_TIMCLK) return request_timclk(enable); else if (clock == PRCMU_SYSCLK) @@ -1541,6 +1550,99 @@ int prcmu_request_clock(u8 clock, bool enable) return -EINVAL; } +static unsigned long pll_rate(unsigned int reg_offset, unsigned long src_rate, + u32 div, int branch) +{ + u64 rate; + u32 val; + u32 d; + + val = readl(_PRCMU_BASE + reg_offset); + + rate = src_rate; + rate *= ((val & PRCM_PLL_FREQ_D_MASK) >> PRCM_PLL_FREQ_D_SHIFT); + + d = ((val & PRCM_PLL_FREQ_N_MASK) >> PRCM_PLL_FREQ_N_SHIFT); + if (d > 1) + div *= d; + + d = ((val & PRCM_PLL_FREQ_R_MASK) >> PRCM_PLL_FREQ_R_SHIFT); + if (d > 1) + div *= d; + + if (val & PRCM_PLL_FREQ_SELDIV2) + div *= 2; + + if ((branch == PLL_FIX) || ((branch == PLL_DIV) && + (val & PRCM_PLL_FREQ_DIV2EN) && + ((reg_offset == PRCM_PLLSOC0_FREQ) || + (reg_offset == PRCM_PLLDDR_FREQ)))) + div *= 2; + + (void)do_div(rate, div); + + return (unsigned long)rate; +} + +#define ROOT_CLOCK_RATE 38400000 + +static unsigned long clock_rate(u8 clock) +{ + u32 val; + u32 div; + unsigned long src_rate = ROOT_CLOCK_RATE; + + val = readl(_PRCMU_BASE + clk_mgt[clock].offset); + + if (val & PRCM_CLK_MGT_CLK38) { + if (clk_mgt[clock].clk38div && (val & PRCM_CLK_MGT_CLK38DIV)) + src_rate /= 2; + return src_rate; + } + + if ((clock == PRCMU_SGACLK) && + (val & PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN)) { + src_rate *= 10; + div = 25; + } else { + div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK); + if (!div) + return 0; + } + + switch ((val | clk_mgt[clock].pllsw) & PRCM_CLK_MGT_CLKPLLSW_MASK) { + case PRCM_CLK_MGT_CLKPLLSW_SOC0: + return pll_rate(PRCM_PLLSOC0_FREQ, src_rate, div, + clk_mgt[clock].branch); + case PRCM_CLK_MGT_CLKPLLSW_SOC1: + return pll_rate(PRCM_PLLSOC1_FREQ, src_rate, div, + clk_mgt[clock].branch); + case PRCM_CLK_MGT_CLKPLLSW_DDR: + return pll_rate(PRCM_PLLDDR_FREQ, src_rate, div, + clk_mgt[clock].branch); + default: + return 0; + } +} + +unsigned long prcmu_clock_rate(u8 clock) +{ + if (clock < PRCMU_NUM_REG_CLOCKS) + return clock_rate(clock); + else if (clock == PRCMU_TIMCLK) + return ROOT_CLOCK_RATE / 16; + else if (clock == PRCMU_SYSCLK) + return ROOT_CLOCK_RATE; + else if (clock == PRCMU_PLLSOC0) + return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, 1, PLL_RAW); + else if (clock == PRCMU_PLLSOC1) + return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, 1, PLL_RAW); + else if (clock == PRCMU_PLLDDR) + return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, 1, PLL_RAW); + else + return 0; +} + int prcmu_config_esram0_deep_sleep(u8 state) { if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) || diff --git a/arch/arm/mach-ux500/prcmu-regs-db8500.h b/arch/arm/mach-ux500/prcmu-regs-db8500.h index 60faa143075..4e84232a4cd 100644 --- a/arch/arm/mach-ux500/prcmu-regs-db8500.h +++ b/arch/arm/mach-ux500/prcmu-regs-db8500.h @@ -93,7 +93,20 @@ #define PRCM_SEM_PRCM_SEM BIT(0) /* PRCMU clock/PLL/reset registers */ +#define PRCM_PLLSOC0_FREQ 0x080 +#define PRCM_PLLSOC1_FREQ 0x084 +#define PRCM_PLLDDR_FREQ 0x08C #define PRCM_PLLDSI_FREQ 0x500 + +#define PRCM_PLL_FREQ_D_SHIFT 0 +#define PRCM_PLL_FREQ_D_MASK BITS(0, 7) +#define PRCM_PLL_FREQ_N_SHIFT 8 +#define PRCM_PLL_FREQ_N_MASK BITS(8, 13) +#define PRCM_PLL_FREQ_R_SHIFT 16 +#define PRCM_PLL_FREQ_R_MASK BITS(16, 18) +#define PRCM_PLL_FREQ_SELDIV2 BIT(24) +#define PRCM_PLL_FREQ_DIV2EN BIT(25) + #define PRCM_PLLDSI_ENABLE 0x504 #define PRCM_PLLDSI_LOCKP 0x508 #define PRCM_DSI_PLLOUT_SEL 0x530 @@ -149,9 +162,15 @@ #define PRCM_RNGCLK_MGT 0x284 #define PRCM_UICCCLK_MGT 0x27C -#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4) -#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7) -#define PRCM_CLK_MGT_CLKEN BIT(8) +#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4) +#define PRCM_CLK_MGT_CLKPLLSW_SOC0 BIT(5) +#define PRCM_CLK_MGT_CLKPLLSW_SOC1 BIT(6) +#define PRCM_CLK_MGT_CLKPLLSW_DDR BIT(7) +#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7) +#define PRCM_CLK_MGT_CLKEN BIT(8) +#define PRCM_CLK_MGT_CLK38 BIT(9) +#define PRCM_CLK_MGT_CLK38DIV BIT(11) +#define PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN BIT(12) /* ePOD and memory power signal control registers */ #define PRCM_EPOD_C_SET 0x410 |