From 73e1bad355bee944eaa0e2f15d2a52da073b980b Mon Sep 17 00:00:00 2001 From: Boris Gjenero Date: Sun, 12 Apr 2009 14:54:12 +0000 Subject: Fixes and improvements for FS#9890 - iPod 5G: LCD sleep, BCM shutdown and bootstrap * Ensure LCD is updated if lcd_update() is called while the LCD is initializing * Turn on BCM and LCD in lcd_init_device() if it is off * Speed up lcd_awake() * Shorten minimum length of time BCM must stay off and fix related code git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20695 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/ipod/video/lcd-video.c | 99 ++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 34 deletions(-) (limited to 'firmware/target/arm/ipod/video') diff --git a/firmware/target/arm/ipod/video/lcd-video.c b/firmware/target/arm/ipod/video/lcd-video.c index 0a2c5985a9..200126d837 100644 --- a/firmware/target/arm/ipod/video/lcd-video.c +++ b/firmware/target/arm/ipod/video/lcd-video.c @@ -57,6 +57,8 @@ /* Time until the BCM is considered stalled and will be re-kicked. * Must be guaranteed to be >~ 20ms. */ #define BCM_UPDATE_TIMEOUT (HZ/20) +/* An LCD update command done while the LCD is off needs >~ 200ms */ +#define BCM_LCDINIT_TIMEOUT (HZ/2) /* Addresses within BCM */ #define BCMA_SRAM_BASE 0 @@ -92,7 +94,7 @@ enum lcd_status { }; struct { - long update_timeout; + long update_timeout; /* also used to ensure BCM stays off for >= 50 ms */ enum lcd_status state; bool blocked; #if NUM_CORES > 1 @@ -100,11 +102,12 @@ struct { #endif #ifdef HAVE_LCD_SLEEP bool display_on; + bool waking; + struct wakeup initwakeup; #endif } lcd_state IBSS_ATTR; #ifdef HAVE_LCD_SLEEP -static long bcm_off_wait; const fb_data *flash_vmcs_offset; unsigned flash_vmcs_length; /* This mutex exists because enabling the backlight by changing a setting @@ -179,6 +182,12 @@ static inline unsigned bcm_read32(unsigned address) return BCM_DATA32; /* read value */ } +static void continue_lcd_awake(void) +{ + lcd_state.waking = false; + wakeup_signal(&(lcd_state.initwakeup)); +} + #ifndef BOOTLOADER static void lcd_tick(void) { @@ -201,11 +210,15 @@ static void lcd_tick(void) BCM_CONTROL = 0x31; lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT; lcd_state.state = LCD_UPDATING; + if (lcd_state.waking) + continue_lcd_awake(); } else if ((lcd_state.state == LCD_UPDATING) && !bcm_is_busy) { /* Update finished properly and no new update pending. */ lcd_state.state = LCD_IDLE; + if (lcd_state.waking) + continue_lcd_awake(); } } #if NUM_CORES > 1 @@ -246,6 +259,8 @@ static void lcd_unblock_and_update(void) BCM_CONTROL = 0x31; lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT; lcd_state.state = LCD_UPDATING; + if (lcd_state.waking) + continue_lcd_awake(); } else { @@ -309,10 +324,7 @@ void lcd_init_device(void) /* These port initializations are supposed to be done when initializing the BCM. None of it is changed when shutting down the BCM. */ - GPO32_ENABLE |= 0x4000; - /* GPO32_VAL & 0x8000 may supply power for BCM sleep state */ - GPO32_ENABLE |= 0x8000; - GPO32_VAL &= ~0x8000; + GPO32_ENABLE |= 0xC000; GPIO_CLEAR_BITWISE(GPIOC_ENABLE, 0x80); /* This pin is used for BCM interrupts */ GPIOC_ENABLE |= 0x40; @@ -326,7 +338,6 @@ void lcd_init_device(void) corelock_init(&lcd_state.cl); #endif #ifdef HAVE_LCD_SLEEP - lcd_state.display_on = true; /* Code in flash turned it on */ if (!flash_get_section(ROM_ID('v', 'm', 'c', 's'), (void **)(&flash_vmcs_offset), &flash_vmcs_length)) /* BCM cannot be shut down because firmware wasn't found */ @@ -336,8 +347,27 @@ void lcd_init_device(void) flash_vmcs_length = ((flash_vmcs_length + 3) >> 1) & ~1; } mutex_init(&lcdstate_lock); -#endif + wakeup_init(&(lcd_state.initwakeup)); + lcd_state.waking = false; + + if (GPO32_VAL & 0x4000) + { + /* BCM is powered. Assume it is initialized. */ + lcd_state.display_on = true; + tick_add_task(&lcd_tick); + } + else + { + /* BCM is not powered, so it needs to be initialized. + This can only happen when loading Rockbox via ROLO. + */ + lcd_state.update_timeout = current_tick; + lcd_state.display_on = false; + lcd_awake(); + } +#else /* !HAVE_LCD_SLEEP */ tick_add_task(&lcd_tick); +#endif #endif /* !BOOTLOADER */ } @@ -495,9 +525,7 @@ void bcm_init(void) /* Power up BCM */ GPO32_VAL |= 0x4000; - - /* Changed from HZ/2 to speed up this function */ - sleep(HZ/8); + sleep(HZ/20); /* Bootstrap stage 1 */ @@ -511,7 +539,10 @@ void bcm_init(void) */ /* Bootstrap stage 2 */ - + + while (BCM_ALT_CONTROL & 0x80); + while (!(BCM_ALT_CONTROL & 0x40)); + for (i = 0; i < 8; i++) { BCM_CONTROL = bcm_bootstrapdata[i]; } @@ -520,19 +551,15 @@ void bcm_init(void) BCM_ALT_CONTROL = bcm_bootstrapdata[i]; } - while ((BCM_RD_ADDR & 1) == 0 || (BCM_ALT_RD_ADDR & 1) == 0) - yield(); + while ((BCM_RD_ADDR & 1) == 0 || (BCM_ALT_RD_ADDR & 1) == 0); (void)BCM_WR_ADDR; (void)BCM_ALT_WR_ADDR; /* Bootstrap stage 3: upload firmware */ - while (BCM_ALT_CONTROL & 0x80) - yield(); - - while (!(BCM_ALT_CONTROL & 0x40)) - yield(); + while (BCM_ALT_CONTROL & 0x80); + while (!(BCM_ALT_CONTROL & 0x40)); /* Upload firmware to BCM SRAM */ bcm_write_addr(BCMA_SRAM_BASE); @@ -541,8 +568,7 @@ void bcm_init(void) bcm_write32(BCMA_COMMAND, 0); bcm_write32(0x10000C00, 0xC0000000); - while (!(bcm_read32(0x10000C00) & 1)) - yield(); + while (!(bcm_read32(0x10000C00) & 1)); bcm_write32(0x10000C00, 0); bcm_write32(0x10000400, 0xA5A50002); @@ -558,23 +584,26 @@ void lcd_awake(void) mutex_lock(&lcdstate_lock); if (!lcd_state.display_on && flash_vmcs_length != 0) { - /* Ensure BCM has been off for 1/2 s at least */ - while (!TIME_AFTER(current_tick, lcd_state.update_timeout)) - yield(); + /* Ensure BCM has been off for >= 50 ms */ + long sleepwait = lcd_state.update_timeout + HZ/20 - current_tick; + if (sleepwait > 0 && sleepwait < HZ/20) + sleep(sleepwait); bcm_init(); - /* Update LCD, but don't use lcd_update(). Instead, wait here - until the command completes so LCD isn't white when the - backlight turns on - */ - bcm_write_addr(BCMA_CMDPARAM); - lcd_write_data(&(lcd_framebuffer[0][0]), LCD_WIDTH * LCD_HEIGHT); - bcm_command(BCMCMD_LCD_UPDATE); - + /* Start the first LCD update, which also initializes the LCD */ lcd_state.state = LCD_INITIAL; - tick_add_task(&lcd_tick); lcd_state.display_on = true; + lcd_update(); + lcd_state.update_timeout = current_tick + BCM_LCDINIT_TIMEOUT; + + /* Wait for end of first LCD update, so LCD isn't white + when the backlight turns on. + */ + lcd_state.waking = true; + tick_add_task(&lcd_tick); + wakeup_wait(&(lcd_state.initwakeup), TIMEOUT_BLOCK); + lcd_activation_call_hook(); } mutex_unlock(&lcdstate_lock); @@ -592,7 +621,9 @@ void lcd_sleep(void) tick_remove_task(&lcd_tick); bcm_powerdown(); - bcm_off_wait = current_tick + HZ/2; + + /* Remember time to ensure BCM stays off for >= 50 ms */ + lcd_state.update_timeout = current_tick; } mutex_unlock(&lcdstate_lock); } -- cgit v1.2.3