ARM: tegra12: clock: Add memory controller clock
Alex Frid [Thu, 12 Dec 2013 07:14:27 +0000 (23:14 -0800)]
Memory controller clock is a child of EMC clock and it is running at
either 1:1 or 1:2 ratio from EMC. MC rate is changing as part of EMC
clock scaling only. No direct MC rate control is allowed.

Added MC clock to the clock tree for information purpose.
Ported from commit 9f8c1aa319ca19a39b56db901326997883fa6f2b

Change-Id: Ie4217493355745ba8e0df7129dc08cc7192d3bd6
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/344657
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/tegra12_clocks.c
arch/arm/mach-tegra/tegra12_emc.c
arch/arm/mach-tegra/tegra_emc.h

index b8be815..d624edf 100644 (file)
@@ -373,7 +373,7 @@ static __initdata struct tegra_clk_init_table tegra11x_cbus_init_table[] = {
 static __initdata struct tegra_clk_init_table tegra12x_clk_init_table[] = {
        /* name         parent          rate            enabled */
        { "clk_m",      NULL,           0,              true },
-       { "emc",        NULL,           0,              true },
+       { "mc",         NULL,           0,              true },
        { "cpu",        NULL,           0,              true },
        { "kfuse",      NULL,           0,              true },
        { "fuse",       NULL,           0,              true },
index 7437d58..d5fb782 100644 (file)
 
 #define PERIPH_CLK_SOURCE_I2S1         0x100
 #define PERIPH_CLK_SOURCE_EMC          0x19c
+#define PERIPH_CLK_SOURCE_EMC_MC_SAME  (1<<16)
+
 #define PERIPH_CLK_SOURCE_LA           0x1f8
 #define PERIPH_CLK_SOURCE_NUM1 \
        ((PERIPH_CLK_SOURCE_LA - PERIPH_CLK_SOURCE_I2S1) / 4)
@@ -5201,6 +5203,29 @@ static struct clk_ops tegra_emc_clk_ops = {
        .shared_bus_update      = &tegra12_clk_emc_bus_update,
 };
 
+void tegra_mc_divider_update(struct clk *emc)
+{
+       emc->child_bus->div = (clk_readl(emc->reg) &
+                              PERIPH_CLK_SOURCE_EMC_MC_SAME) ? 1 : 2;
+}
+
+static void tegra12_mc_clk_init(struct clk *c)
+{
+       c->state = ON;
+       if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
+               c->state = OFF;
+
+       c->parent->child_bus = c;
+       tegra_mc_divider_update(c->parent);
+       c->mul = 1;
+}
+
+static struct clk_ops tegra_mc_clk_ops = {
+       .init                   = &tegra12_mc_clk_init,
+       .enable                 = &tegra12_periph_clk_enable,
+       .disable                = &tegra12_periph_clk_disable,
+};
+
 /* Clock doubler ops (non-atomic shared register access) */
 static DEFINE_SPINLOCK(doubler_lock);
 
@@ -7421,6 +7446,17 @@ static struct clk tegra_clk_emc = {
        .rate_change_nh = &emc_rate_change_nh,
 };
 
+static struct clk tegra_clk_mc = {
+       .name = "mc",
+       .ops = &tegra_mc_clk_ops,
+       .max_rate =  533000000,
+       .parent = &tegra_clk_emc,
+       .flags = PERIPH_NO_RESET,
+       .u.periph = {
+               .clk_num = 32,
+       },
+};
+
 static struct raw_notifier_head host1x_rate_change_nh;
 
 static struct clk tegra_clk_host1x = {
@@ -8359,6 +8395,7 @@ struct clk *tegra_ptr_clks[] = {
        &tegra_clk_ahb,
        &tegra_clk_apb,
        &tegra_clk_emc,
+       &tegra_clk_mc,
        &tegra_clk_host1x,
        &tegra_clk_mselect,
 #ifdef CONFIG_TEGRA_DUAL_CBUS
index 8b9f3e6..3ba3324 100644 (file)
@@ -967,6 +967,7 @@ int tegra_emc_set_rate(unsigned long rate)
        emc_set_clock(&tegra_emc_table[i], last_timing, clk_setting);
        clkchange_time = ktime_get();
        emc_timing = &tegra_emc_table[i];
+       tegra_mc_divider_update(emc);
        spin_unlock_irqrestore(&emc_access_lock, flags);
 
        emc_last_stats_update(i);
@@ -1559,6 +1560,7 @@ int __init tegra12_emc_init(void)
 void tegra_emc_timing_invalidate(void)
 {
        emc_timing = NULL;
+       tegra_mc_divider_update(emc);
 }
 
 void tegra_emc_dram_type_init(struct clk *c)
index 7f49a72..afeb021 100644 (file)
@@ -74,6 +74,7 @@ struct clk *tegra_emc_predict_parent(unsigned long rate, u32 *div_value);
 bool tegra_emc_is_parent_ready(unsigned long rate, struct clk **parent,
                unsigned long *parent_rate, unsigned long *backup_rate);
 void tegra_emc_timing_invalidate(void);
+void tegra_mc_divider_update(struct clk *emc);
 
 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
 int tegra_emc_backup(unsigned long rate);