mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 05:05:20 -05:00
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
This commit is contained in:
parent
7ed1a5f120
commit
73e1bad355
2 changed files with 66 additions and 35 deletions
|
|
@ -57,6 +57,8 @@
|
||||||
/* Time until the BCM is considered stalled and will be re-kicked.
|
/* Time until the BCM is considered stalled and will be re-kicked.
|
||||||
* Must be guaranteed to be >~ 20ms. */
|
* Must be guaranteed to be >~ 20ms. */
|
||||||
#define BCM_UPDATE_TIMEOUT (HZ/20)
|
#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 */
|
/* Addresses within BCM */
|
||||||
#define BCMA_SRAM_BASE 0
|
#define BCMA_SRAM_BASE 0
|
||||||
|
|
@ -92,7 +94,7 @@ enum lcd_status {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
long update_timeout;
|
long update_timeout; /* also used to ensure BCM stays off for >= 50 ms */
|
||||||
enum lcd_status state;
|
enum lcd_status state;
|
||||||
bool blocked;
|
bool blocked;
|
||||||
#if NUM_CORES > 1
|
#if NUM_CORES > 1
|
||||||
|
|
@ -100,11 +102,12 @@ struct {
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LCD_SLEEP
|
#ifdef HAVE_LCD_SLEEP
|
||||||
bool display_on;
|
bool display_on;
|
||||||
|
bool waking;
|
||||||
|
struct wakeup initwakeup;
|
||||||
#endif
|
#endif
|
||||||
} lcd_state IBSS_ATTR;
|
} lcd_state IBSS_ATTR;
|
||||||
|
|
||||||
#ifdef HAVE_LCD_SLEEP
|
#ifdef HAVE_LCD_SLEEP
|
||||||
static long bcm_off_wait;
|
|
||||||
const fb_data *flash_vmcs_offset;
|
const fb_data *flash_vmcs_offset;
|
||||||
unsigned flash_vmcs_length;
|
unsigned flash_vmcs_length;
|
||||||
/* This mutex exists because enabling the backlight by changing a setting
|
/* 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 */
|
return BCM_DATA32; /* read value */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void continue_lcd_awake(void)
|
||||||
|
{
|
||||||
|
lcd_state.waking = false;
|
||||||
|
wakeup_signal(&(lcd_state.initwakeup));
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef BOOTLOADER
|
#ifndef BOOTLOADER
|
||||||
static void lcd_tick(void)
|
static void lcd_tick(void)
|
||||||
{
|
{
|
||||||
|
|
@ -201,11 +210,15 @@ static void lcd_tick(void)
|
||||||
BCM_CONTROL = 0x31;
|
BCM_CONTROL = 0x31;
|
||||||
lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT;
|
lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT;
|
||||||
lcd_state.state = LCD_UPDATING;
|
lcd_state.state = LCD_UPDATING;
|
||||||
|
if (lcd_state.waking)
|
||||||
|
continue_lcd_awake();
|
||||||
}
|
}
|
||||||
else if ((lcd_state.state == LCD_UPDATING) && !bcm_is_busy)
|
else if ((lcd_state.state == LCD_UPDATING) && !bcm_is_busy)
|
||||||
{
|
{
|
||||||
/* Update finished properly and no new update pending. */
|
/* Update finished properly and no new update pending. */
|
||||||
lcd_state.state = LCD_IDLE;
|
lcd_state.state = LCD_IDLE;
|
||||||
|
if (lcd_state.waking)
|
||||||
|
continue_lcd_awake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if NUM_CORES > 1
|
#if NUM_CORES > 1
|
||||||
|
|
@ -246,6 +259,8 @@ static void lcd_unblock_and_update(void)
|
||||||
BCM_CONTROL = 0x31;
|
BCM_CONTROL = 0x31;
|
||||||
lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT;
|
lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT;
|
||||||
lcd_state.state = LCD_UPDATING;
|
lcd_state.state = LCD_UPDATING;
|
||||||
|
if (lcd_state.waking)
|
||||||
|
continue_lcd_awake();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -309,10 +324,7 @@ void lcd_init_device(void)
|
||||||
/* These port initializations are supposed to be done when initializing
|
/* These port initializations are supposed to be done when initializing
|
||||||
the BCM. None of it is changed when shutting down the BCM.
|
the BCM. None of it is changed when shutting down the BCM.
|
||||||
*/
|
*/
|
||||||
GPO32_ENABLE |= 0x4000;
|
GPO32_ENABLE |= 0xC000;
|
||||||
/* GPO32_VAL & 0x8000 may supply power for BCM sleep state */
|
|
||||||
GPO32_ENABLE |= 0x8000;
|
|
||||||
GPO32_VAL &= ~0x8000;
|
|
||||||
GPIO_CLEAR_BITWISE(GPIOC_ENABLE, 0x80);
|
GPIO_CLEAR_BITWISE(GPIOC_ENABLE, 0x80);
|
||||||
/* This pin is used for BCM interrupts */
|
/* This pin is used for BCM interrupts */
|
||||||
GPIOC_ENABLE |= 0x40;
|
GPIOC_ENABLE |= 0x40;
|
||||||
|
|
@ -326,7 +338,6 @@ void lcd_init_device(void)
|
||||||
corelock_init(&lcd_state.cl);
|
corelock_init(&lcd_state.cl);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LCD_SLEEP
|
#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'),
|
if (!flash_get_section(ROM_ID('v', 'm', 'c', 's'),
|
||||||
(void **)(&flash_vmcs_offset), &flash_vmcs_length))
|
(void **)(&flash_vmcs_offset), &flash_vmcs_length))
|
||||||
/* BCM cannot be shut down because firmware wasn't found */
|
/* 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;
|
flash_vmcs_length = ((flash_vmcs_length + 3) >> 1) & ~1;
|
||||||
}
|
}
|
||||||
mutex_init(&lcdstate_lock);
|
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);
|
tick_add_task(&lcd_tick);
|
||||||
|
#endif
|
||||||
#endif /* !BOOTLOADER */
|
#endif /* !BOOTLOADER */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,9 +525,7 @@ void bcm_init(void)
|
||||||
|
|
||||||
/* Power up BCM */
|
/* Power up BCM */
|
||||||
GPO32_VAL |= 0x4000;
|
GPO32_VAL |= 0x4000;
|
||||||
|
sleep(HZ/20);
|
||||||
/* Changed from HZ/2 to speed up this function */
|
|
||||||
sleep(HZ/8);
|
|
||||||
|
|
||||||
/* Bootstrap stage 1 */
|
/* Bootstrap stage 1 */
|
||||||
|
|
||||||
|
|
@ -511,7 +539,10 @@ void bcm_init(void)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Bootstrap stage 2 */
|
/* Bootstrap stage 2 */
|
||||||
|
|
||||||
|
while (BCM_ALT_CONTROL & 0x80);
|
||||||
|
while (!(BCM_ALT_CONTROL & 0x40));
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
BCM_CONTROL = bcm_bootstrapdata[i];
|
BCM_CONTROL = bcm_bootstrapdata[i];
|
||||||
}
|
}
|
||||||
|
|
@ -520,19 +551,15 @@ void bcm_init(void)
|
||||||
BCM_ALT_CONTROL = bcm_bootstrapdata[i];
|
BCM_ALT_CONTROL = bcm_bootstrapdata[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((BCM_RD_ADDR & 1) == 0 || (BCM_ALT_RD_ADDR & 1) == 0)
|
while ((BCM_RD_ADDR & 1) == 0 || (BCM_ALT_RD_ADDR & 1) == 0);
|
||||||
yield();
|
|
||||||
|
|
||||||
(void)BCM_WR_ADDR;
|
(void)BCM_WR_ADDR;
|
||||||
(void)BCM_ALT_WR_ADDR;
|
(void)BCM_ALT_WR_ADDR;
|
||||||
|
|
||||||
/* Bootstrap stage 3: upload firmware */
|
/* Bootstrap stage 3: upload firmware */
|
||||||
|
|
||||||
while (BCM_ALT_CONTROL & 0x80)
|
while (BCM_ALT_CONTROL & 0x80);
|
||||||
yield();
|
while (!(BCM_ALT_CONTROL & 0x40));
|
||||||
|
|
||||||
while (!(BCM_ALT_CONTROL & 0x40))
|
|
||||||
yield();
|
|
||||||
|
|
||||||
/* Upload firmware to BCM SRAM */
|
/* Upload firmware to BCM SRAM */
|
||||||
bcm_write_addr(BCMA_SRAM_BASE);
|
bcm_write_addr(BCMA_SRAM_BASE);
|
||||||
|
|
@ -541,8 +568,7 @@ void bcm_init(void)
|
||||||
bcm_write32(BCMA_COMMAND, 0);
|
bcm_write32(BCMA_COMMAND, 0);
|
||||||
bcm_write32(0x10000C00, 0xC0000000);
|
bcm_write32(0x10000C00, 0xC0000000);
|
||||||
|
|
||||||
while (!(bcm_read32(0x10000C00) & 1))
|
while (!(bcm_read32(0x10000C00) & 1));
|
||||||
yield();
|
|
||||||
|
|
||||||
bcm_write32(0x10000C00, 0);
|
bcm_write32(0x10000C00, 0);
|
||||||
bcm_write32(0x10000400, 0xA5A50002);
|
bcm_write32(0x10000400, 0xA5A50002);
|
||||||
|
|
@ -558,23 +584,26 @@ void lcd_awake(void)
|
||||||
mutex_lock(&lcdstate_lock);
|
mutex_lock(&lcdstate_lock);
|
||||||
if (!lcd_state.display_on && flash_vmcs_length != 0)
|
if (!lcd_state.display_on && flash_vmcs_length != 0)
|
||||||
{
|
{
|
||||||
/* Ensure BCM has been off for 1/2 s at least */
|
/* Ensure BCM has been off for >= 50 ms */
|
||||||
while (!TIME_AFTER(current_tick, lcd_state.update_timeout))
|
long sleepwait = lcd_state.update_timeout + HZ/20 - current_tick;
|
||||||
yield();
|
if (sleepwait > 0 && sleepwait < HZ/20)
|
||||||
|
sleep(sleepwait);
|
||||||
|
|
||||||
bcm_init();
|
bcm_init();
|
||||||
|
|
||||||
/* Update LCD, but don't use lcd_update(). Instead, wait here
|
/* Start the first LCD update, which also initializes the LCD */
|
||||||
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);
|
|
||||||
|
|
||||||
lcd_state.state = LCD_INITIAL;
|
lcd_state.state = LCD_INITIAL;
|
||||||
tick_add_task(&lcd_tick);
|
|
||||||
lcd_state.display_on = true;
|
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();
|
lcd_activation_call_hook();
|
||||||
}
|
}
|
||||||
mutex_unlock(&lcdstate_lock);
|
mutex_unlock(&lcdstate_lock);
|
||||||
|
|
@ -592,7 +621,9 @@ void lcd_sleep(void)
|
||||||
|
|
||||||
tick_remove_task(&lcd_tick);
|
tick_remove_task(&lcd_tick);
|
||||||
bcm_powerdown();
|
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);
|
mutex_unlock(&lcdstate_lock);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -380,7 +380,7 @@ void system_init(void)
|
||||||
DEV_EN = 0xc2000124;
|
DEV_EN = 0xc2000124;
|
||||||
DEV_EN2 = 0x00000000;
|
DEV_EN2 = 0x00000000;
|
||||||
CACHE_PRIORITY = 0x0000003f;
|
CACHE_PRIORITY = 0x0000003f;
|
||||||
GPO32_VAL = 0x00004000;
|
GPO32_VAL &= 0x00004000;
|
||||||
DEV_INIT1 = 0x00000000;
|
DEV_INIT1 = 0x00000000;
|
||||||
DEV_INIT2 = 0x40000000;
|
DEV_INIT2 = 0x40000000;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue