aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy@openmoko.com>2008-11-19 17:11:11 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-11-19 17:11:11 +0000
commit6e0df963162d04cb4243155a0137faa12516d9a2 (patch)
tree56f5e07f5f82ae22b4fe71ce37a2c7e52ddd5578
parent9d6e27160ddcd316d5b5fc9a2caf74d340e2ba93 (diff)
debug-resume-hang.patch
Weeks of frantic effort to control Glamo, traced the issue to two outcomes: nWAIT is forced down and the device is hard locked, or we survive immediate Glamo resume and die again with nWAIT forced down when the framebuffer driver tries to flash the soft cursor. Signed-off-by: Andy Green <andy@openmoko.com>
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c28
-rw-r--r--drivers/mfd/glamo/glamo-core.c158
-rw-r--r--drivers/mfd/glamo/glamo-fb.c15
-rw-r--r--drivers/mfd/glamo/glamo-mci.c43
-rw-r--r--drivers/video/console/fbcon.c3
-rw-r--r--drivers/video/display/jbt6k74.c8
6 files changed, 192 insertions, 63 deletions
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index a55fd43ef6b..5fa837751e3 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -1582,28 +1582,29 @@ __setup("hardware_ecc=", hardware_ecc_setup);
/* these are the guys that don't need to be children of PMU */
static struct platform_device *gta02_devices[] __initdata = {
- &gta02_pmu_dev,
+ &gta02_version_device,
&s3c_device_usb,
&s3c_device_wdt,
- &s3c_device_i2c,
- &s3c_device_iis,
+ &gta02_memconfig_device,
// &s3c_device_sdi, /* FIXME: temporary disable to avoid s3cmci bind */
&s3c_device_usbgadget,
&s3c_device_nand,
&s3c_device_ts,
&gta02_nor_flash,
+
&sc32440_fiq_device,
- &gta02_version_device,
- &gta02_memconfig_device,
&s3c24xx_pwm_device,
&gta02_pm_wlan_dev,
+
+ &s3c_device_iis,
+ &gta02_pmu_dev,
+ &s3c_device_i2c,
};
/* these guys DO need to be children of PMU */
static struct platform_device *gta02_devices_pmu_children[] = {
- &gta02_glamo_dev, /* glamo-mci power handling depends on PMU */
&gta01_pm_gps_dev,
&gta01_pm_bt_dev,
&gta02_pm_gsm_dev,
@@ -1612,6 +1613,7 @@ static struct platform_device *gta02_devices_pmu_children[] = {
&s3c_device_spi_acc,
&gta02_button_dev,
&gta02_resume_reason_device,
+ &gta02_glamo_dev, /* glamo-mci power handling depends on PMU */
};
/* this is called when pc50633 is probed, unfortunately quite late in the
@@ -1733,10 +1735,20 @@ static void __init gta02_machine_init(void)
enable_irq_wake(GTA02_IRQ_WLAN_GPIO1);
}
-void DEBUG_LED(void)
+void DEBUG_LED(int n)
{
// int *p = NULL;
- neo1973_gpb_setpin(GTA02_GPIO_AUX_LED, 1);
+ switch (n) {
+ case 0:
+ neo1973_gpb_setpin(GTA02_GPIO_PWR_LED1, 1);
+ break;
+ case 1:
+ neo1973_gpb_setpin(GTA02_GPIO_PWR_LED2, 1);
+ break;
+ default:
+ neo1973_gpb_setpin(GTA02_GPIO_AUX_LED, 1);
+ break;
+ }
// printk(KERN_ERR"die %d\n", *p);
}
EXPORT_SYMBOL_GPL(DEBUG_LED);
diff --git a/drivers/mfd/glamo/glamo-core.c b/drivers/mfd/glamo/glamo-core.c
index 2ddc0357588..c3ecb0af81a 100644
--- a/drivers/mfd/glamo/glamo-core.c
+++ b/drivers/mfd/glamo/glamo-core.c
@@ -393,26 +393,24 @@ static void glamo_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
int __glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine)
{
- printk(KERN_ERR" __glamo_engine_enable %d\n", engine);
switch (engine) {
case GLAMO_ENGINE_LCD:
- __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_LCD,
+ __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2),
+ GLAMO_HOSTBUS2_MMIO_EN_LCD,
+ GLAMO_HOSTBUS2_MMIO_EN_LCD);
+ __reg_write(glamo, GLAMO_REG_CLOCK_LCD,
GLAMO_CLOCK_LCD_EN_M5CLK |
GLAMO_CLOCK_LCD_EN_DHCLK |
GLAMO_CLOCK_LCD_EN_DMCLK |
GLAMO_CLOCK_LCD_EN_DCLK |
GLAMO_CLOCK_LCD_DG_M5CLK |
- GLAMO_CLOCK_LCD_DG_DMCLK, 0xffff);
+ GLAMO_CLOCK_LCD_DG_DMCLK);
__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, 0xffff);
- __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2),
- GLAMO_HOSTBUS2_MMIO_EN_LCD,
- 0xffff);
break;
case GLAMO_ENGINE_MMC:
- /* enable access to MMC unit */
__reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2),
GLAMO_HOSTBUS2_MMIO_EN_MMC,
GLAMO_HOSTBUS2_MMIO_EN_MMC);
@@ -469,7 +467,6 @@ EXPORT_SYMBOL_GPL(glamo_engine_enable);
int __glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine)
{
- printk(KERN_ERR" __glamo_engine_disable %d\n", engine);
switch (engine) {
case GLAMO_ENGINE_LCD:
/* remove pixel clock to LCM */
@@ -486,23 +483,18 @@ int __glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine)
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,
- GLAMO_CLOCK_MMC_EN_M9CLK |
- GLAMO_CLOCK_MMC_EN_TCLK |
- GLAMO_CLOCK_MMC_DG_M9CLK |
- GLAMO_CLOCK_MMC_DG_TCLK, 0);
+// __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MMC,
+// GLAMO_CLOCK_MMC_EN_M9CLK |
+// GLAMO_CLOCK_MMC_EN_TCLK |
+// GLAMO_CLOCK_MMC_DG_M9CLK |
+// GLAMO_CLOCK_MMC_DG_TCLK, 0);
/* disable the TCLK divider clk input */
- __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_GEN5_1,
- GLAMO_CLOCK_GEN51_EN_DIV_TCLK, 0);
- /* kill access to MMC unit */
-// __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2),
-// GLAMO_HOSTBUS2_MMIO_EN_MMC, 0);
- break;
+// __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_GEN5_1,
+// GLAMO_CLOCK_GEN51_EN_DIV_TCLK, 0);
+
default:
break;
}
@@ -803,6 +795,28 @@ static struct glamo_script glamo_init_script[] = {
{ GLAMO_REG_CLOCK_MEMORY, 0x000b },
};
+static struct glamo_script glamo_resume_script[] = {
+
+ { GLAMO_REG_PLL_GEN1, 0x05db }, /* 48MHz */
+ { GLAMO_REG_PLL_GEN3, 0x0aba }, /* 90MHz */
+ { 0xfffd, 0 },
+ /*
+ * b9 of this register MUST be zero to get any interrupts on INT#
+ * the other set bits enable all the engine interrupt sources
+ */
+ { GLAMO_REG_IRQ_ENABLE, 0x01ff },
+ { GLAMO_REG_CLOCK_HOST, 0x0018 },
+ { GLAMO_REG_CLOCK_GEN5_1, 0x1801 },
+
+ { 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 },
+};
+
enum glamo_power {
GLAMO_POWER_ON,
@@ -813,8 +827,9 @@ static void glamo_power(struct glamo_core *glamo,
enum glamo_power new_state)
{
int n;
+ unsigned long flags;
- spin_lock(&glamo->lock);
+ spin_lock_irqsave(&glamo->lock, flags);
dev_dbg(&glamo->pdev->dev, "***** glamo_power -> %d\n", new_state);
@@ -849,24 +864,57 @@ static const REG_VALUE_MASK_TYPE reg_powerSuspend[] =
switch (new_state) {
case GLAMO_POWER_ON:
- /* power up PLL1 and PLL2 */
- __reg_set_bit_mask(glamo, GLAMO_REG_DFT_GEN6, 1, 1);
- __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 1 << 13, 0);
+ glamo_run_script(glamo, glamo_resume_script,
+ ARRAY_SIZE(glamo_resume_script), 0);
+#if 0
+ __reg_write(glamo, GLAMO_REG_MEM_TYPE, 0x0c74);
+ __reg_write(glamo, GLAMO_REG_MEM_GEN, 0xafaf);
- /* spin until PLL1 and PLL2 lock */
- while ((__reg_read(glamo, GLAMO_REG_PLL_GEN5) & 3) != 3)
- ;
+ /* 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 | GLAMO_CLOCK_MEM_RESET);
/* re-enable clocks to memory */
- __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
- GLAMO_CLOCK_MEM_EN_MOCACLK, GLAMO_CLOCK_MEM_EN_MOCACLK);
+ __reg_write(glamo, GLAMO_REG_CLOCK_MEMORY,
+ GLAMO_CLOCK_MEM_EN_MOCACLK | GLAMO_CLOCK_MEM_EN_M1CLK |
+ GLAMO_CLOCK_MEM_DG_M1CLK);
+
/* Get memory out of deep powerdown */
- __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM2,
- GLAMO_MEM_DRAM2_DEEP_PWRDOWN, 0);
- /* clear selfrefresh */
+ __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);
- __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM1, 1 << 12, 0);
+ /* power up PLL2 and PLL1 */
+ __reg_write(glamo, GLAMO_REG_PLL_GEN3, (1 << 12) | 0xaba);
+ __reg_write(glamo, GLAMO_REG_DFT_GEN6, 1);
+
+ mdelay(50);
+
+ /* spin until PLL1 and PLL2 lock */
+ while ((__reg_read(glamo, GLAMO_REG_PLL_GEN5) & 3) != 3)
+ ;
+
+ /* PLL2 out of bypass */
+ __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 1 << 12, 0);
+#endif
+ /* all dividers from PLLs */
+ __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_GEN5_1, 0x400, 0);
/* restore each engine that was up before suspend */
for (n = 0; n < __NUM_GLAMO_ENGINES; n++)
@@ -891,20 +939,47 @@ static const REG_VALUE_MASK_TYPE reg_powerSuspend[] =
for (n = 0; n < __NUM_GLAMO_ENGINES; n++)
if (glamo->engine_enabled_bitfield & (1 << n))
__glamo_engine_disable(glamo, n);
-
- __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM2,
- GLAMO_MEM_DRAM2_DEEP_PWRDOWN, GLAMO_MEM_DRAM2_DEEP_PWRDOWN);
+ /* 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 */
+
/* disable clocks to memory */
- __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
- GLAMO_CLOCK_MEM_EN_MOCACLK, 0);
- __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 1 << 13, 1 << 13);
+ __reg_write(glamo, GLAMO_REG_CLOCK_MEMORY, 0);
+
+ /* all dividers from OSCI */
+ __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_GEN5_1, 0x400, 0x400);
+
+ /* PLL2 into bypass */
+ __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 1 << 12, 1 << 12);
+
+ /* kill PLLS 1 then 2 */
__reg_write(glamo, GLAMO_REG_DFT_GEN5, 0x0001);
+ __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 1 << 13, 1 << 13);
break;
}
- spin_unlock(&glamo->lock);
+ spin_unlock_irqrestore(&glamo->lock, flags);
}
#if 0
@@ -1306,6 +1381,7 @@ static int glamo_resume(struct platform_device *pdev)
return 0;
}
+
#else
#define glamo_suspend NULL
#define glamo_resume NULL
diff --git a/drivers/mfd/glamo/glamo-fb.c b/drivers/mfd/glamo/glamo-fb.c
index 26a6d29ddba..7bfd539972f 100644
--- a/drivers/mfd/glamo/glamo-fb.c
+++ b/drivers/mfd/glamo/glamo-fb.c
@@ -945,8 +945,14 @@ static int glamofb_suspend(struct platform_device *pdev, pm_message_t state)
{
struct glamofb_handle *gfb = platform_get_drvdata(pdev);
- if (state.event & PM_EVENT_SLEEP)
- fb_set_suspend(gfb->fb, 1);
+ /* we need to stop anything touching our framebuffer */
+// fb_blank(gfb->fb, FB_BLANK_NORMAL);
+ fb_set_suspend(gfb->fb, 1);
+
+ /* seriously -- nobody is allowed to touch glamo memory when we
+ * are suspended or we lock on nWAIT
+ */
+// iounmap(gfb->fb->screen_base);
return 0;
}
@@ -955,7 +961,12 @@ static int glamofb_resume(struct platform_device *pdev)
{
struct glamofb_handle *gfb = platform_get_drvdata(pdev);
+ /* OK let's allow framebuffer ops again */
+// gfb->fb->screen_base = ioremap(gfb->fb_res->start,
+// RESSIZE(gfb->fb_res));
+
fb_set_suspend(gfb->fb, 0);
+// fb_blank(gfb->fb, FB_BLANK_UNBLANK);
return 0;
}
diff --git a/drivers/mfd/glamo/glamo-mci.c b/drivers/mfd/glamo/glamo-mci.c
index 13175c4a240..b5d6ad10dd9 100644
--- a/drivers/mfd/glamo/glamo-mci.c
+++ b/drivers/mfd/glamo/glamo-mci.c
@@ -341,6 +341,12 @@ static void glamo_mci_irq(unsigned int irq, struct irq_desc *desc)
if (!host)
return;
+
+ if (host->suspending) { /* bad news, dangerous time */
+ dev_err(&host->pdev->dev, "****glamo_mci_irq before resumed\n");
+ return;
+ }
+
if (!host->mrq)
return;
cmd = host->mrq->cmd;
@@ -499,7 +505,7 @@ static int glamo_mci_send_command(struct glamo_mci_host *host,
/* multiblock with stop */
fire |= GLAMO_FIRE_MMC_CC_MBWS;
else
- /* multiblock NO stop-- 'RESERVED'? */
+// /* multiblock NO stop-- 'RESERVED'? */
fire |= GLAMO_FIRE_MMC_CC_MBWNS;
break;
case MMC_STOP_TRANSMISSION:
@@ -573,7 +579,14 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
u16 * reg_resp = (u16 *)(host->base + GLAMO_REG_MMC_CMD_RSP1);
u16 status;
int n;
- int timeout = 100000000;
+ int timeout = 10000000;
+ int insanity_timeout = 10000000;
+
+ if (host->suspending) {
+ dev_err(&host->pdev->dev, "IGNORING glamo_mci_send_request while "
+ "suspended\n");
+ return;
+ }
host->ccnt++;
/*
@@ -620,7 +633,12 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
GLAMO_STAT1_MMC_RTOUT |
GLAMO_STAT1_MMC_DTOUT |
GLAMO_STAT1_MMC_BWERR |
- GLAMO_STAT1_MMC_BRERR))));
+ GLAMO_STAT1_MMC_BRERR))) && (insanity_timeout--));
+
+ if (insanity_timeout < 0) {
+ cmd->error = -ETIMEDOUT;
+ dev_err(&host->pdev->dev, "****** insanity timeout\n");
+ }
if (status & (GLAMO_STAT1_MMC_RTOUT |
GLAMO_STAT1_MMC_DTOUT))
@@ -716,13 +734,18 @@ static void glamo_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
#if 0
static void glamo_mci_reset(struct glamo_mci_host *host)
{
+ if (host->suspending) {
+ dev_err(&host->pdev->dev, "IGNORING glamo_mci_reset while "
+ "suspended\n");
+ return;
+ }
dev_err(&host->pdev->dev, "******* glamo_mci_reset\n");
/* reset MMC controller */
writew(GLAMO_CLOCK_MMC_RESET | GLAMO_CLOCK_MMC_DG_TCLK |
GLAMO_CLOCK_MMC_EN_TCLK | GLAMO_CLOCK_MMC_DG_M9CLK |
GLAMO_CLOCK_MMC_EN_M9CLK,
glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_MMC);
- msleep(1);
+ udelay(10);
/* and disable reset */
writew(GLAMO_CLOCK_MMC_DG_TCLK |
GLAMO_CLOCK_MMC_EN_TCLK | GLAMO_CLOCK_MMC_DG_M9CLK |
@@ -738,6 +761,12 @@ static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
int div;
int powering = 0;
+ if (host->suspending) {
+ dev_err(&host->pdev->dev, "IGNORING glamo_mci_set_ios while "
+ "suspended\n");
+ return;
+ }
+
/* Set power */
switch(ios->power_mode) {
case MMC_POWER_ON:
@@ -1002,6 +1031,7 @@ static int glamo_mci_suspend(struct platform_device *dev, pm_message_t state)
ret = mmc_suspend_host(mmc, state);
+ host->suspending++;
/* so that when we resume, we use any modified max rate */
mmc->f_max = sd_max_clk;
@@ -1014,6 +1044,11 @@ int glamo_mci_resume(struct platform_device *dev)
struct glamo_mci_host *host = mmc_priv(mmc);
int ret;
+ sd_idleclk = 1;
+
+ glamo_engine_enable(host->pdata->pglamo, GLAMO_ENGINE_MMC);
+ glamo_mci_reset(host);
+
host->suspending--;
ret = mmc_resume_host(mmc);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 6b666a50e3a..285acaeafe8 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -401,6 +401,9 @@ static void fb_flashcursor(struct work_struct *work)
int c;
int mode;
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+
acquire_console_sem();
if (ops && ops->currcon != -1)
vc = vc_cons[ops->currcon].d;
diff --git a/drivers/video/display/jbt6k74.c b/drivers/video/display/jbt6k74.c
index 807d6b538f7..77f9528ff5a 100644
--- a/drivers/video/display/jbt6k74.c
+++ b/drivers/video/display/jbt6k74.c
@@ -692,14 +692,6 @@ int jbt6k74_resume(struct spi_device *spi)
struct jbt_info *jbt = dev_get_drvdata(&spi->dev);
struct jbt6k74_platform_data *jbt6k74_pdata = spi->dev.platform_data;
- /* we can get called twice with all dependencies resumed if our core
- * resume callback is last of all. Protect against doing anything twice
- */
- if (jbt->have_resumed)
- return 0;
-
- jbt->have_resumed |= 1;
-
switch (jbt->last_state) {
case JBT_STATE_QVGA_NORMAL:
jbt6k74_enter_state(jbt, JBT_STATE_QVGA_NORMAL);