summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMattias Nilsson <mattias.i.nilsson@stericsson.com>2011-09-12 11:49:13 +0200
committerRabin Vincent <rabin.vincent@stericsson.com>2011-09-22 15:41:13 +0530
commiteec1ebb3331e143ed552dba57baedb4c2bde3c78 (patch)
tree0db06235ad142b03a4417b4d53089d33399d5fe7
parent4ec93058a619acfafcb3ed307b04a21bf8fdaa09 (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.c1
-rw-r--r--arch/arm/mach-ux500/clock-db8500.c49
-rw-r--r--arch/arm/mach-ux500/clock.c7
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu-db5500.h5
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu.h6
-rw-r--r--arch/arm/mach-ux500/prcmu-db8500.c168
-rw-r--r--arch/arm/mach-ux500/prcmu-regs-db8500.h25
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