ARM: tegra: power: Restore Tegra3 MC registers after LP0
Alex Frid [Thu, 15 Sep 2011 05:27:07 +0000 (22:27 -0700)]
On exit from deep sleep (LP0) restore from SDRAM Tegra3 MC registers
that are not saved in PMC scratch file for boot-rom restoration. Since
SDRAM after LP0 is running at boot rate, MC registers are saved only
once during initialization.

Bug 874351

(ported from commit 99966c242920978a92f3f51e5957ada30afc4b1d)

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

Rebase-Id: R272136c877818d44b0cf28f8b5f720af71623301

arch/arm/mach-tegra/common-t3.c
arch/arm/mach-tegra/pm-t3.c
arch/arm/mach-tegra/tegra3_emc.h

index 867217a..6317a2e 100644 (file)
 #define MC_ERROR_STATUS                        0x8
 #define MC_ERROR_ADDRESS               0xC
 
+#define MC_TIMING_REG_NUM1 \
+       ((MC_EMEM_ARB_TIMING_W2R - MC_EMEM_ARB_CFG) / 4 + 1)
+#define MC_TIMING_REG_NUM2 \
+       ((MC_EMEM_ARB_MISC1 - MC_EMEM_ARB_DA_TURNS) / 4 + 1)
+
 struct mc_client {
        const char *name;
 };
@@ -49,6 +54,57 @@ struct mc_client {
                .name = _name,          \
        }
 
+
+static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
+
+
+#ifdef CONFIG_PM_SLEEP
+static u32 mc_boot_timing[MC_TIMING_REG_NUM1 + MC_TIMING_REG_NUM2 + 4];
+
+static void tegra_mc_timing_save(void)
+{
+       u32 off;
+       u32 *ctx = mc_boot_timing;
+
+       for (off = MC_EMEM_ARB_CFG; off <= MC_EMEM_ARB_TIMING_W2R; off += 4)
+               *ctx++ = readl(mc + off);
+
+       for (off = MC_EMEM_ARB_DA_TURNS; off <= MC_EMEM_ARB_MISC1; off += 4)
+               *ctx++ = readl(mc + off);
+
+       *ctx++ = readl(mc + MC_EMEM_ARB_RING3_THROTTLE);
+       *ctx++ = readl(mc + MC_EMEM_ARB_OVERRIDE);
+       *ctx++ = readl(mc + MC_RESERVED_RSV);
+
+       *ctx++ = readl(mc + MC_INT_MASK);
+}
+
+void tegra_mc_timing_restore(void)
+{
+       u32 off;
+       u32 *ctx = mc_boot_timing;
+
+       for (off = MC_EMEM_ARB_CFG; off <= MC_EMEM_ARB_TIMING_W2R; off += 4)
+               __raw_writel(*ctx++, mc + off);
+
+       for (off = MC_EMEM_ARB_DA_TURNS; off <= MC_EMEM_ARB_MISC1; off += 4)
+               __raw_writel(*ctx++, mc + off);
+
+       __raw_writel(*ctx++, mc + MC_EMEM_ARB_RING3_THROTTLE);
+       __raw_writel(*ctx++, mc + MC_EMEM_ARB_OVERRIDE);
+       __raw_writel(*ctx++, mc + MC_RESERVED_RSV);
+
+       writel(*ctx++, mc + MC_INT_MASK);
+       off = readl(mc + MC_INT_MASK);
+
+       writel(0x1, mc + MC_TIMING_CONTROL);
+       off = readl(mc + MC_TIMING_CONTROL);
+}
+#else
+#define tegra_mc_timing_save()
+#endif
+
+
 static const struct mc_client mc_clients[] = {
        client("ptc"),
        client("display0_wina"), client("display1_wina"),
@@ -115,7 +171,6 @@ static DECLARE_DELAYED_WORK(unthrottle_prints_work, unthrottle_prints);
 
 static irqreturn_t tegra_mc_error_isr(int irq, void *data)
 {
-       void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
        const struct mc_client *client = NULL;
        const char *mc_err;
        const char *mc_err_info;
@@ -187,7 +242,6 @@ out:
 
 static int __init tegra30_mc_init(void)
 {
-       void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
        u32 reg;
        int ret = 0;
 
@@ -207,6 +261,7 @@ static int __init tegra30_mc_init(void)
                                MC_INT_INVALID_SMMU_PAGE;
                writel(reg, mc + MC_INT_MASK);
        }
+       tegra_mc_timing_save();
 
        return ret;
 }
index 8a49c6a..1168415 100644 (file)
@@ -370,21 +370,17 @@ int tegra_cluster_control(unsigned int us, unsigned int flags)
 #endif
 
 #ifdef CONFIG_PM_SLEEP
-static u32 mc_reserved_rsv;
-static u32 mc_emem_arb_override;
 
 void tegra_lp0_suspend_mc(void)
 {
-       void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
-       mc_reserved_rsv = readl(mc + MC_RESERVED_RSV);
-       mc_emem_arb_override = readl(mc + MC_EMEM_ARB_OVERRIDE);
+       /* Since memory frequency after LP0 is restored to boot rate
+          mc timing is saved during init, not on entry to LP0. Keep
+          this hook just in case, anyway */
 }
 
 void tegra_lp0_resume_mc(void)
 {
-       void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
-       writel(mc_reserved_rsv, mc + MC_RESERVED_RSV);
-       writel(mc_emem_arb_override, mc + MC_EMEM_ARB_OVERRIDE);
+       tegra_mc_timing_restore();
 }
 
 void tegra_lp0_cpu_mode(bool enter)
index 455982a..4c854bb 100644 (file)
 
 int tegra_emc_get_dram_type(void);
 
+#ifdef CONFIG_PM_SLEEP
+void tegra_mc_timing_restore(void);
+#else
+static inline void tegra_mc_timing_restore(void)
+{ }
+#endif
+
 #define EMC_INTSTATUS                          0x0
 #define EMC_INTSTATUS_CLKCHANGE_COMPLETE       (0x1 << 4)
 
@@ -232,8 +239,11 @@ enum {
 #define MC_EMEM_ARB_DA_COVERS                  0xd4
 #define MC_EMEM_ARB_MISC0                      0xd8
 #define MC_EMEM_ARB_MISC0_EMC_SAME_FREQ                (0x1 << 27)
+#define MC_EMEM_ARB_MISC1                      0xdc
 #define MC_EMEM_ARB_RING1_THROTTLE             0xe0
+#define MC_EMEM_ARB_RING3_THROTTLE             0xe4
 #define MC_EMEM_ARB_OVERRIDE                   0xe8
+#define MC_TIMING_CONTROL                      0xfc
 #define MC_RESERVED_RSV                                0x3fc
 
 #endif