summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/target/arm/ipod/video/lcd-video.c113
1 files changed, 62 insertions, 51 deletions
diff --git a/firmware/target/arm/ipod/video/lcd-video.c b/firmware/target/arm/ipod/video/lcd-video.c
index da3011887c..e62928724e 100644
--- a/firmware/target/arm/ipod/video/lcd-video.c
+++ b/firmware/target/arm/ipod/video/lcd-video.c
@@ -8,7 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * LCD driver for iPod Video 10 * LCD driver for iPod Video
11 * 11 *
12 * Based on code from the ipodlinux project - http://ipodlinux.org/ 12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in December 2005 13 * Adapted for Rockbox in December 2005
14 * 14 *
@@ -56,7 +56,7 @@
56 56
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 */ 60/* An LCD update command done while the LCD is off needs >~ 200ms */
61#define BCM_LCDINIT_TIMEOUT (HZ/2) 61#define BCM_LCDINIT_TIMEOUT (HZ/2)
62 62
@@ -81,19 +81,21 @@
81#define BCMCMD_LCD_UPDATERECT BCM_CMD(5) 81#define BCMCMD_LCD_UPDATERECT BCM_CMD(5)
82#define BCMCMD_LCD_SLEEP BCM_CMD(8) 82#define BCMCMD_LCD_SLEEP BCM_CMD(8)
83/* BCM_CMD(12) involved in shutdown */ 83/* BCM_CMD(12) involved in shutdown */
84/* Macrovision analog copy prevention is on by default on TV output. 84/* Macrovision analog copy prevention is on by default on TV output.
85 Execute this command after enabling TV out to turn it off. 85 Execute this command after enabling TV out to turn it off.
86 */ 86 */
87#define BCMCMD_TV_MVOFF BCM_CMD(14) 87#define BCMCMD_TV_MVOFF BCM_CMD(14)
88 88
89enum lcd_status { 89enum lcd_status
90{
90 LCD_IDLE, 91 LCD_IDLE,
91 LCD_INITIAL, 92 LCD_INITIAL,
92 LCD_NEED_UPDATE, 93 LCD_NEED_UPDATE,
93 LCD_UPDATING 94 LCD_UPDATING
94}; 95};
95 96
96struct { 97struct
98{
97 long update_timeout; /* also used to ensure BCM stays off for >= 50 ms */ 99 long update_timeout; /* also used to ensure BCM stays off for >= 50 ms */
98 enum lcd_status state; 100 enum lcd_status state;
99 bool blocked; 101 bool blocked;
@@ -125,7 +127,7 @@ static struct mutex lcdstate_lock SHAREDBSS_ATTR;
125 Based on part of FS#6721. This may belong elsewhere. 127 Based on part of FS#6721. This may belong elsewhere.
126 (BCM initialization uploads the vmcs section to the BCM.) 128 (BCM initialization uploads the vmcs section to the BCM.)
127 */ 129 */
128bool flash_get_section(const unsigned int imageid, 130bool flash_get_section(const unsigned int imageid,
129 void **offset, 131 void **offset,
130 unsigned int *length) 132 unsigned int *length)
131{ 133{
@@ -134,7 +136,8 @@ bool flash_get_section(const unsigned int imageid,
134 unsigned long checksum; 136 unsigned long checksum;
135 137
136 /* Find the image in the directory */ 138 /* Find the image in the directory */
137 while (1) { 139 while (1)
140 {
138 if (p[0] != ROM_ID('f','l','s','h')) 141 if (p[0] != ROM_ID('f','l','s','h'))
139 return false; 142 return false;
140 if (p[1] == imageid) 143 if (p[1] == imageid)
@@ -148,7 +151,8 @@ bool flash_get_section(const unsigned int imageid,
148 /* Verify checksum. Probably unnecessary, but it's fast. */ 151 /* Verify checksum. Probably unnecessary, but it's fast. */
149 checksum = 0; 152 checksum = 0;
150 csend = (unsigned char *)(ROM_BASE + p[3] + p[4]); 153 csend = (unsigned char *)(ROM_BASE + p[3] + p[4]);
151 for(csp = (unsigned char *)(ROM_BASE + p[3]); csp < csend; csp++) { 154 for(csp = (unsigned char *)(ROM_BASE + p[3]); csp < csend; csp++)
155 {
152 checksum += *csp; 156 checksum += *csp;
153 } 157 }
154 158
@@ -202,8 +206,8 @@ static void lcd_tick(void)
202 { 206 {
203 unsigned data = bcm_read32(BCMA_COMMAND); 207 unsigned data = bcm_read32(BCMA_COMMAND);
204 bool bcm_is_busy = (data == BCMCMD_LCD_UPDATE || data == 0xFFFF); 208 bool bcm_is_busy = (data == BCMCMD_LCD_UPDATE || data == 0xFFFF);
205 209
206 if (((lcd_state.state == LCD_NEED_UPDATE) && !bcm_is_busy) 210 if (((lcd_state.state == LCD_NEED_UPDATE) && !bcm_is_busy)
207 /* Update requested and BCM is no longer busy. */ 211 /* Update requested and BCM is no longer busy. */
208 || (TIME_AFTER(current_tick, lcd_state.update_timeout) && bcm_is_busy)) 212 || (TIME_AFTER(current_tick, lcd_state.update_timeout) && bcm_is_busy))
209 /* BCM still busy after timeout, i.e. stalled. */ 213 /* BCM still busy after timeout, i.e. stalled. */
@@ -257,7 +261,7 @@ static void lcd_unblock_and_update(void)
257#endif 261#endif
258 data = bcm_read32(BCMA_COMMAND); 262 data = bcm_read32(BCMA_COMMAND);
259 bcm_is_busy = (data == BCMCMD_LCD_UPDATE || data == 0xFFFF); 263 bcm_is_busy = (data == BCMCMD_LCD_UPDATE || data == 0xFFFF);
260 264
261 if (!bcm_is_busy || (lcd_state.state == LCD_INITIAL) || 265 if (!bcm_is_busy || (lcd_state.state == LCD_INITIAL) ||
262 TIME_AFTER(current_tick, lcd_state.update_timeout)) 266 TIME_AFTER(current_tick, lcd_state.update_timeout))
263 { 267 {
@@ -275,7 +279,7 @@ static void lcd_unblock_and_update(void)
275 lcd_state.state = LCD_NEED_UPDATE; /* Post update request */ 279 lcd_state.state = LCD_NEED_UPDATE; /* Post update request */
276 } 280 }
277 lcd_state.blocked = false; 281 lcd_state.blocked = false;
278 282
279#if NUM_CORES > 1 283#if NUM_CORES > 1
280 corelock_unlock(&lcd_state.cl); 284 corelock_unlock(&lcd_state.cl);
281#endif 285#endif
@@ -289,7 +293,7 @@ static void lcd_unblock_and_update(void)
289static void lcd_unblock_and_update(void) 293static void lcd_unblock_and_update(void)
290{ 294{
291 unsigned data; 295 unsigned data;
292 296
293 if (lcd_state.state != LCD_INITIAL) 297 if (lcd_state.state != LCD_INITIAL)
294 { 298 {
295 data = bcm_read32(BCMA_COMMAND); 299 data = bcm_read32(BCMA_COMMAND);
@@ -333,7 +337,7 @@ void lcd_init_device(void)
333 the BCM. None of it is changed when shutting down the BCM. 337 the BCM. None of it is changed when shutting down the BCM.
334 */ 338 */
335 GPO32_ENABLE |= 0xC000; 339 GPO32_ENABLE |= 0xC000;
336 GPIO_CLEAR_BITWISE(GPIOC_ENABLE, 0x80); 340 GPIO_CLEAR_BITWISE(GPIOC_ENABLE, 0x80);
337 /* This pin is used for BCM interrupts */ 341 /* This pin is used for BCM interrupts */
338 GPIOC_ENABLE |= 0x40; 342 GPIOC_ENABLE |= 0x40;
339 GPIOC_OUTPUT_EN &= ~0x40; 343 GPIOC_OUTPUT_EN &= ~0x40;
@@ -346,11 +350,12 @@ void lcd_init_device(void)
346 corelock_init(&lcd_state.cl); 350 corelock_init(&lcd_state.cl);
347#endif 351#endif
348#ifdef HAVE_LCD_SLEEP 352#ifdef HAVE_LCD_SLEEP
349 if (!flash_get_section(ROM_ID('v', 'm', 'c', 's'), 353 if (!flash_get_section(ROM_ID('v', 'm', 'c', 's'),
350 (void **)(&flash_vmcs_offset), &flash_vmcs_length)) 354 (void **)(&flash_vmcs_offset), &flash_vmcs_length))
351 /* BCM cannot be shut down because firmware wasn't found */ 355 /* BCM cannot be shut down because firmware wasn't found */
352 flash_vmcs_length = 0; 356 flash_vmcs_length = 0;
353 else { 357 else
358 {
354 /* lcd_write_data needs an even number of 16 bit values */ 359 /* lcd_write_data needs an even number of 16 bit values */
355 flash_vmcs_length = ((flash_vmcs_length + 3) >> 1) & ~1; 360 flash_vmcs_length = ((flash_vmcs_length + 3) >> 1) & ~1;
356 } 361 }
@@ -358,15 +363,15 @@ void lcd_init_device(void)
358 wakeup_init(&(lcd_state.initwakeup)); 363 wakeup_init(&(lcd_state.initwakeup));
359 lcd_state.waking = false; 364 lcd_state.waking = false;
360 365
361 if (GPO32_VAL & 0x4000) 366 if (GPO32_VAL & 0x4000)
362 { 367 {
363 /* BCM is powered. Assume it is initialized. */ 368 /* BCM is powered. Assume it is initialized. */
364 lcd_state.display_on = true; 369 lcd_state.display_on = true;
365 tick_add_task(&lcd_tick); 370 tick_add_task(&lcd_tick);
366 } 371 }
367 else 372 else
368 { 373 {
369 /* BCM is not powered, so it needs to be initialized. 374 /* BCM is not powered, so it needs to be initialized.
370 This can only happen when loading Rockbox via ROLO. 375 This can only happen when loading Rockbox via ROLO.
371 */ 376 */
372 lcd_state.update_timeout = current_tick; 377 lcd_state.update_timeout = current_tick;
@@ -375,7 +380,7 @@ void lcd_init_device(void)
375 } 380 }
376#else /* !HAVE_LCD_SLEEP */ 381#else /* !HAVE_LCD_SLEEP */
377 tick_add_task(&lcd_tick); 382 tick_add_task(&lcd_tick);
378#endif 383#endif
379#endif /* !BOOTLOADER */ 384#endif /* !BOOTLOADER */
380} 385}
381 386
@@ -396,7 +401,7 @@ void lcd_update_rect(int x, int y, int width, int height)
396 width = LCD_WIDTH - x; 401 width = LCD_WIDTH - x;
397 if (y + height >= LCD_HEIGHT) 402 if (y + height >= LCD_HEIGHT)
398 height = LCD_HEIGHT - y; 403 height = LCD_HEIGHT - y;
399 404
400 if ((width <= 0) || (height <= 0)) 405 if ((width <= 0) || (height <= 0))
401 return; /* Nothing left to do. */ 406 return; /* Nothing left to do. */
402 407
@@ -404,7 +409,7 @@ void lcd_update_rect(int x, int y, int width, int height)
404 * writes and would just ignore them. */ 409 * writes and would just ignore them. */
405 width = (width + (x & 1) + 1) & ~1; 410 width = (width + (x & 1) + 1) & ~1;
406 x &= ~1; 411 x &= ~1;
407 412
408 /* Prevent the tick from triggering BCM updates while we're writing. */ 413 /* Prevent the tick from triggering BCM updates while we're writing. */
409 lcd_block_tick(); 414 lcd_block_tick();
410 415
@@ -442,7 +447,7 @@ extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
442 unsigned bcmaddr, 447 unsigned bcmaddr,
443 int width, 448 int width,
444 int stride); 449 int stride);
445 450
446/* Performance function to blit a YUV bitmap directly to the LCD */ 451/* Performance function to blit a YUV bitmap directly to the LCD */
447void lcd_blit_yuv(unsigned char * const src[3], 452void lcd_blit_yuv(unsigned char * const src[3],
448 int src_x, int src_y, int stride, 453 int src_x, int src_y, int stride,
@@ -478,24 +483,26 @@ void lcd_blit_yuv(unsigned char * const src[3],
478 yuv_src[0] += stride << 1; 483 yuv_src[0] += stride << 1;
479 yuv_src[1] += stride >> 1; /* Skip down one chroma line */ 484 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
480 yuv_src[2] += stride >> 1; 485 yuv_src[2] += stride >> 1;
481 } 486 }
482 while (--height > 0); 487 while (--height > 0);
483 488
484 lcd_unblock_and_update(); 489 lcd_unblock_and_update();
485} 490}
486 491
487#ifdef HAVE_LCD_SLEEP 492#ifdef HAVE_LCD_SLEEP
488/* Executes a BCM command immediately and waits for it to complete. 493/* Executes a BCM command immediately and waits for it to complete.
489 Other BCM commands (eg. LCD updates or lcd_tick) must not interfere. 494 Other BCM commands (eg. LCD updates or lcd_tick) must not interfere.
490 */ 495 */
491static void bcm_command(unsigned cmd) { 496static void bcm_command(unsigned cmd)
497{
492 unsigned status; 498 unsigned status;
493 499
494 bcm_write32(BCMA_COMMAND, cmd); 500 bcm_write32(BCMA_COMMAND, cmd);
495 501
496 BCM_CONTROL = 0x31; 502 BCM_CONTROL = 0x31;
497 503
498 while (1) { 504 while (1)
505 {
499 status = bcm_read32(BCMA_COMMAND); 506 status = bcm_read32(BCMA_COMMAND);
500 if (status != cmd && status != 0xFFFF) 507 if (status != cmd && status != 0xFFFF)
501 break; 508 break;
@@ -507,7 +514,7 @@ void bcm_powerdown(void)
507{ 514{
508 bcm_write32(0x10001400, bcm_read32(0x10001400) & ~0xF0); 515 bcm_write32(0x10001400, bcm_read32(0x10001400) & ~0xF0);
509 516
510 /* Blanks the LCD and decreases power consumption 517 /* Blanks the LCD and decreases power consumption
511 below what clearing the LCD would achieve. 518 below what clearing the LCD would achieve.
512 Executing an LCD update command wakes it. 519 Executing an LCD update command wakes it.
513 */ 520 */
@@ -523,17 +530,18 @@ void bcm_powerdown(void)
523} 530}
524 531
525/* Data written to BCM_CONTROL and BCM_ALT_CONTROL */ 532/* Data written to BCM_CONTROL and BCM_ALT_CONTROL */
526const unsigned char bcm_bootstrapdata[] = { 533const unsigned char bcm_bootstrapdata[] =
534{
527 0xA1, 0x81, 0x91, 0x02, 0x12, 0x22, 0x72, 0x62 535 0xA1, 0x81, 0x91, 0x02, 0x12, 0x22, 0x72, 0x62
528}; 536};
529 537
530void bcm_init(void) 538void bcm_init(void)
531{ 539{
532 int i; 540 int i;
533 541
534 /* Power up BCM */ 542 /* Power up BCM */
535 GPO32_VAL |= 0x4000; 543 GPO32_VAL |= 0x4000;
536 sleep(HZ/20); 544 sleep(HZ/20);
537 545
538 /* Bootstrap stage 1 */ 546 /* Bootstrap stage 1 */
539 547
@@ -543,7 +551,7 @@ void bcm_init(void)
543 /* Interrupt-related code for future use 551 /* Interrupt-related code for future use
544 GPIOC_INT_LEV |= 0x40; 552 GPIOC_INT_LEV |= 0x40;
545 GPIOC_INT_EN |= 0x40; 553 GPIOC_INT_EN |= 0x40;
546 CPU_HI_INT_EN |= 0x40000; 554 CPU_HI_INT_EN |= 0x40000;
547 */ 555 */
548 556
549 /* Bootstrap stage 2 */ 557 /* Bootstrap stage 2 */
@@ -551,21 +559,23 @@ void bcm_init(void)
551 while (BCM_ALT_CONTROL & 0x80); 559 while (BCM_ALT_CONTROL & 0x80);
552 while (!(BCM_ALT_CONTROL & 0x40)); 560 while (!(BCM_ALT_CONTROL & 0x40));
553 561
554 for (i = 0; i < 8; i++) { 562 for (i = 0; i < 8; i++)
563 {
555 BCM_CONTROL = bcm_bootstrapdata[i]; 564 BCM_CONTROL = bcm_bootstrapdata[i];
556 } 565 }
557 566
558 for (i = 3; i < 8; i++) { 567 for (i = 3; i < 8; i++)
568 {
559 BCM_ALT_CONTROL = bcm_bootstrapdata[i]; 569 BCM_ALT_CONTROL = bcm_bootstrapdata[i];
560 } 570 }
561 571
562 while ((BCM_RD_ADDR & 1) == 0 || (BCM_ALT_RD_ADDR & 1) == 0); 572 while ((BCM_RD_ADDR & 1) == 0 || (BCM_ALT_RD_ADDR & 1) == 0);
563 573
564 (void)BCM_WR_ADDR; 574 (void)BCM_WR_ADDR;
565 (void)BCM_ALT_WR_ADDR; 575 (void)BCM_ALT_WR_ADDR;
566 576
567 /* Bootstrap stage 3: upload firmware */ 577 /* Bootstrap stage 3: upload firmware */
568 578
569 while (BCM_ALT_CONTROL & 0x80); 579 while (BCM_ALT_CONTROL & 0x80);
570 while (!(BCM_ALT_CONTROL & 0x40)); 580 while (!(BCM_ALT_CONTROL & 0x40));
571 581
@@ -575,12 +585,12 @@ void bcm_init(void)
575 585
576 bcm_write32(BCMA_COMMAND, 0); 586 bcm_write32(BCMA_COMMAND, 0);
577 bcm_write32(0x10000C00, 0xC0000000); 587 bcm_write32(0x10000C00, 0xC0000000);
578 588
579 while (!(bcm_read32(0x10000C00) & 1)); 589 while (!(bcm_read32(0x10000C00) & 1));
580 590
581 bcm_write32(0x10000C00, 0); 591 bcm_write32(0x10000C00, 0);
582 bcm_write32(0x10000400, 0xA5A50002); 592 bcm_write32(0x10000400, 0xA5A50002);
583 593
584 while (bcm_read32(BCMA_COMMAND) == 0) 594 while (bcm_read32(BCMA_COMMAND) == 0)
585 yield(); 595 yield();
586 596
@@ -605,7 +615,7 @@ void lcd_awake(void)
605 lcd_update(); 615 lcd_update();
606 lcd_state.update_timeout = current_tick + BCM_LCDINIT_TIMEOUT; 616 lcd_state.update_timeout = current_tick + BCM_LCDINIT_TIMEOUT;
607 617
608 /* Wait for end of first LCD update, so LCD isn't white 618 /* Wait for end of first LCD update, so LCD isn't white
609 when the backlight turns on. 619 when the backlight turns on.
610 */ 620 */
611 lcd_state.waking = true; 621 lcd_state.waking = true;
@@ -617,16 +627,17 @@ void lcd_awake(void)
617 mutex_unlock(&lcdstate_lock); 627 mutex_unlock(&lcdstate_lock);
618} 628}
619 629
620void lcd_sleep(void) 630void lcd_sleep(void)
621{ 631{
622 mutex_lock(&lcdstate_lock); 632 mutex_lock(&lcdstate_lock);
623 if (lcd_state.display_on && flash_vmcs_length != 0) { 633 if (lcd_state.display_on && flash_vmcs_length != 0)
634 {
624 lcd_state.display_on = false; 635 lcd_state.display_on = false;
625 636
626 /* Wait for BCM to finish work */ 637 /* Wait for BCM to finish work */
627 while (lcd_state.state != LCD_INITIAL && lcd_state.state != LCD_IDLE) 638 while (lcd_state.state != LCD_INITIAL && lcd_state.state != LCD_IDLE)
628 yield(); 639 yield();
629 640
630 tick_remove_task(&lcd_tick); 641 tick_remove_task(&lcd_tick);
631 bcm_powerdown(); 642 bcm_powerdown();
632 643
@@ -642,7 +653,7 @@ bool lcd_active(void)
642} 653}
643 654
644#ifdef HAVE_LCD_SHUTDOWN 655#ifdef HAVE_LCD_SHUTDOWN
645void lcd_shutdown(void) 656void lcd_shutdown(void)
646{ 657{
647 lcd_sleep(); 658 lcd_sleep();
648} 659}