summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorBoris Gjenero <dreamlayers@rockbox.org>2009-04-12 14:54:12 +0000
committerBoris Gjenero <dreamlayers@rockbox.org>2009-04-12 14:54:12 +0000
commit73e1bad355bee944eaa0e2f15d2a52da073b980b (patch)
tree59d407e4f52219a8a4f164267cd0cd1ffce1e9d1 /firmware
parent7ed1a5f1206142a7087867b549ddf629e89ebe14 (diff)
downloadrockbox-73e1bad355bee944eaa0e2f15d2a52da073b980b.tar.gz
rockbox-73e1bad355bee944eaa0e2f15d2a52da073b980b.zip
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
Diffstat (limited to 'firmware')
-rw-r--r--firmware/target/arm/ipod/video/lcd-video.c99
-rw-r--r--firmware/target/arm/system-pp502x.c2
2 files changed, 66 insertions, 35 deletions
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 @@
57/* Time until the BCM is considered stalled and will be re-kicked. 57/* Time until the BCM is considered stalled and will be re-kicked.
58 * Must be guaranteed to be >~ 20ms. */ 58 * Must be guaranteed to be >~ 20ms. */
59#define BCM_UPDATE_TIMEOUT (HZ/20) 59#define BCM_UPDATE_TIMEOUT (HZ/20)
60/* An LCD update command done while the LCD is off needs >~ 200ms */
61#define BCM_LCDINIT_TIMEOUT (HZ/2)
60 62
61/* Addresses within BCM */ 63/* Addresses within BCM */
62#define BCMA_SRAM_BASE 0 64#define BCMA_SRAM_BASE 0
@@ -92,7 +94,7 @@ enum lcd_status {
92}; 94};
93 95
94struct { 96struct {
95 long update_timeout; 97 long update_timeout; /* also used to ensure BCM stays off for >= 50 ms */
96 enum lcd_status state; 98 enum lcd_status state;
97 bool blocked; 99 bool blocked;
98#if NUM_CORES > 1 100#if NUM_CORES > 1
@@ -100,11 +102,12 @@ struct {
100#endif 102#endif
101#ifdef HAVE_LCD_SLEEP 103#ifdef HAVE_LCD_SLEEP
102 bool display_on; 104 bool display_on;
105 bool waking;
106 struct wakeup initwakeup;
103#endif 107#endif
104} lcd_state IBSS_ATTR; 108} lcd_state IBSS_ATTR;
105 109
106#ifdef HAVE_LCD_SLEEP 110#ifdef HAVE_LCD_SLEEP
107static long bcm_off_wait;
108const fb_data *flash_vmcs_offset; 111const fb_data *flash_vmcs_offset;
109unsigned flash_vmcs_length; 112unsigned flash_vmcs_length;
110/* This mutex exists because enabling the backlight by changing a setting 113/* This mutex exists because enabling the backlight by changing a setting
@@ -179,6 +182,12 @@ static inline unsigned bcm_read32(unsigned address)
179 return BCM_DATA32; /* read value */ 182 return BCM_DATA32; /* read value */
180} 183}
181 184
185static void continue_lcd_awake(void)
186{
187 lcd_state.waking = false;
188 wakeup_signal(&(lcd_state.initwakeup));
189}
190
182#ifndef BOOTLOADER 191#ifndef BOOTLOADER
183static void lcd_tick(void) 192static void lcd_tick(void)
184{ 193{
@@ -201,11 +210,15 @@ static void lcd_tick(void)
201 BCM_CONTROL = 0x31; 210 BCM_CONTROL = 0x31;
202 lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT; 211 lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT;
203 lcd_state.state = LCD_UPDATING; 212 lcd_state.state = LCD_UPDATING;
213 if (lcd_state.waking)
214 continue_lcd_awake();
204 } 215 }
205 else if ((lcd_state.state == LCD_UPDATING) && !bcm_is_busy) 216 else if ((lcd_state.state == LCD_UPDATING) && !bcm_is_busy)
206 { 217 {
207 /* Update finished properly and no new update pending. */ 218 /* Update finished properly and no new update pending. */
208 lcd_state.state = LCD_IDLE; 219 lcd_state.state = LCD_IDLE;
220 if (lcd_state.waking)
221 continue_lcd_awake();
209 } 222 }
210 } 223 }
211#if NUM_CORES > 1 224#if NUM_CORES > 1
@@ -246,6 +259,8 @@ static void lcd_unblock_and_update(void)
246 BCM_CONTROL = 0x31; 259 BCM_CONTROL = 0x31;
247 lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT; 260 lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT;
248 lcd_state.state = LCD_UPDATING; 261 lcd_state.state = LCD_UPDATING;
262 if (lcd_state.waking)
263 continue_lcd_awake();
249 } 264 }
250 else 265 else
251 { 266 {
@@ -309,10 +324,7 @@ void lcd_init_device(void)
309 /* These port initializations are supposed to be done when initializing 324 /* These port initializations are supposed to be done when initializing
310 the BCM. None of it is changed when shutting down the BCM. 325 the BCM. None of it is changed when shutting down the BCM.
311 */ 326 */
312 GPO32_ENABLE |= 0x4000; 327 GPO32_ENABLE |= 0xC000;
313 /* GPO32_VAL & 0x8000 may supply power for BCM sleep state */
314 GPO32_ENABLE |= 0x8000;
315 GPO32_VAL &= ~0x8000;
316 GPIO_CLEAR_BITWISE(GPIOC_ENABLE, 0x80); 328 GPIO_CLEAR_BITWISE(GPIOC_ENABLE, 0x80);
317 /* This pin is used for BCM interrupts */ 329 /* This pin is used for BCM interrupts */
318 GPIOC_ENABLE |= 0x40; 330 GPIOC_ENABLE |= 0x40;
@@ -326,7 +338,6 @@ void lcd_init_device(void)
326 corelock_init(&lcd_state.cl); 338 corelock_init(&lcd_state.cl);
327#endif 339#endif
328#ifdef HAVE_LCD_SLEEP 340#ifdef HAVE_LCD_SLEEP
329 lcd_state.display_on = true; /* Code in flash turned it on */
330 if (!flash_get_section(ROM_ID('v', 'm', 'c', 's'), 341 if (!flash_get_section(ROM_ID('v', 'm', 'c', 's'),
331 (void **)(&flash_vmcs_offset), &flash_vmcs_length)) 342 (void **)(&flash_vmcs_offset), &flash_vmcs_length))
332 /* BCM cannot be shut down because firmware wasn't found */ 343 /* BCM cannot be shut down because firmware wasn't found */
@@ -336,8 +347,27 @@ void lcd_init_device(void)
336 flash_vmcs_length = ((flash_vmcs_length + 3) >> 1) & ~1; 347 flash_vmcs_length = ((flash_vmcs_length + 3) >> 1) & ~1;
337 } 348 }
338 mutex_init(&lcdstate_lock); 349 mutex_init(&lcdstate_lock);
339#endif 350 wakeup_init(&(lcd_state.initwakeup));
351 lcd_state.waking = false;
352
353 if (GPO32_VAL & 0x4000)
354 {
355 /* BCM is powered. Assume it is initialized. */
356 lcd_state.display_on = true;
357 tick_add_task(&lcd_tick);
358 }
359 else
360 {
361 /* BCM is not powered, so it needs to be initialized.
362 This can only happen when loading Rockbox via ROLO.
363 */
364 lcd_state.update_timeout = current_tick;
365 lcd_state.display_on = false;
366 lcd_awake();
367 }
368#else /* !HAVE_LCD_SLEEP */
340 tick_add_task(&lcd_tick); 369 tick_add_task(&lcd_tick);
370#endif
341#endif /* !BOOTLOADER */ 371#endif /* !BOOTLOADER */
342} 372}
343 373
@@ -495,9 +525,7 @@ void bcm_init(void)
495 525
496 /* Power up BCM */ 526 /* Power up BCM */
497 GPO32_VAL |= 0x4000; 527 GPO32_VAL |= 0x4000;
498 528 sleep(HZ/20);
499 /* Changed from HZ/2 to speed up this function */
500 sleep(HZ/8);
501 529
502 /* Bootstrap stage 1 */ 530 /* Bootstrap stage 1 */
503 531
@@ -511,7 +539,10 @@ void bcm_init(void)
511 */ 539 */
512 540
513 /* Bootstrap stage 2 */ 541 /* Bootstrap stage 2 */
514 542
543 while (BCM_ALT_CONTROL & 0x80);
544 while (!(BCM_ALT_CONTROL & 0x40));
545
515 for (i = 0; i < 8; i++) { 546 for (i = 0; i < 8; i++) {
516 BCM_CONTROL = bcm_bootstrapdata[i]; 547 BCM_CONTROL = bcm_bootstrapdata[i];
517 } 548 }
@@ -520,19 +551,15 @@ void bcm_init(void)
520 BCM_ALT_CONTROL = bcm_bootstrapdata[i]; 551 BCM_ALT_CONTROL = bcm_bootstrapdata[i];
521 } 552 }
522 553
523 while ((BCM_RD_ADDR & 1) == 0 || (BCM_ALT_RD_ADDR & 1) == 0) 554 while ((BCM_RD_ADDR & 1) == 0 || (BCM_ALT_RD_ADDR & 1) == 0);
524 yield();
525 555
526 (void)BCM_WR_ADDR; 556 (void)BCM_WR_ADDR;
527 (void)BCM_ALT_WR_ADDR; 557 (void)BCM_ALT_WR_ADDR;
528 558
529 /* Bootstrap stage 3: upload firmware */ 559 /* Bootstrap stage 3: upload firmware */
530 560
531 while (BCM_ALT_CONTROL & 0x80) 561 while (BCM_ALT_CONTROL & 0x80);
532 yield(); 562 while (!(BCM_ALT_CONTROL & 0x40));
533
534 while (!(BCM_ALT_CONTROL & 0x40))
535 yield();
536 563
537 /* Upload firmware to BCM SRAM */ 564 /* Upload firmware to BCM SRAM */
538 bcm_write_addr(BCMA_SRAM_BASE); 565 bcm_write_addr(BCMA_SRAM_BASE);
@@ -541,8 +568,7 @@ void bcm_init(void)
541 bcm_write32(BCMA_COMMAND, 0); 568 bcm_write32(BCMA_COMMAND, 0);
542 bcm_write32(0x10000C00, 0xC0000000); 569 bcm_write32(0x10000C00, 0xC0000000);
543 570
544 while (!(bcm_read32(0x10000C00) & 1)) 571 while (!(bcm_read32(0x10000C00) & 1));
545 yield();
546 572
547 bcm_write32(0x10000C00, 0); 573 bcm_write32(0x10000C00, 0);
548 bcm_write32(0x10000400, 0xA5A50002); 574 bcm_write32(0x10000400, 0xA5A50002);
@@ -558,23 +584,26 @@ void lcd_awake(void)
558 mutex_lock(&lcdstate_lock); 584 mutex_lock(&lcdstate_lock);
559 if (!lcd_state.display_on && flash_vmcs_length != 0) 585 if (!lcd_state.display_on && flash_vmcs_length != 0)
560 { 586 {
561 /* Ensure BCM has been off for 1/2 s at least */ 587 /* Ensure BCM has been off for >= 50 ms */
562 while (!TIME_AFTER(current_tick, lcd_state.update_timeout)) 588 long sleepwait = lcd_state.update_timeout + HZ/20 - current_tick;
563 yield(); 589 if (sleepwait > 0 && sleepwait < HZ/20)
590 sleep(sleepwait);
564 591
565 bcm_init(); 592 bcm_init();
566 593
567 /* Update LCD, but don't use lcd_update(). Instead, wait here 594 /* Start the first LCD update, which also initializes the LCD */
568 until the command completes so LCD isn't white when the
569 backlight turns on
570 */
571 bcm_write_addr(BCMA_CMDPARAM);
572 lcd_write_data(&(lcd_framebuffer[0][0]), LCD_WIDTH * LCD_HEIGHT);
573 bcm_command(BCMCMD_LCD_UPDATE);
574
575 lcd_state.state = LCD_INITIAL; 595 lcd_state.state = LCD_INITIAL;
576 tick_add_task(&lcd_tick);
577 lcd_state.display_on = true; 596 lcd_state.display_on = true;
597 lcd_update();
598 lcd_state.update_timeout = current_tick + BCM_LCDINIT_TIMEOUT;
599
600 /* Wait for end of first LCD update, so LCD isn't white
601 when the backlight turns on.
602 */
603 lcd_state.waking = true;
604 tick_add_task(&lcd_tick);
605 wakeup_wait(&(lcd_state.initwakeup), TIMEOUT_BLOCK);
606
578 lcd_activation_call_hook(); 607 lcd_activation_call_hook();
579 } 608 }
580 mutex_unlock(&lcdstate_lock); 609 mutex_unlock(&lcdstate_lock);
@@ -592,7 +621,9 @@ void lcd_sleep(void)
592 621
593 tick_remove_task(&lcd_tick); 622 tick_remove_task(&lcd_tick);
594 bcm_powerdown(); 623 bcm_powerdown();
595 bcm_off_wait = current_tick + HZ/2; 624
625 /* Remember time to ensure BCM stays off for >= 50 ms */
626 lcd_state.update_timeout = current_tick;
596 } 627 }
597 mutex_unlock(&lcdstate_lock); 628 mutex_unlock(&lcdstate_lock);
598} 629}
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c
index 5fb6b20c4c..7a320055b0 100644
--- a/firmware/target/arm/system-pp502x.c
+++ b/firmware/target/arm/system-pp502x.c
@@ -380,7 +380,7 @@ void system_init(void)
380 DEV_EN = 0xc2000124; 380 DEV_EN = 0xc2000124;
381 DEV_EN2 = 0x00000000; 381 DEV_EN2 = 0x00000000;
382 CACHE_PRIORITY = 0x0000003f; 382 CACHE_PRIORITY = 0x0000003f;
383 GPO32_VAL = 0x00004000; 383 GPO32_VAL &= 0x00004000;
384 DEV_INIT1 = 0x00000000; 384 DEV_INIT1 = 0x00000000;
385 DEV_INIT2 = 0x40000000; 385 DEV_INIT2 = 0x40000000;
386 386