|
@@ -16,6 +16,7 @@
|
|
|
|
|
|
#include <asm/clkdev.h>
|
|
#include <asm/clkdev.h>
|
|
|
|
|
|
|
|
+#include <plat/mtu.h>
|
|
#include <mach/hardware.h>
|
|
#include <mach/hardware.h>
|
|
#include "clock.h"
|
|
#include "clock.h"
|
|
|
|
|
|
@@ -59,6 +60,9 @@
|
|
#define PRCM_DMACLK_MGT 0x074
|
|
#define PRCM_DMACLK_MGT 0x074
|
|
#define PRCM_B2R2CLK_MGT 0x078
|
|
#define PRCM_B2R2CLK_MGT 0x078
|
|
#define PRCM_TVCLK_MGT 0x07C
|
|
#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_UNIPROCLK_MGT 0x278
|
|
#define PRCM_SSPCLK_MGT 0x280
|
|
#define PRCM_SSPCLK_MGT 0x280
|
|
#define PRCM_RNGCLK_MGT 0x284
|
|
#define PRCM_RNGCLK_MGT 0x284
|
|
@@ -120,10 +124,95 @@ void clk_disable(struct clk *clk)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(clk_disable);
|
|
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(U8500_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 clk_get_rate(struct clk *clk)
|
|
{
|
|
{
|
|
unsigned long rate;
|
|
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)
|
|
if (clk->ops && clk->ops->get_rate)
|
|
return clk->ops->get_rate(clk);
|
|
return clk->ops->get_rate(clk);
|
|
|
|
|
|
@@ -341,8 +430,9 @@ static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL);
|
|
|
|
|
|
/* Peripheral Cluster #6 */
|
|
/* 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, cfgreg_v1, 6, 6, NULL);
|
|
static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
|
|
static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
|
|
static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
|
|
static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
|
|
@@ -357,8 +447,9 @@ static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk);
|
|
/* Peripheral Cluster #7 */
|
|
/* Peripheral Cluster #7 */
|
|
|
|
|
|
static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL);
|
|
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, wdg_ed, 1, -1, NULL);
|
|
static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
|
|
static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
|
|
|
|
|
|
@@ -503,15 +594,17 @@ static struct clk_lookup u8500_v1_clks[] = {
|
|
CLK(uiccclk, "uicc", NULL),
|
|
CLK(uiccclk, "uicc", NULL),
|
|
};
|
|
};
|
|
|
|
|
|
-static int __init clk_init(void)
|
|
|
|
|
|
+int __init clk_init(void)
|
|
{
|
|
{
|
|
if (cpu_is_u8500ed()) {
|
|
if (cpu_is_u8500ed()) {
|
|
clk_prcmu_ops.enable = clk_prcmu_ed_enable;
|
|
clk_prcmu_ops.enable = clk_prcmu_ed_enable;
|
|
clk_prcmu_ops.disable = clk_prcmu_ed_disable;
|
|
clk_prcmu_ops.disable = clk_prcmu_ed_disable;
|
|
|
|
+ clk_per6clk.rate = 100000000;
|
|
} else if (cpu_is_u5500()) {
|
|
} else if (cpu_is_u5500()) {
|
|
/* Clock tree for U5500 not implemented yet */
|
|
/* Clock tree for U5500 not implemented yet */
|
|
clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
|
|
clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
|
|
clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
|
|
clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
|
|
|
|
+ clk_per6clk.rate = 26000000;
|
|
}
|
|
}
|
|
|
|
|
|
clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
|
|
clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
|
|
@@ -522,4 +615,3 @@ static int __init clk_init(void)
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
-arch_initcall(clk_init);
|
|
|