arm: tegra: la: Add latency allowance support for T11x.
[linux-3.10.git] / arch / arm / mach-tegra / latency_allowance.c
index 22375af..9222819 100644 (file)
@@ -31,6 +31,7 @@
 #include <mach/latency_allowance.h>
 #include "la_priv_common.h"
 #include "tegra3_la_priv.h"
+#include "tegra11x_la_priv.h"
 
 #define ENABLE_LA_DEBUG                0
 #define TEST_LA_CODE           0
 #define HACK_LA_FIFO 1
 
 static struct dentry *latency_debug_dir;
-
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
 static DEFINE_SPINLOCK(safety_lock);
-#endif
-
-static int la_scaling_enable_count;
-
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
 static unsigned short id_to_index[ID(MAX_ID) + 1];
 static struct la_scaling_info scaling_info[TEGRA_LA_MAX_ID];
+static int la_scaling_enable_count;
 
 #define VALIDATE_ID(id) \
        do { \
@@ -76,6 +71,62 @@ static struct la_scaling_info scaling_info[TEGRA_LA_MAX_ID];
                        return -EINVAL; \
        } while (0)
 
+/* Sets latency allowance based on clients memory bandwitdh requirement.
+ * Bandwidth passed is in mega bytes per second.
+ */
+int tegra_set_latency_allowance(enum tegra_la_id id,
+                               unsigned int bandwidth_in_mbps)
+{
+       int ideal_la;
+       int la_to_set;
+       unsigned long reg_read;
+       unsigned long reg_write;
+       unsigned int fifo_size_in_atoms;
+       int bytes_per_atom = normal_atom_size;
+       const int fifo_scale = 4;               /* 25% of the FIFO */
+       struct la_client_info *ci;
+       int idx = id_to_index[id];
+
+       VALIDATE_ID(id);
+       VALIDATE_BW(bandwidth_in_mbps);
+
+       ci = &la_info_array[idx];
+       fifo_size_in_atoms = ci->fifo_size_in_atoms;
+
+#if HACK_LA_FIFO
+       /* pretend that our FIFO is only as deep as the lowest fullness
+        * we expect to see */
+       if (id >= ID(DISPLAY_0A) && id <= ID(DISPLAY_HCB))
+               fifo_size_in_atoms /= fifo_scale;
+#endif
+
+       if (bandwidth_in_mbps == 0) {
+               la_to_set = MC_LA_MAX_VALUE;
+       } else {
+               ideal_la = (fifo_size_in_atoms * bytes_per_atom * 1000) /
+                          (bandwidth_in_mbps * ns_per_tick);
+               la_to_set = ideal_la - (ci->expiration_in_ns/ns_per_tick) - 1;
+       }
+
+       la_debug("\n%s:id=%d,idx=%d, bw=%dmbps, la_to_set=%d",
+               __func__, id, idx, bandwidth_in_mbps, la_to_set);
+       la_to_set = (la_to_set < 0) ? 0 : la_to_set;
+       la_to_set = (la_to_set > MC_LA_MAX_VALUE) ? MC_LA_MAX_VALUE : la_to_set;
+       scaling_info[idx].actual_la_to_set = la_to_set;
+
+       spin_lock(&safety_lock);
+       reg_read = readl(ci->reg_addr);
+       reg_write = (reg_read & ~ci->mask) |
+                       (la_to_set << ci->shift);
+       writel(reg_write, ci->reg_addr);
+       scaling_info[idx].la_set = la_to_set;
+       la_debug("reg_addr=0x%x, read=0x%x, write=0x%x",
+               (u32)ci->reg_addr, (u32)reg_read, (u32)reg_write);
+       spin_unlock(&safety_lock);
+       return 0;
+}
+
+#if defined(CONFIG_TEGRA_LATENCY_ALLOWANCE_SCALING)
 static void set_thresholds(struct la_scaling_reg_info *info,
                            enum tegra_la_id id)
 {
@@ -134,61 +185,6 @@ static void set_vi_latency_thresholds(enum tegra_la_id id)
        set_thresholds(&vi_info[id - ID(VI_WSB)], id);
 }
 
