ARM: tegra11: clock: Allow EMC rates above PLLM boot rate
Alex Frid [Sat, 15 Dec 2012 02:57:57 +0000 (18:57 -0800)]
Added kernel command line parameter "emc_max_dvfs". If this parameter
is set, and PLLM scaling is enabled, then EMC rate may exceed boot
PLLM frequency and reach maximum accepted rate in the EMC DVFS table.

Otherwise, EMC scaling rates are limited by boot PLLM rate (this is
backward compatible with current EMC maximum rate limitations).

Bug 1193281

Change-Id: I0c8b11b8866fe8b2c82dec5a344c04e7feee3c46
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/172141
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

arch/arm/mach-tegra/board.h
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/tegra11_clocks.c
arch/arm/mach-tegra/tegra11_emc.c

index a31ad38..55d417c 100644 (file)
@@ -202,6 +202,7 @@ enum power_supply_type get_power_supply_type(void);
 enum audio_codec_type get_audio_codec_type(void);
 int get_maximum_cpu_current_supported(void);
 int get_maximum_core_current_supported(void);
+int get_emc_max_dvfs(void);
 void tegra_enable_pinmux(void);
 enum image_type get_tegra_image_type(void);
 int tegra_get_cvb_alignment_uV(void);
index 27fa900..2d38b0c 100644 (file)
@@ -765,7 +765,7 @@ int tegra_clk_shared_bus_update(struct clk *c)
 }
 
 /* dvfs initialization may lower default maximum rate */
-void __init tegra_init_max_rate(struct clk *c, unsigned long max_rate)
+void tegra_init_max_rate(struct clk *c, unsigned long max_rate)
 {
        struct clk *shared_bus_user;
 
index 23b7eac..8005ee9 100644 (file)
@@ -190,6 +190,7 @@ static enum audio_codec_type audio_codec_name;
 static enum image_type board_image_type = system_image;
 static int max_cpu_current;
 static int max_core_current;
+static int emc_max_dvfs;
 static int usb_port_owner_info;
 
 #ifdef CONFIG_ARCH_TEGRA_11x_SOC
@@ -805,6 +806,18 @@ static int __init tegra_max_core_current(char *options)
 }
 __setup("core_edp_ma=", tegra_max_core_current);
 
+int get_emc_max_dvfs(void)
+{
+       return emc_max_dvfs;
+}
+static int __init tegra_emc_max_dvfs(char *options)
+{
+       char *p = options;
+       emc_max_dvfs = memparse(p, &p);
+       return 1;
+}
+__setup("emc_max_dvfs", tegra_emc_max_dvfs);
+
 static int __init tegra_debug_uartport(char *info)
 {
        char *p = info;
index a0ae2e8..b7040a5 100644 (file)
@@ -4135,7 +4135,6 @@ static void tegra11_emc_clk_init(struct clk *c)
 {
        tegra11_periph_clk_init(c);
        tegra_emc_dram_type_init(c);
-       c->max_rate = clk_get_rate(c->parent);
 }
 
 static long tegra11_emc_clk_round_rate(struct clk *c, unsigned long rate)
index 9f420aa..263406e 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "clock.h"
 #include "dvfs.h"
+#include "board.h"
 #include "tegra11_emc.h"
 
 #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
@@ -1026,6 +1027,7 @@ static int init_emc_table(const struct tegra11_emc_table *table, int table_size)
        int i, mv;
        u32 reg;
        bool max_entry = false;
+       bool emc_max_dvfs_sel = get_emc_max_dvfs();
        unsigned long boot_rate, max_rate;
        struct clk *pll_c = tegra_get_clock_by_name("pll_c");
 
@@ -1034,9 +1036,6 @@ static int init_emc_table(const struct tegra11_emc_table *table, int table_size)
        emc_stats.last_update = get_jiffies_64();
        emc_stats.last_sel = TEGRA_EMC_TABLE_MAX_SIZE;
 
-       boot_rate = clk_get_rate(emc) / 1000;
-       max_rate = clk_get_max_rate(emc) / 1000;
-
        if ((dram_type != DRAM_TYPE_DDR3) && (dram_type != DRAM_TYPE_LPDDR2)) {
                pr_err("tegra: not supported DRAM type %u\n", dram_type);
                return -ENODATA;
@@ -1053,6 +1052,9 @@ static int init_emc_table(const struct tegra11_emc_table *table, int table_size)
                return -ENODATA;
        }
 
+       boot_rate = clk_get_rate(emc) / 1000;
+       max_rate = clk_get_rate(emc->parent) / 1000;
+
        tegra_emc_table_size = min(table_size, TEGRA_EMC_TABLE_MAX_SIZE);
        switch (table[0].rev) {
        case 0x40:
@@ -1084,7 +1086,14 @@ static int init_emc_table(const struct tegra11_emc_table *table, int table_size)
                if (table_rate == boot_rate)
                        emc_stats.last_sel = i;
 
-               if (table_rate == max_rate) {
+               if (emc_max_dvfs_sel) {
+                       /* EMC max rate = max table entry above boot pll_m */
+                       if (table_rate >= max_rate) {
+                               max_rate = table_rate;
+                               max_entry = true;
+                       }
+               } else if (table_rate == max_rate) {
+                       /* EMC max rate = boot pll_m rate */
                        max_entry = true;
                        break;
                }
@@ -1096,6 +1105,7 @@ static int init_emc_table(const struct tegra11_emc_table *table, int table_size)
                       " %lu kHz is not found\n", max_rate);
                return -ENODATA;
        }
+       tegra_init_max_rate(emc, max_rate * 1000);
 
        tegra_emc_table = table;