ARM: tegra: clock: Add Tegra3 emc high voltage bridge
Alex Frid [Wed, 29 Jun 2011 03:50:29 +0000 (20:50 -0700)]
On Tegra3 platforms emc configurations for DDR3 rates below 300MHz
can not work at high core voltage; the intermediate step (bridge) is
mandatory when core voltage is crossing the 1.2V threshold (fixed for
Tegra3 arch). In addition emc must run above bridge rate if any other
than emc clock requires high voltage.

EMC bridge is implemented as a special emc shared user: its rate is set
once during emc dvfs table initialization; then, the bridge is enabled
or disabled when sbus and/or cbus voltage requirement is crossing the
threshold (sbus and cbus together include all clocks that may require
voltage above threshold - other peripherals can reach their maximum
rates below threshold).

Bug 846693

Change-Id: Ib17448877583453250cf11adf6c5c94dab0fadcf
Reviewed-on: http://git-master/r/39919
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>

Rebase-Id: Re546be46958b6bf8e491553679b1637eaf3786ff

arch/arm/mach-tegra/dvfs.c
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/tegra3_emc.c
arch/arm/mach-tegra/tegra3_emc.h

index bbf43ae..da0e69e 100644 (file)
@@ -267,6 +267,27 @@ __tegra_dvfs_set_rate(struct dvfs *d, unsigned long rate)
        return ret;
 }
 
+int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate)
+{
+       int i;
+
+       if (!rate || !c->dvfs)
+               return 0;
+
+       if (!c->dvfs->millivolts)
+               return -ENODEV;
+
+       for (i = 0; i < c->dvfs->num_freqs; i++) {
+               if (rate <= c->dvfs->freqs[i])
+                       break;
+       }
+
+       if (i == c->dvfs->num_freqs)
+               return -EINVAL;
+
+       return c->dvfs->millivolts[i];
+}
+
 int tegra_dvfs_set_rate(struct clk *c, unsigned long rate)
 {
        int ret;
index 2efa2af..862a827 100644 (file)
@@ -96,6 +96,7 @@ void tegra_dvfs_add_relationships(struct dvfs_relationship *rels, int n);
 void tegra_dvfs_rail_enable(struct dvfs_rail *rail);
 void tegra_dvfs_rail_disable(struct dvfs_rail *rail);
 bool tegra_dvfs_rail_updating(struct clk *clk);
+int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate);
 #else
 static inline int tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d)
 { return 0; }
@@ -113,6 +114,8 @@ static inline void tegra_dvfs_rail_disable(struct dvfs_rail *rail)
 {}
 static inline bool tegra_dvfs_rail_updating(struct clk *clk)
 { return false; }
+static inline int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate)
+{ return 0; }
 #endif
 
 #endif
index 0a3df4c..9d72368 100644 (file)
@@ -35,6 +35,7 @@
 #include <mach/iomap.h>
 
 #include "clock.h"
+#include "dvfs.h"
 #include "tegra3_emc.h"
 
 #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
@@ -721,6 +722,36 @@ static const struct clk_mux_sel *find_matching_input(
        return NULL;
 }
 
+static bool is_emc_bridge(void)
+{
+       int mv;
+       unsigned long rate;
+       struct clk *bridge = tegra_get_clock_by_name("bridge.emc");
+       BUG_ON(!bridge);
+
+       /* LPDDR2 does not need a bridge entry in DFS table: just lock bridge
+          rate at minimum so it won't interfere with emc bus operations */
+       if (dram_type == DRAM_TYPE_LPDDR2) {
+               clk_set_rate(bridge, 0);
+               return true;
+       }
+
+       /* DDR3 requires EMC DFS table to include a bridge entry with frequency
+          above minimum bridge threshold, and voltage below bridge threshold */
+       rate = clk_round_rate(bridge, TEGRA_EMC_BRIDGE_RATE_MIN);
+       if (IS_ERR_VALUE(rate))
+               return false;
+
+       mv = tegra_dvfs_predict_millivolts(emc, rate);
+       if (IS_ERR_VALUE(mv) || (mv > TEGRA_EMC_BRIDGE_MVOLTS_MIN))
+               return false;
+
+       if (clk_set_rate(bridge, rate))
+               return false;
+
+       return true;
+}
+
 static int tegra_emc_probe(struct platform_device *pdev)
 {
        struct tegra_emc_pdata *pdata = NULL;
@@ -819,8 +850,15 @@ static int tegra_emc_probe(struct platform_device *pdev)
                       " %lu kHz is not found\n", max_rate);
                return;
        }
-       pr_info("tegra: validated EMC DFS table\n");
+
        tegra_emc_table = table;
+
+       if (!is_emc_bridge()) {
+               tegra_emc_table = NULL;
+               pr_err("tegra: invalid EMC DFS table: emc bridge not found");
+       }
+       pr_info("tegra: validated EMC DFS table\n");
+
        return 0;
 }
 
index 085a1dc..50b0007 100644 (file)
@@ -22,6 +22,9 @@
 #ifndef _MACH_TEGRA_TEGRA3_EMC_H
 #define _MACH_TEGRA_TEGRA3_EMC_H
 
+#define TEGRA_EMC_BRIDGE_RATE_MIN      300000000
+#define TEGRA_EMC_BRIDGE_MVOLTS_MIN    1200
+
 #define EMC_INTSTATUS                          0x0
 #define EMC_INTSTATUS_CLKCHANGE_COMPLETE       (0x1 << 4)