-/* Sets latency allowance based on clients memory bandwitdh requirement.
- * Bandwidth passed is in mega bytes per second.
- */
-int tegra_set_latency_allowance(enum tegra_la_id id,
-                               unsigned int bandwidth_in_mbps)
-{
-       int ideal_la;
-       int la_to_set;
-       unsigned long reg_read;
-       unsigned long reg_write;
-       unsigned int fifo_size_in_atoms;
-       int bytes_per_atom = normal_atom_size;
-       const int fifo_scale = 4;               /* 25% of the FIFO */
-       struct la_client_info *ci;
-       int idx = id_to_index[id];
-
-       VALIDATE_ID(id);
-       VALIDATE_BW(bandwidth_in_mbps);
-
-       ci = &la_info_array[idx];
-       fifo_size_in_atoms = ci->fifo_size_in_atoms;
-
-#if HACK_LA_FIFO
-       /* pretend that our FIFO is only as deep as the lowest fullness
-        * we expect to see */
-       if (id >= ID(DISPLAY_0A) && id <= ID(DISPLAY_HCB))
-               fifo_size_in_atoms /= fifo_scale;
-#endif
-
-       if (bandwidth_in_mbps == 0) {
-               la_to_set = MC_LA_MAX_VALUE;
-       } else {
-               ideal_la = (fifo_size_in_atoms * bytes_per_atom * 1000) /
-                          (bandwidth_in_mbps * ns_per_tick);
-               la_to_set = ideal_la - (ci->expiration_in_ns/ns_per_tick) - 1;
-       }
-
-       la_debug("\n%s:id=%d,idx=%d, bw=%dmbps, la_to_set=%d",
-               __func__, id, idx, bandwidth_in_mbps, la_to_set);
-       la_to_set = (la_to_set < 0) ? 0 : la_to_set;
-       la_to_set = (la_to_set > MC_LA_MAX_VALUE) ? MC_LA_MAX_VALUE : la_to_set;
-       scaling_info[idx].actual_la_to_set = la_to_set;
-
-       spin_lock(&safety_lock);
-       reg_read = readl(ci->reg_addr);
-       reg_write = (reg_read & ~ci->mask) |
-                       (la_to_set << ci->shift);
-       writel(reg_write, ci->reg_addr);
-       scaling_info[idx].la_set = la_to_set;
-       la_debug("reg_addr=0x%x, read=0x%x, write=0x%x",
-               (u32)ci->reg_addr, (u32)reg_read, (u32)reg_write);
-       spin_unlock(&safety_lock);
-       return 0;
-}
-
 /* Thresholds for scaling are specified in % of fifo freeness.
  * If threshold_low is specified as 20%, it means when the fifo free
  * between 0 to 20%, use la as programmed_la.
@@ -264,6 +260,37 @@ void tegra_disable_latency_scaling(enum tegra_la_id id)
 }
 #endif
 
+void tegra_latency_allowance_update_tick_length(unsigned int new_ns_per_tick)
+{
+       int i = 0;
+       int la;
+       unsigned long reg_read;
+       unsigned long reg_write;
+       unsigned long scale_factor = new_ns_per_tick / ns_per_tick;
+
+       if (scale_factor > 1) {
+               spin_lock(&safety_lock);
+               ns_per_tick = new_ns_per_tick;
+               for (i = 0; i < ARRAY_SIZE(la_info_array) - 1; i++) {
+                       reg_read = readl(la_info_array[i].reg_addr);
+                       la = ((reg_read & la_info_array[i].mask) >>
+                               la_info_array[i].shift) / scale_factor;
+
+                       reg_write = (reg_read & ~la_info_array[i].mask) |
+                                       (la << la_info_array[i].shift);
+                       writel(reg_write, la_info_array[i].reg_addr);
+                       scaling_info[i].la_set = la;
+               }
+               spin_unlock(&safety_lock);
+
+               /* Re-scale G2PR, G2SR, G2DR, G2DW with updated ns_per_tick */
+               tegra_set_latency_allowance(TEGRA_LA_G2PR, 20);
+               tegra_set_latency_allowance(TEGRA_LA_G2SR, 20);
+               tegra_set_latency_allowance(TEGRA_LA_G2DR, 20);
+               tegra_set_latency_allowance(TEGRA_LA_G2DW, 20);
+       }
+}
+
 static int la_regs_show(struct seq_file *s, void *unused)
 {
        unsigned i;