summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndree Buschmann <AndreeBuschmann@t-online.de>2009-02-21 11:10:50 +0000
committerAndree Buschmann <AndreeBuschmann@t-online.de>2009-02-21 11:10:50 +0000
commitc567fc9be20d12b9f6e246dffa99472b66677c28 (patch)
tree20cb2bec2853c8c9b9d8c08368b1dd2efce40e8c
parent34e120928447d4afbaae1fac2477f1975a100e0c (diff)
downloadrockbox-c567fc9be20d12b9f6e246dffa99472b66677c28.tar.gz
rockbox-c567fc9be20d12b9f6e246dffa99472b66677c28.zip
Submit FS#9890 by Boris Gjenero. Enabling option for iPod Video to shut down LCD and BCM (controller) after backlight was switched off. With this option the user can decide whether to keep the transflective LCD switched on (e.g. during daylight use) or to switch it off (to save power). The power saving is extreme and increases the battery runtime by far (measured >30%).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20076 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/export/config-ipodvideo.h8
-rw-r--r--firmware/target/arm/ipod/backlight-nano_video.c11
-rw-r--r--firmware/target/arm/ipod/backlight-target.h4
-rw-r--r--firmware/target/arm/ipod/power-ipod.c2
-rw-r--r--firmware/target/arm/ipod/video/lcd-video.c316
5 files changed, 314 insertions, 27 deletions
diff --git a/firmware/export/config-ipodvideo.h b/firmware/export/config-ipodvideo.h
index ca8e43db77..fb00fd99d1 100644
--- a/firmware/export/config-ipodvideo.h
+++ b/firmware/export/config-ipodvideo.h
@@ -204,4 +204,12 @@
204#define IPOD_ACCESSORY_PROTOCOL 204#define IPOD_ACCESSORY_PROTOCOL
205#define HAVE_SERIAL 205#define HAVE_SERIAL
206 206
207#ifndef BOOTLOADER
208/* Support for LCD sleep/BCM shutdown */
209#define HAVE_LCD_SLEEP
210#define HAVE_LCD_SLEEP_SETTING
211/* The same code may also be used when shutting down the iPod */
212#define HAVE_LCD_SHUTDOWN
213#endif
214
207#endif 215#endif
diff --git a/firmware/target/arm/ipod/backlight-nano_video.c b/firmware/target/arm/ipod/backlight-nano_video.c
index 5eb5198b73..2f56f94225 100644
--- a/firmware/target/arm/ipod/backlight-nano_video.c
+++ b/firmware/target/arm/ipod/backlight-nano_video.c
@@ -73,9 +73,18 @@ void _backlight_set_brightness(int val)
73 73
74void _backlight_hw_enable(bool on) 74void _backlight_hw_enable(bool on)
75{ 75{
76#ifdef HAVE_LCD_SLEEP
77 if (on)
78 /* If the fade-out is interrupted, enabled will be true, but
79 lcd_awake() needs to be called anyways because the LCD
80 may be sleeping.
81 */
82 lcd_awake();
83#endif
84
76 if (on == enabled) 85 if (on == enabled)
77 return; 86 return;
78 87
79 if (on) 88 if (on)
80 { 89 {
81 GPIO_SET_BITWISE(GPIOB_OUTPUT_VAL, 0x08); 90 GPIO_SET_BITWISE(GPIOB_OUTPUT_VAL, 0x08);
diff --git a/firmware/target/arm/ipod/backlight-target.h b/firmware/target/arm/ipod/backlight-target.h
index 50a7a0c7f1..28c519e4c0 100644
--- a/firmware/target/arm/ipod/backlight-target.h
+++ b/firmware/target/arm/ipod/backlight-target.h
@@ -29,6 +29,10 @@ void _backlight_led_on(void);
29void _backlight_led_off(void); 29void _backlight_led_off(void);
30void _backlight_hw_enable(bool on); 30void _backlight_hw_enable(bool on);
31 31
32#ifdef HAVE_LCD_SLEEP
33void lcd_awake(void);
34#endif
35
32#ifdef BOOTLOADER 36#ifdef BOOTLOADER
33#define _backlight_on() do { _backlight_hw_enable(true); \ 37#define _backlight_on() do { _backlight_hw_enable(true); \
34 _backlight_led_on(); } while(0) 38 _backlight_led_on(); } while(0)
diff --git a/firmware/target/arm/ipod/power-ipod.c b/firmware/target/arm/ipod/power-ipod.c
index 4c6df882c6..66d703859c 100644
--- a/firmware/target/arm/ipod/power-ipod.c
+++ b/firmware/target/arm/ipod/power-ipod.c
@@ -130,7 +130,7 @@ bool ide_powered(void)
130 130
131void power_off(void) 131void power_off(void)
132{ 132{
133#if defined(HAVE_LCD_COLOR) 133#if defined(HAVE_LCD_COLOR) && !defined(HAVE_LCD_SHUTDOWN)
134 /* Clear the screen and backdrop to 134 /* Clear the screen and backdrop to
135 remove ghosting effect on shutdown */ 135 remove ghosting effect on shutdown */
136 lcd_set_backdrop(NULL); 136 lcd_set_backdrop(NULL);
diff --git a/firmware/target/arm/ipod/video/lcd-video.c b/firmware/target/arm/ipod/video/lcd-video.c
index 6e5523d72c..d1701ea3d7 100644
--- a/firmware/target/arm/ipod/video/lcd-video.c
+++ b/firmware/target/arm/ipod/video/lcd-video.c
@@ -30,6 +30,10 @@
30#include "lcd.h" 30#include "lcd.h"
31#include "kernel.h" 31#include "kernel.h"
32#include "system.h" 32#include "system.h"
33#ifdef HAVE_LCD_SLEEP
34/* Included only for lcd_awake() prototype */
35#include "backlight-target.h"
36#endif
33 37
34/* The BCM bus width is 16 bits. But since the low address bits aren't decoded 38/* The BCM bus width is 16 bits. But since the low address bits aren't decoded
35 * by the chip (the 3 BCM address bits are mapped to address bits 16..18 of the 39 * by the chip (the 3 BCM address bits are mapped to address bits 16..18 of the
@@ -50,12 +54,36 @@
50#define BCM_ALT_RD_ADDR32 (*(volatile unsigned long *)(0x30060000)) 54#define BCM_ALT_RD_ADDR32 (*(volatile unsigned long *)(0x30060000))
51#define BCM_ALT_CONTROL (*(volatile unsigned short*)(0x30070000)) 55#define BCM_ALT_CONTROL (*(volatile unsigned short*)(0x30070000))
52 56
53#define BCM_FB_BASE 0xE0020 /* Address of internal BCM framebuffer */
54
55/* 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.
56 * Must be guaranteed to be >~ 20ms. */ 58 * Must be guaranteed to be >~ 20ms. */
57#define BCM_UPDATE_TIMEOUT (HZ/20) 59#define BCM_UPDATE_TIMEOUT (HZ/20)
58 60
61/* Addresses within BCM */
62#define BCMA_SRAM_BASE 0
63#define BCMA_COMMAND 0x1F8
64#define BCMA_STATUS 0x1FC
65#define BCMA_CMDPARAM 0xE0000 /* Parameters/data for commands */
66#define BCMA_SDRAM_BASE 0xC0000000
67#define BCMA_TV_FB 0xC0000000 /* TV out framebuffer */
68#define BCMA_TV_BMPDATA 0xC0200000 /* BMP data for TV out functions */
69
70/* BCM commands. Write them to BCMA_COMMAND. Note BCM_CMD encoding. */
71#define BCM_CMD(x) ((~((unsigned long)x) << 16) | ((unsigned long)x))
72#define BCMCMD_LCD_UPDATE BCM_CMD(0)
73/* Execute "M25 Diagnostics". Status displayed on LCD. Takes <40s */
74#define BCMCMD_SELFTEST BCM_CMD(1)
75#define BCMCMD_TV_PALBMP BCM_CMD(2)
76#define BCMCMD_TV_NTSCBMP BCM_CMD(3)
77/* BCM_CMD(4) may be another TV-related command */
78/* The following might do more depending on word at 0xE00000 */
79#define BCMCMD_LCD_UPDATERECT BCM_CMD(5)
80#define BCMCMD_LCD_SLEEP BCM_CMD(8)
81/* BCM_CMD(12) involved in shutdown */
82/* Macrovision analog copy prevention is on by default on TV output.
83 Execute this command after enabling TV out to turn it off.
84 */
85#define BCMCMD_TV_MVOFF BCM_CMD(14)
86
59enum lcd_status { 87enum lcd_status {
60 LCD_IDLE, 88 LCD_IDLE,
61 LCD_INITIAL, 89 LCD_INITIAL,
@@ -70,8 +98,60 @@ struct {
70#if NUM_CORES > 1 98#if NUM_CORES > 1
71 struct corelock cl; /* inter-core sync */ 99 struct corelock cl; /* inter-core sync */
72#endif 100#endif
101#ifdef HAVE_LCD_SLEEP
102 bool display_on;
103#endif
73} lcd_state IBSS_ATTR; 104} lcd_state IBSS_ATTR;
74 105
106#ifdef HAVE_LCD_SLEEP
107static long bcm_off_wait;
108const fb_data *flash_vmcs_offset;
109unsigned flash_vmcs_length;
110/* This mutex exists because enabling the backlight by changing a setting
111 will cause multiple concurrent lcd_wake() calls.
112 */
113static struct mutex lcdstate_lock SHAREDBSS_ATTR;
114
115#define ROM_BASE 0x20000000
116#define ROM_ID(a,b,c,d) (unsigned int)( ((unsigned int)(d)) | \
117 (((unsigned int)(c)) << 8) | \
118 (((unsigned int)(b)) << 16) | \
119 (((unsigned int)(a)) << 24) )
120
121/* Get address and length of iPod flash section.
122 Based on part of FS#6721. This may belong elsewhere.
123 (BCM initialization uploads the vmcs section to the BCM.)
124 */
125bool flash_get_section(const unsigned int imageid,
126 void **offset,
127 unsigned int *length)
128{
129 unsigned long *p = (unsigned long*)(ROM_BASE + 0xffe00);
130 unsigned char *csp, *csend;
131 unsigned long checksum;
132
133 /* Find the image in the directory */
134 while (1) {
135 if (p[0] != ROM_ID('f','l','s','h'))
136 return false;
137 if (p[1] == imageid)
138 break;
139 p += 10;
140 }
141
142 *offset = (void *)(ROM_BASE + p[3]);
143 *length = p[4];
144
145 /* Verify checksum. Probably unnecessary, but it's fast. */
146 checksum = 0;
147 csend = (unsigned char *)(ROM_BASE + p[3] + p[4]);
148 for(csp = (unsigned char *)(ROM_BASE + p[3]); csp < csend; csp++) {
149 checksum += *csp;
150 }
151
152 return checksum == p[7];
153}
154#endif /* HAVE_LCD_SLEEP */
75 155
76static inline void bcm_write_addr(unsigned address) 156static inline void bcm_write_addr(unsigned address)
77{ 157{
@@ -99,16 +179,6 @@ static inline unsigned bcm_read32(unsigned address)
99 return BCM_DATA32; /* read value */ 179 return BCM_DATA32; /* read value */
100} 180}
101 181
102static void bcm_setup_rect(unsigned x, unsigned y,
103 unsigned width, unsigned height)
104{
105 bcm_write_addr(0xE0004);
106 BCM_DATA32 = x;
107 BCM_DATA32 = y;
108 BCM_DATA32 = x + width - 1;
109 BCM_DATA32 = y + height - 1;
110}
111
112#ifndef BOOTLOADER 182#ifndef BOOTLOADER
113static void lcd_tick(void) 183static void lcd_tick(void)
114{ 184{
@@ -119,15 +189,15 @@ static void lcd_tick(void)
119 189
120 if (!lcd_state.blocked && lcd_state.state >= LCD_NEED_UPDATE) 190 if (!lcd_state.blocked && lcd_state.state >= LCD_NEED_UPDATE)
121 { 191 {
122 unsigned data = bcm_read32(0x1F8); 192 unsigned data = bcm_read32(BCMA_COMMAND);
123 bool bcm_is_busy = (data == 0xFFFA0005 || data == 0xFFFF); 193 bool bcm_is_busy = (data == BCMCMD_LCD_UPDATE || data == 0xFFFF);
124 194
125 if (((lcd_state.state == LCD_NEED_UPDATE) && !bcm_is_busy) 195 if (((lcd_state.state == LCD_NEED_UPDATE) && !bcm_is_busy)
126 /* Update requested and BCM is no longer busy. */ 196 /* Update requested and BCM is no longer busy. */
127 || (TIME_AFTER(current_tick, lcd_state.update_timeout) && bcm_is_busy)) 197 || (TIME_AFTER(current_tick, lcd_state.update_timeout) && bcm_is_busy))
128 /* BCM still busy after timeout, i.e. stalled. */ 198 /* BCM still busy after timeout, i.e. stalled. */
129 { 199 {
130 bcm_write32(0x1F8, 0xFFFA0005); /* Kick off update */ 200 bcm_write32(BCMA_COMMAND, BCMCMD_LCD_UPDATE); /* Kick off update */
131 BCM_CONTROL = 0x31; 201 BCM_CONTROL = 0x31;
132 lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT; 202 lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT;
133 lcd_state.state = LCD_UPDATING; 203 lcd_state.state = LCD_UPDATING;
@@ -166,13 +236,13 @@ static void lcd_unblock_and_update(void)
166#if NUM_CORES > 1 236#if NUM_CORES > 1
167 corelock_lock(&lcd_state.cl); 237 corelock_lock(&lcd_state.cl);
168#endif 238#endif
169 data = bcm_read32(0x1F8); 239 data = bcm_read32(BCMA_COMMAND);
170 bcm_is_busy = (data == 0xFFFA0005 || data == 0xFFFF); 240 bcm_is_busy = (data == BCMCMD_LCD_UPDATE || data == 0xFFFF);
171 241
172 if (!bcm_is_busy || (lcd_state.state == LCD_INITIAL) || 242 if (!bcm_is_busy || (lcd_state.state == LCD_INITIAL) ||
173 TIME_AFTER(current_tick, lcd_state.update_timeout)) 243 TIME_AFTER(current_tick, lcd_state.update_timeout))
174 { 244 {
175 bcm_write32(0x1F8, 0xFFFA0005); /* Kick off update */ 245 bcm_write32(BCMA_COMMAND, BCMCMD_LCD_UPDATE); /* Kick off update */
176 BCM_CONTROL = 0x31; 246 BCM_CONTROL = 0x31;
177 lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT; 247 lcd_state.update_timeout = current_tick + BCM_UPDATE_TIMEOUT;
178 lcd_state.state = LCD_UPDATING; 248 lcd_state.state = LCD_UPDATING;
@@ -199,14 +269,14 @@ static void lcd_unblock_and_update(void)
199 269
200 if (lcd_state.state != LCD_INITIAL) 270 if (lcd_state.state != LCD_INITIAL)
201 { 271 {
202 data = bcm_read32(0x1F8); 272 data = bcm_read32(BCMA_COMMAND);
203 while (data == 0xFFFA0005 || data == 0xFFFF) 273 while (data == BCMCMD_LCD_UPDATE || data == 0xFFFF)
204 { 274 {
205 yield(); 275 yield();
206 data = bcm_read32(0x1F8); 276 data = bcm_read32(BCMA_COMMAND);
207 } 277 }
208 } 278 }
209 bcm_write32(0x1F8, 0xFFFA0005); /* Kick off update */ 279 bcm_write32(BCMA_COMMAND, BCMCMD_LCD_UPDATE); /* Kick off update */
210 BCM_CONTROL = 0x31; 280 BCM_CONTROL = 0x31;
211 lcd_state.state = LCD_IDLE; 281 lcd_state.state = LCD_IDLE;
212} 282}
@@ -236,13 +306,37 @@ void lcd_set_flip(bool yesno)
236/* LCD init */ 306/* LCD init */
237void lcd_init_device(void) 307void lcd_init_device(void)
238{ 308{
239 bcm_setup_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); 309 /* These port initializations are supposed to be done when initializing
310 the BCM. None of it is changed when shutting down the BCM.
311 */
312 GPO32_ENABLE |= 0x4000;
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);
317 /* This pin is used for BCM interrupts */
318 GPIOC_ENABLE |= 0x40;
319 GPIOC_OUTPUT_EN &= ~0x40;
320 GPO32_ENABLE &= ~1;
321
240 lcd_state.blocked = false; 322 lcd_state.blocked = false;
241 lcd_state.state = LCD_INITIAL; 323 lcd_state.state = LCD_INITIAL;
242#ifndef BOOTLOADER 324#ifndef BOOTLOADER
243#if NUM_CORES > 1 325#if NUM_CORES > 1
244 corelock_init(&lcd_state.cl); 326 corelock_init(&lcd_state.cl);
245#endif 327#endif
328#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'),
331 (void **)(&flash_vmcs_offset), &flash_vmcs_length))
332 /* BCM cannot be shut down because firmware wasn't found */
333 flash_vmcs_length = 0;
334 else {
335 /* lcd_write_data needs an even number of 16 bit values */
336 flash_vmcs_length = ((flash_vmcs_length + 3) >> 1) & ~1;
337 }
338 mutex_init(&lcdstate_lock);
339#endif
246 tick_add_task(&lcd_tick); 340 tick_add_task(&lcd_tick);
247#endif /* !BOOTLOADER */ 341#endif /* !BOOTLOADER */
248} 342}
@@ -255,6 +349,11 @@ void lcd_update_rect(int x, int y, int width, int height)
255 const fb_data *addr; 349 const fb_data *addr;
256 unsigned bcmaddr; 350 unsigned bcmaddr;
257 351
352#ifdef HAVE_LCD_SLEEP
353 if (!lcd_state.display_on)
354 return;
355#endif
356
258 if (x + width >= LCD_WIDTH) 357 if (x + width >= LCD_WIDTH)
259 width = LCD_WIDTH - x; 358 width = LCD_WIDTH - x;
260 if (y + height >= LCD_HEIGHT) 359 if (y + height >= LCD_HEIGHT)
@@ -272,7 +371,7 @@ void lcd_update_rect(int x, int y, int width, int height)
272 lcd_block_tick(); 371 lcd_block_tick();
273 372
274 addr = &lcd_framebuffer[y][x]; 373 addr = &lcd_framebuffer[y][x];
275 bcmaddr = BCM_FB_BASE + (LCD_WIDTH*2) * y + (x << 1); 374 bcmaddr = BCMA_CMDPARAM + (LCD_WIDTH*2) * y + (x << 1);
276 375
277 if (width == LCD_WIDTH) 376 if (width == LCD_WIDTH)
278 { 377 {
@@ -315,6 +414,11 @@ void lcd_blit_yuv(unsigned char * const src[3],
315 off_t z; 414 off_t z;
316 unsigned char const * yuv_src[3]; 415 unsigned char const * yuv_src[3];
317 416
417#ifdef HAVE_LCD_SLEEP
418 if (!lcd_state.display_on)
419 return;
420#endif
421
318 /* Sorry, but width and height must be >= 2 or else */ 422 /* Sorry, but width and height must be >= 2 or else */
319 width &= ~1; 423 width &= ~1;
320 424
@@ -326,7 +430,7 @@ void lcd_blit_yuv(unsigned char * const src[3],
326 /* Prevent the tick from triggering BCM updates while we're writing. */ 430 /* Prevent the tick from triggering BCM updates while we're writing. */
327 lcd_block_tick(); 431 lcd_block_tick();
328 432
329 bcmaddr = BCM_FB_BASE + (LCD_WIDTH*2) * y + (x << 1); 433 bcmaddr = BCMA_CMDPARAM + (LCD_WIDTH*2) * y + (x << 1);
330 height >>= 1; 434 height >>= 1;
331 435
332 do 436 do
@@ -341,3 +445,165 @@ void lcd_blit_yuv(unsigned char * const src[3],
341 445
342 lcd_unblock_and_update(); 446 lcd_unblock_and_update();
343} 447}
448
449#ifdef HAVE_LCD_SLEEP
450/* Executes a BCM command immediately and waits for it to complete.
451 Other BCM commands (eg. LCD updates or lcd_tick) must not interfere.
452 */
453static void bcm_command(unsigned cmd) {
454 unsigned status;
455
456 bcm_write32(BCMA_COMMAND, cmd);
457
458 BCM_CONTROL = 0x31;
459
460 while (1) {
461 status = bcm_read32(BCMA_COMMAND);
462 if (status != cmd && status != 0xFFFF)
463 break;
464 yield();
465 }
466}
467
468void bcm_powerdown(void)
469{
470 bcm_write32(0x10001400, bcm_read32(0x10001400) & ~0xF0);
471
472 /* Blanks the LCD and decreases power consumption
473 below what clearing the LCD would achieve.
474 Executing an LCD update command wakes it.
475 */
476 bcm_command(BCMCMD_LCD_SLEEP);
477
478 /* Not sure if this does anything */
479 bcm_command(BCM_CMD(0xC));
480
481 /* Further cuts power use, probably by powering down BCM.
482 After this point, BCM needs to be bootstrapped
483 */
484 GPO32_VAL &= ~0x4000;
485}
486
487/* Data written to BCM_CONTROL and BCM_ALT_CONTROL */
488const unsigned char bcm_bootstrapdata[] = {
489 0xA1, 0x81, 0x91, 0x02, 0x12, 0x22, 0x72, 0x62
490};
491
492void bcm_init(void)
493{
494 int i;
495
496 /* Power up BCM */
497 GPO32_VAL |= 0x4000;
498
499 /* Changed from HZ/2 to speed up this function */
500 sleep(HZ/8);
501
502 /* Bootstrap stage 1 */
503
504 STRAP_OPT_A &= ~0xF00;
505 outl(0x1313, 0x70000040);
506
507 /* Interrupt-related code for future use
508 GPIOC_INT_LEV |= 0x40;
509 GPIOC_INT_EN |= 0x40;
510 CPU_HI_INT_EN |= 0x40000;
511 */
512
513 /* Bootstrap stage 2 */
514
515 for (i = 0; i < 8; i++) {
516 BCM_CONTROL = bcm_bootstrapdata[i];
517 }
518
519 for (i = 3; i < 8; i++) {
520 BCM_ALT_CONTROL = bcm_bootstrapdata[i];
521 }
522
523 while ((BCM_RD_ADDR & 1) == 0 || (BCM_ALT_RD_ADDR & 1) == 0)
524 yield();
525
526 (void)BCM_WR_ADDR;
527 (void)BCM_ALT_WR_ADDR;
528
529 /* Bootstrap stage 3: upload firmware */
530
531 while (BCM_ALT_CONTROL & 0x80)
532 yield();
533
534 while (!(BCM_ALT_CONTROL & 0x40))
535 yield();
536
537 /* Upload firmware to BCM SRAM */
538 bcm_write_addr(BCMA_SRAM_BASE);
539 lcd_write_data(flash_vmcs_offset, flash_vmcs_length);
540
541 bcm_write32(BCMA_COMMAND, 0);
542 bcm_write32(0x10000C00, 0xC0000000);
543
544 while (!(bcm_read32(0x10000C00) & 1))
545 yield();
546
547 bcm_write32(0x10000C00, 0);
548 bcm_write32(0x10000400, 0xA5A50002);
549
550 while (bcm_read32(BCMA_COMMAND) == 0)
551 yield();
552
553 /* sleep(HZ/2) apparently unneeded */
554}
555
556void lcd_awake(void)
557{
558 mutex_lock(&lcdstate_lock);
559 if (!lcd_state.display_on && flash_vmcs_length != 0)
560 {
561 /* Ensure BCM has been off for 1/2 s at least */
562 while (!TIME_AFTER(current_tick, lcd_state.update_timeout))
563 yield();
564
565 bcm_init();
566
567 /* Update LCD, but don't use lcd_update(). Instead, wait here
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;
576 tick_add_task(&lcd_tick);
577 lcd_state.display_on = true;
578 /* Note that only the RGB data from lcd_framebuffer has been
579 displayed. If YUV data was displayed, it needs to be updated
580 now. (eg. see lcd_call_enable_hook())
581 */
582 }
583 mutex_unlock(&lcdstate_lock);
584}
585
586void lcd_sleep(void)
587{
588 mutex_lock(&lcdstate_lock);
589 if (lcd_state.display_on && flash_vmcs_length != 0) {
590 lcd_state.display_on = false;
591
592 /* Wait for BCM to finish work */
593 while (lcd_state.state != LCD_INITIAL && lcd_state.state != LCD_IDLE)
594 yield();
595
596 tick_remove_task(&lcd_tick);
597 bcm_powerdown();
598 bcm_off_wait = current_tick + HZ/2;
599 }
600 mutex_unlock(&lcdstate_lock);
601}
602
603#ifdef HAVE_LCD_SHUTDOWN
604void lcd_shutdown(void)
605{
606 lcd_sleep();
607}
608#endif /* HAVE_LCD_SHUTDOWN */
609#endif /* HAVE_LCD_SLEEP */