aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2010-06-21 17:06:19 +0200
committerJohn Rigby <john.rigby@linaro.org>2010-09-02 22:45:47 -0600
commit12b9f0fbb9a060951420fde0d47e2f821f12b915 (patch)
tree5874ba7b3d020444fdcbe5881a3611eb4c9e4084
parent6875d3d22c455ce42aa86be66f1c196bb0e570de (diff)
mach-ux500: backport clock rate callbacks and MTU frequency fix
This is a backport of the changes adding per-clock callbacks submitted to the mainline kernel tree, and reads out the MTU- specific clock routing register. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/1700 Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> Change-Id: I41f65d78b995ecfa210b9bf6283351b027ae8bbd Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/2631 Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
-rwxr-xr-xarch/arm/mach-ux500/clock.c100
-rwxr-xr-xarch/arm/mach-ux500/clock.h19
-rw-r--r--arch/arm/mach-ux500/cpu-db5500.c1
3 files changed, 116 insertions, 4 deletions
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index 24561b35ee7..43d6b9e2062 100755
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -60,6 +60,9 @@
#define PRCM_DMACLK_MGT 0x074
#define PRCM_B2R2CLK_MGT 0x078
#define PRCM_TVCLK_MGT 0x07C
+#define PRCM_TCR 0x1C8
+#define PRCM_TCR_STOPPED (1 << 16)
+#define PRCM_TCR_DOZE_MODE (1 << 17)
#define PRCM_UNIPROCLK_MGT 0x278
#define PRCM_SSPCLK_MGT 0x280
#define PRCM_RNGCLK_MGT 0x284
@@ -141,10 +144,95 @@ void clk_disable(struct clk *clk)
}
EXPORT_SYMBOL(clk_disable);
+/*
+ * The MTU has a separate, rather complex muxing setup
+ * with alternative parents (peripheral cluster or
+ * ULP or fixed 32768 Hz) depending on settings
+ */
+static unsigned long clk_mtu_get_rate(struct clk *clk)
+{
+ void __iomem *addr = __io_address(UX500_PRCMU_BASE)
+ + PRCM_TCR;
+ u32 tcr = readl(addr);
+ int mtu = (int) clk->data;
+ /*
+ * One of these is selected eventually
+ * TODO: Replace the constant with a reference
+ * to the ULP source once this is modeled.
+ */
+ unsigned long clk32k = 32768;
+ unsigned long mturate;
+ unsigned long retclk;
+
+ /* Get the rate from the parent as a default */
+ if (clk->parent_periph)
+ mturate = clk_get_rate(clk->parent_periph);
+ else if (clk->parent_cluster)
+ mturate = clk_get_rate(clk->parent_cluster);
+ else
+ /* We need to be connected SOMEWHERE */
+ BUG();
+
+ /*
+ * Are we in doze mode?
+ * In this mode the parent peripheral or the fixed 32768 Hz
+ * clock is fed into the block.
+ */
+ if (!(tcr & PRCM_TCR_DOZE_MODE)) {
+ /*
+ * Here we're using the clock input from the APE ULP
+ * clock domain. But first: are the timers stopped?
+ */
+ if (tcr & PRCM_TCR_STOPPED) {
+ clk32k = 0;
+ mturate = 0;
+ } else {
+ /* Else default mode: 0 and 2.4 MHz */
+ clk32k = 0;
+ if (cpu_is_u5500())
+ /* DB5500 divides by 8 */
+ mturate /= 8;
+ else if (cpu_is_u8500ed()) {
+ /*
+ * This clocking setting must not be used
+ * in the ED chip, it is simply not
+ * connected anywhere!
+ */
+ mturate = 0;
+ BUG();
+ } else
+ /*
+ * In this mode the ulp38m4 clock is divided
+ * by a factor 16, on the DB8500 typically
+ * 38400000 / 16 ~ 2.4 MHz.
+ * TODO: Replace the constant with a reference
+ * to the ULP source once this is modeled.
+ */
+ mturate = 38400000 / 16;
+ }
+ }
+
+ /* Return the clock selected for this MTU */
+ if (tcr & (1 << mtu))
+ retclk = clk32k;
+ else
+ retclk = mturate;
+
+ pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk);
+ return retclk;
+}
+
unsigned long clk_get_rate(struct clk *clk)
{
unsigned long rate;
+ /*
+ * If there is a custom getrate callback for this clock,
+ * it will take precedence.
+ */
+ if (clk->get_rate)
+ return clk->get_rate(clk);
+
if (clk->ops && clk->ops->get_rate)
return clk->ops->get_rate(clk);
@@ -385,8 +473,9 @@ static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL);
/* Peripheral Cluster #6 */
-static DEFINE_PRCC_CLK(6, mtu1_v1, 8, -1, NULL);
-static DEFINE_PRCC_CLK(6, mtu0_v1, 7, -1, NULL);
+/* MTU ID in data */
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1);
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0);
static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL);
static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
@@ -401,8 +490,9 @@ static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk);
/* Peripheral Cluster #7 */
static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL);
-static DEFINE_PRCC_CLK(7, mtu1_ed, 3, -1, NULL);
-static DEFINE_PRCC_CLK(7, mtu0_ed, 2, -1, NULL);
+/* MTU ID in data */
+static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1);
+static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0);
static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL);
static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
@@ -677,6 +767,7 @@ int __init clk_init(void)
clk_prcmu_ops.enable = clk_prcmu_ed_enable;
clk_prcmu_ops.disable = clk_prcmu_ed_disable;
clk_i2cclk.rate = 48000000;
+ clk_per6clk.rate = 100000000;
} else if (cpu_is_u8500v1()) {
void __iomem *sdmmclkmgt = __io_address(U8500_PRCMU_BASE)
+ PRCM_SDMMCCLK_MGT;
@@ -691,6 +782,7 @@ int __init clk_init(void)
clk_prcmu_ops.disable = NULL;
clk_prcc_ops.enable = NULL;
clk_prcc_ops.disable = NULL;
+ clk_per6clk.rate = 26000000;
}
clks_register(u8500_common_clkregs, ARRAY_SIZE(u8500_common_clkregs));
diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h
index 50383fb028d..5a454b95886 100755
--- a/arch/arm/mach-ux500/clock.h
+++ b/arch/arm/mach-ux500/clock.h
@@ -51,6 +51,9 @@ struct clkops {
* @ops: pointer to clkops struct used to control this clock
* @name: name, for debugging
* @enabled: refcount. positive if enabled, zero if disabled
+ * @get_rate: custom callback for getting the clock rate
+ * @data: custom per-clock data for example for the get_rate
+ * callback
* @rate: fixed rate for clocks which don't implement
* ops->getrate
* @prcmu_cg_off: address offset of the combined enable/disable register
@@ -90,6 +93,8 @@ struct clk {
const struct clkops *ops;
const char *name;
unsigned int enabled;
+ unsigned long (*get_rate)(struct clk *);
+ void *data;
unsigned long rate;
struct list_head list;
@@ -159,6 +164,20 @@ struct clk clk_##_name = { \
.parent_periph = _kernclk \
}
+#define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \
+struct clk clk_##_name = { \
+ .name = #_name, \
+ .ops = &clk_prcc_ops, \
+ .cluster = _pclust, \
+ .prcc_bus = _bus_en, \
+ .prcc_kernel = _kernel_en, \
+ .parent_cluster = &clk_per##_pclust##clk, \
+ .parent_periph = _kernclk, \
+ .get_rate = _callback, \
+ .data = (void *) _data \
+ }
+
+
#define CLK(_clk, _devname, _conname) \
{ \
.clk = &clk_##_clk, \
diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c
index c9844c9d86c..6bf35781d40 100644
--- a/arch/arm/mach-ux500/cpu-db5500.c
+++ b/arch/arm/mach-ux500/cpu-db5500.c
@@ -23,6 +23,7 @@ static struct map_desc u5500_io_desc[] __initdata = {
__IO_DEV_DESC(U5500_GPIO2_BASE, SZ_4K),
__IO_DEV_DESC(U5500_GPIO3_BASE, SZ_4K),
__IO_DEV_DESC(U5500_GPIO4_BASE, SZ_4K),
+ __IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K),
};
static struct resource mbox0_resources[] = {