summaryrefslogtreecommitdiff
path: root/target/linux/s3c24xx/patches/0180-fix-glamo-suspend-resume-dram-and-engines.patch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/s3c24xx/patches/0180-fix-glamo-suspend-resume-dram-and-engines.patch.patch')
-rwxr-xr-xtarget/linux/s3c24xx/patches/0180-fix-glamo-suspend-resume-dram-and-engines.patch.patch431
1 files changed, 431 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches/0180-fix-glamo-suspend-resume-dram-and-engines.patch.patch b/target/linux/s3c24xx/patches/0180-fix-glamo-suspend-resume-dram-and-engines.patch.patch
new file mode 100755
index 0000000000..7759c065d6
--- /dev/null
+++ b/target/linux/s3c24xx/patches/0180-fix-glamo-suspend-resume-dram-and-engines.patch.patch
@@ -0,0 +1,431 @@
+From 9ada9a3247ca02a0dddeae24a07a2744690aeb51 Mon Sep 17 00:00:00 2001
+From: Andy Green <andy@openmoko.com>
+Date: Fri, 25 Jul 2008 23:06:15 +0100
+Subject: [PATCH] fix-glamo-suspend-resume-dram-and-engines.patch
+
+Two issues... we never took care to take down engines in suspend
+and bring them back in resume. This was part of the display
+corruption that could be seen briefly on resume. The other issue
+that made the "noise" corruption was bad ordering of resume steps.
+
+This patch simplifies (removing needless re-init) resume actions
+and makes explicit the suspend and resume steps. It also adds
+code to track which engines are up and push them down in suspend
+and bring them back in resume.
+
+The result is no more corruption of display buffer in suspend, it
+comes back completely clean.
+
+Signed-off-by: Andy Green <andy@openmoko.com>
+---
+ drivers/mfd/glamo/glamo-core.c | 269 +++++++++++++++++++---------------------
+ drivers/mfd/glamo/glamo-core.h | 2 +
+ drivers/mfd/glamo/glamo-regs.h | 6 +-
+ 3 files changed, 137 insertions(+), 140 deletions(-)
+
+diff --git a/drivers/mfd/glamo/glamo-core.c b/drivers/mfd/glamo/glamo-core.c
+index d4b526d..ee33901 100644
+--- a/drivers/mfd/glamo/glamo-core.c
++++ b/drivers/mfd/glamo/glamo-core.c
+@@ -54,6 +54,8 @@
+
+ #define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)
+
++#define GLAMO_MEM_REFRESH_COUNT 0x100
++
+ static struct glamo_core *glamo_handle;
+
+ static inline void __reg_write(struct glamo_core *glamo,
+@@ -381,9 +383,8 @@ out_unlock:
+ * 'engine' support
+ ***********************************************************************/
+
+-int glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine)
++int __glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine)
+ {
+- spin_lock(&glamo->lock);
+ switch (engine) {
+ case GLAMO_ENGINE_LCD:
+ __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_LCD,
+@@ -432,27 +433,59 @@ int glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine)
+ default:
+ break;
+ }
+- spin_unlock(&glamo->lock);
++
++ glamo->engine_enabled_bitfield |= 1 << engine;
+
+ return 0;
+ }
+-EXPORT_SYMBOL_GPL(glamo_engine_enable);
+
+-int glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine)
++int glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine)
+ {
++ int ret;
++
+ spin_lock(&glamo->lock);
++
++ ret = __glamo_engine_enable(glamo, engine);
++
++ spin_unlock(&glamo->lock);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(glamo_engine_enable);
++
++int __glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine)
++{
+ switch (engine) {
++ case GLAMO_ENGINE_LCD:
++ /* remove pixel clock to LCM */
++ __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_LCD,
++ GLAMO_CLOCK_LCD_EN_DCLK, 0);
++ __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_LCD,
++ GLAMO_CLOCK_LCD_EN_DHCLK |
++ GLAMO_CLOCK_LCD_EN_DMCLK, 0);
++ /* kill memory clock */
++ __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_LCD,
++ GLAMO_CLOCK_LCD_EN_M5CLK, 0);
++ /* stop dividing the clocks */
++ __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_GEN5_1,
++ GLAMO_CLOCK_GEN51_EN_DIV_DHCLK |
++ GLAMO_CLOCK_GEN51_EN_DIV_DMCLK |
++ GLAMO_CLOCK_GEN51_EN_DIV_DCLK, 0);
++ __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2),
++ GLAMO_HOSTBUS2_MMIO_EN_LCD, 0);
++ break;
++
+ case GLAMO_ENGINE_MMC:
+ __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MMC, 0,
+ GLAMO_CLOCK_MMC_EN_M9CLK |
+ GLAMO_CLOCK_MMC_EN_TCLK |
+ GLAMO_CLOCK_MMC_DG_M9CLK |
+ GLAMO_CLOCK_MMC_DG_TCLK);
+- __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2), 0,
+- GLAMO_HOSTBUS2_MMIO_EN_MMC);
+ /* disable the TCLK divider clk input */
+ __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_GEN5_1, 0,
+ GLAMO_CLOCK_GEN51_EN_DIV_TCLK);
++ __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2), 0,
++ GLAMO_HOSTBUS2_MMIO_EN_MMC);
+ /* good idea to hold the thing in reset when we power it off? */
+ /* writew(readw(glamo->base + GLAMO_REG_CLOCK_MMC) |
+ GLAMO_CLOCK_MMC_RESET, glamo->base + GLAMO_REG_CLOCK_MMC);
+@@ -461,10 +494,23 @@ int glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine)
+ default:
+ break;
+ }
+- spin_unlock(&glamo->lock);
++
++ glamo->engine_enabled_bitfield &= ~(1 << engine);
+
+ return 0;
+ }
++int glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine)
++{
++ int ret;
++
++ spin_lock(&glamo->lock);
++
++ ret = __glamo_engine_disable(glamo, engine);
++
++ spin_unlock(&glamo->lock);
++
++ return ret;
++}
+ EXPORT_SYMBOL_GPL(glamo_engine_disable);
+
+ struct glamo_script reset_regs[] = {
+@@ -618,7 +664,7 @@ int glamo_run_script(struct glamo_core *glamo, struct glamo_script *script,
+ if (may_sleep)
+ msleep(line->val);
+ else
+- mdelay(line->val);
++ mdelay(line->val * 4);
+ break;
+ case 0xfffd:
+ /* spin until PLLs lock */
+@@ -717,111 +763,17 @@ static struct glamo_script glamo_init_script[] = {
+ { GLAMO_REG_CLOCK_MEMORY, 0x000b },
+ };
+
+-static struct glamo_script glamo_resume_script[] = {
+- { GLAMO_REG_IRQ_ENABLE, 0x01ff },
+- { GLAMO_REG_CLOCK_GEN6, 0x2000 },
+- { GLAMO_REG_CLOCK_GEN7, 0x0001 }, /* 0101 */
+- { GLAMO_REG_CLOCK_GEN8, 0x0100 },
+- { GLAMO_REG_CLOCK_HOST, 0x000d },
+- { 0x200, 0x0ef0 },
+- { 0x202, 0x07ff },
+- { 0x212, 0x0000 },
+- { 0x214, 0x4000 },
+- { 0x216, 0xf00e },
+- { GLAMO_REG_MEM_TYPE, 0x0874 }, /* 8MB, 16 word pg wr+rd */
+- { GLAMO_REG_MEM_GEN, 0xafaf }, /* 63 grants min + max */
+-
+- { GLAMO_REG_MEM_TIMING1, 0x0108 },
+- { GLAMO_REG_MEM_TIMING2, 0x0010 }, /* Taa = 3 MCLK */
+- { GLAMO_REG_MEM_TIMING3, 0x0000 },
+- { GLAMO_REG_MEM_TIMING4, 0x0000 }, /* CE1# delay fall/rise */
+- { GLAMO_REG_MEM_TIMING5, 0x0000 }, /* UB# LB# */
+- { GLAMO_REG_MEM_TIMING6, 0x0000 }, /* OE# */
+- { GLAMO_REG_MEM_TIMING7, 0x0000 }, /* WE# */
+- { GLAMO_REG_MEM_TIMING8, 0x1002 }, /* MCLK delay, was 0x1000 */
+- { GLAMO_REG_MEM_TIMING9, 0x6006 },
+- { GLAMO_REG_MEM_TIMING10, 0x00ff },
+- { GLAMO_REG_MEM_TIMING11, 0x0001 },
+- { GLAMO_REG_MEM_POWER1, 0x0020 },
+- { GLAMO_REG_MEM_POWER2, 0x0000 },
+- { GLAMO_REG_MEM_DRAM1, 0x0000 },
+- { 0xfffe, 1 },
+- { GLAMO_REG_MEM_DRAM1, 0xc100 },
+- { 0xfffe, 1 },
+- { GLAMO_REG_MEM_DRAM1, 0xe100 },
+- { GLAMO_REG_MEM_DRAM2, 0x01d6 },
+- { GLAMO_REG_CLOCK_MEMORY, 0x000b },
+-};
+-
+-#if 0 /* MM370 */
+-static const struct glamo_script regs_vram_2mb = {
+- { GLAMO_REG_CLOCK_MEMORY, 0x3aaa },
+- { 0xfffe, 50 },
+- { GLAMO_REG_CLOCK_MEMORY, 0x0aaa },
+- { 0xfffe, 3 },
+- { GLAMO_REG_MEM_POWER1, 0x0020 },
+- { 0x033a, 0x0000 },
+- { 0x033c, 0x0000 },
+- { 0x033e, 0x0000 },
+- { 0x0340, 0x0000 },
+- { 0x0342, 0x0000 },
+- { 0x0344, 0x0000 },
+- { 0x0346, 0x0240 },
+- { GLAMO_REG_MEM_TIMING8, 0x1016 },
+- { GLAMO_REG_MEM_TIMING9, 0x6067 },
+- { GLAMO_REG_MEM_TIMING10, 0x00ff },
+- { GLAMO_REG_MEM_TIMING11, 0x0030 },
+- { GLAMO_REG_MEM_GEN, 0x3fff },
+- { GLAMO_REG_MEM_GEN, 0xafaf },
+- { GLAMO_REG_MEM_TIMING1, 0x0108 },
+- { GLAMO_REG_MEM_TIMING2, 0x0010 },
+- { GLAMO_REG_MEM_DRAM1, 0x0a00 },
+- { 0xfffe, 3 },
+- { GLAMO_REG_MEM_DRAM1, 0xe200 },
+- { 0xfffe, 1 },
+-};
+-
+-static const struct glamo_script regs_vram_8mb = {
+- { GLAMO_REG_CLOCK_MEMORY, 0x3aaa },
+- { 0xfffe, 50 },
+- { GLAMO_REG_CLOCK_MEMORY, 0x0aaa },
+- { 0xfffe, 3 },
+- { GLAMO_REG_MEM_POWER1, 0x0020 },
+- { 0x033a, 0x45cf },
+- { 0x033c, 0x4240 },
+- { 0x033e, 0x53e0 },
+- { 0x0340, 0x1401 },
+- { 0x0342, 0x0c44 },
+- { 0x0344, 0x1d0b },
+- { 0x0346, 0x25ac },
+- { 0x0348, 0x1953 },
+- { 0xfffe, 1 },
+- { GLAMO_REG_MEM_TYPE, 0x087a },
+- { GLAMO_REG_MEM_DRAM2, 0x01d6 },
+- { GLAMO_REG_MEM_TIMING8, 0x1060 },
+- { GLAMO_REG_MEM_TIMING9, 0x6067 },
+- { GLAMO_REG_MEM_TIMING10, 0x00ff },
+- { GLAMO_REG_MEM_TIMING11, 0x0030 },
+- { GLAMO_REG_MEM_GEN, 0x3fff },
+- { GLAMO_REG_MEM_GEN, 0xafaf },
+- { GLAMO_REG_MEM_TIMING1, 0x3108 },
+- { GLAMO_REG_MEM_TIMING2, 0x0010 },
+- { GLAMO_REG_MEM_DRAM1, 0x0a00 },
+- { 0xfffe, 3 },
+- { GLAMO_REG_MEM_DRAM1, 0xe200 },
+- { 0xfffe, 1 },
+-};
+-#endif
+
+ enum glamo_power {
+ GLAMO_POWER_ON,
+- GLAMO_POWER_STANDBY,
+ GLAMO_POWER_SUSPEND,
+ };
+
+ static void glamo_power(struct glamo_core *glamo,
+ enum glamo_power new_state)
+ {
++ int n;
++
+ spin_lock(&glamo->lock);
+
+ dev_dbg(&glamo->pdev->dev, "***** glamo_power -> %d\n", new_state);
+@@ -836,37 +788,76 @@ static void glamo_power(struct glamo_core *glamo,
+ while ((__reg_read(glamo, GLAMO_REG_PLL_GEN5) & 3) != 3)
+ ;
+
+- /* enable memory clock and get it out of deep pwrdown */
+- __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
+- GLAMO_CLOCK_MEM_EN_MOCACLK, 0xffff);
+- __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM2,
+- GLAMO_MEM_DRAM2_DEEP_PWRDOWN, 0x0000);
+- __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM1,
+- GLAMO_MEM_DRAM1_SELF_REFRESH, 0x0000);
+-
+- glamo_run_script(glamo, glamo_resume_script,
+- ARRAY_SIZE(glamo_resume_script), 0);
+-
+- break;
+-
+- case GLAMO_POWER_STANDBY:
+- /* enable memory self-refresh */
+- __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM1,
+- GLAMO_MEM_DRAM1_SELF_REFRESH, 0xffff);
+- /* stop memory clock */
+- __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
+- GLAMO_CLOCK_MEM_EN_MOCACLK, 0x0000);
+- /* power down PLL2 and then PLL1 */
+- __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 0x2000, 0xffff);
+- __reg_set_bit_mask(glamo, GLAMO_REG_DFT_GEN5, 0x0001, 0xffff);
++ /* Get memory out of deep powerdown */
++
++ __reg_write(glamo, GLAMO_REG_MEM_DRAM2,
++ (7 << 6) | /* tRC */
++ (1 << 4) | /* tRP */
++ (1 << 2) | /* tRCD */
++ 2); /* CAS latency */
++
++ /* Stop self-refresh */
++
++ __reg_write(glamo, GLAMO_REG_MEM_DRAM1,
++ GLAMO_MEM_DRAM1_EN_DRAM_REFRESH |
++ GLAMO_MEM_DRAM1_EN_GATE_CKE |
++ GLAMO_MEM_REFRESH_COUNT);
++ __reg_write(glamo, GLAMO_REG_MEM_DRAM1,
++ GLAMO_MEM_DRAM1_EN_MODEREG_SET |
++ GLAMO_MEM_DRAM1_EN_DRAM_REFRESH |
++ GLAMO_MEM_DRAM1_EN_GATE_CKE |
++ GLAMO_MEM_REFRESH_COUNT);
++
++ /* re-enable clocks to memory */
++
++ __reg_write(glamo, GLAMO_REG_CLOCK_MEMORY,
++ GLAMO_CLOCK_MEM_EN_MOCACLK |
++ GLAMO_CLOCK_MEM_EN_M1CLK |
++ GLAMO_CLOCK_MEM_DG_M1CLK);
++
++ /* restore each engine that was up before suspend */
++ for (n = 0; n < __NUM_GLAMO_ENGINES; n++)
++ if (glamo->engine_enabled_bitfield_suspend & (1 << n))
++ __glamo_engine_enable(glamo, n);
+ break;
+
+ case GLAMO_POWER_SUSPEND:
+- __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM2,
+- GLAMO_MEM_DRAM2_DEEP_PWRDOWN, 0xffff);
+- /* stop memory clock */
+- __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
+- GLAMO_CLOCK_MEM_EN_MOCACLK, 0x0000);
++ /* stash a copy of which engines were running */
++ glamo->engine_enabled_bitfield_suspend =
++ glamo->engine_enabled_bitfield;
++
++ /* take down each engine before we kill mem and pll */
++ for (n = 0; n < __NUM_GLAMO_ENGINES; n++)
++ if (glamo->engine_enabled_bitfield & (1 << n))
++ __glamo_engine_disable(glamo, n);
++
++ /* enable self-refresh */
++
++ __reg_write(glamo, GLAMO_REG_MEM_DRAM1,
++ GLAMO_MEM_DRAM1_EN_DRAM_REFRESH |
++ GLAMO_MEM_DRAM1_EN_GATE_CKE |
++ GLAMO_MEM_DRAM1_SELF_REFRESH |
++ GLAMO_MEM_REFRESH_COUNT);
++ __reg_write(glamo, GLAMO_REG_MEM_DRAM1,
++ GLAMO_MEM_DRAM1_EN_MODEREG_SET |
++ GLAMO_MEM_DRAM1_EN_DRAM_REFRESH |
++ GLAMO_MEM_DRAM1_EN_GATE_CKE |
++ GLAMO_MEM_DRAM1_SELF_REFRESH |
++ GLAMO_MEM_REFRESH_COUNT);
++
++ /* force RAM into deep powerdown */
++
++ __reg_write(glamo, GLAMO_REG_MEM_DRAM2,
++ GLAMO_MEM_DRAM2_DEEP_PWRDOWN |
++ (7 << 6) | /* tRC */
++ (1 << 4) | /* tRP */
++ (1 << 2) | /* tRCD */
++ 2); /* CAS latency */
++
++ /* kill clocks to memory */
++
++ __reg_write(glamo, GLAMO_REG_CLOCK_MEMORY, 0);
++
+ /* power down PLL2 and then PLL1 */
+ __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 0x2000, 0xffff);
+ __reg_set_bit_mask(glamo, GLAMO_REG_DFT_GEN5, 0x0001, 0xffff);
+@@ -1016,15 +1007,15 @@ static ssize_t regs_read(struct device *dev, struct device_attribute *attr,
+ char * name;
+ };
+ struct reg_range reg_range[] = {
+-/* { 0x0000, 0x200, "General" },
+- { 0x0200, 0x100, "Host Bus" },
+- { 0x0300, 0x100, "Memory" },
+- { 0x0400, 0x100, "Sensor" },
++ { 0x0000, 0x76, "General" },
++/* { 0x0200, 0x100, "Host Bus" },
++*/ { 0x0300, 0x38, "Memory" },
++/* { 0x0400, 0x100, "Sensor" },
+ { 0x0500, 0x300, "ISP" },
+ { 0x0800, 0x400, "JPEG" },
+ { 0x0c00, 0x500, "MPEG" },
+ */
+- { 0x1100, 0x400, "LCD" },
++ { 0x1100, 0x88, "LCD" },
+ /*
+ { 0x1500, 0x080, "MPU 0" },
+ { 0x1580, 0x080, "MPU 1" },
+@@ -1039,7 +1030,7 @@ static ssize_t regs_read(struct device *dev, struct device_attribute *attr,
+
+ for (r = 0; r < ARRAY_SIZE(reg_range); r++) {
+ n1 = 0;
+- end += sprintf(end, "\n%s\n\n", reg_range[r].name);
++ end += sprintf(end, "\n%s\n", reg_range[r].name);
+ for (n = reg_range[r].start;
+ n < reg_range[r].start + reg_range[r].count; n += 2) {
+ if (((n1++) & 7) == 0)
+diff --git a/drivers/mfd/glamo/glamo-core.h b/drivers/mfd/glamo/glamo-core.h
+index b1531b3..c89f810 100644
+--- a/drivers/mfd/glamo/glamo-core.h
++++ b/drivers/mfd/glamo/glamo-core.h
+@@ -30,6 +30,8 @@ struct glamo_core {
+ u_int16_t revision;
+ spinlock_t lock;
+ struct resume_dependency resume_dependency;
++ u32 engine_enabled_bitfield;
++ u32 engine_enabled_bitfield_suspend;
+ };
+
+ struct glamo_script {
+diff --git a/drivers/mfd/glamo/glamo-regs.h b/drivers/mfd/glamo/glamo-regs.h
+index 32411e3..2328b8a 100644
+--- a/drivers/mfd/glamo/glamo-regs.h
++++ b/drivers/mfd/glamo/glamo-regs.h
+@@ -142,8 +142,12 @@ enum glamo_register_mem {
+ #define GLAMO_MEM_TYPE_MASK 0x03
+
+ enum glamo_reg_mem_dram1 {
+- GLAMO_MEM_DRAM1_EN_SDRAM_CLK = (1 << 11),
++ /* b0 - b10 == refresh period, 1 -> 2048 clocks */
++ GLAMO_MEM_DRAM1_EN_GATE_CLK = (1 << 11),
+ GLAMO_MEM_DRAM1_SELF_REFRESH = (1 << 12),
++ GLAMO_MEM_DRAM1_EN_GATE_CKE = (1 << 13),
++ GLAMO_MEM_DRAM1_EN_DRAM_REFRESH = (1 << 14),
++ GLAMO_MEM_DRAM1_EN_MODEREG_SET = (1 << 15),
+ };
+
+ enum glamo_reg_mem_dram2 {
+--
+1.5.6.3
+