diff options
Diffstat (limited to 'firmware/target/arm/sandisk/sansa-e200/lcd-e200.c')
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/lcd-e200.c | 496 |
1 files changed, 355 insertions, 141 deletions
diff --git a/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c b/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c index 86f12567b4..3b55bdd15e 100644 --- a/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c | |||
@@ -26,6 +26,20 @@ | |||
26 | #include "backlight-target.h" | 26 | #include "backlight-target.h" |
27 | #include "pp5024.h" | 27 | #include "pp5024.h" |
28 | 28 | ||
29 | /* Power and display status */ | ||
30 | static bool power_on = false; /* Is the power turned on? */ | ||
31 | static bool display_on NOCACHEBSS_ATTR = false; /* Is the display turned on? */ | ||
32 | |||
33 | /* Reverse Flag */ | ||
34 | #define R_DISP_CONTROL_NORMAL 0x0004 | ||
35 | #define R_DISP_CONTROL_REV 0x0000 | ||
36 | static unsigned short r_disp_control_rev = R_DISP_CONTROL_NORMAL; | ||
37 | |||
38 | /* Flipping */ | ||
39 | #define R_DRV_OUTPUT_CONTROL_NORMAL 0x101b | ||
40 | #define R_DRV_OUTPUT_CONTROL_FLIPPED 0x131b | ||
41 | static unsigned short r_drv_output_control = R_DRV_OUTPUT_CONTROL_NORMAL; | ||
42 | |||
29 | #define LCD_DATA_IN_GPIO GPIOB_INPUT_VAL | 43 | #define LCD_DATA_IN_GPIO GPIOB_INPUT_VAL |
30 | #define LCD_DATA_IN_PIN 6 | 44 | #define LCD_DATA_IN_PIN 6 |
31 | 45 | ||
@@ -168,7 +182,177 @@ static unsigned long phys_fb_address(unsigned long address) | |||
168 | } | 182 | } |
169 | } | 183 | } |
170 | 184 | ||
171 | inline void lcd_init_device(void) | 185 | /* Run the powerup sequence for the driver IC */ |
186 | static void lcd_power_on(void) | ||
187 | { | ||
188 | /* Clear standby bit */ | ||
189 | lcd_write_reg(R_POWER_CONTROL1, 0x0000); | ||
190 | |||
191 | /** Power ON Sequence **/ | ||
192 | lcd_write_reg(R_START_OSC, 0x0001); | ||
193 | /* 10ms or more for oscillation circuit to stabilize */ | ||
194 | sleep(HZ/50); | ||
195 | |||
196 | /* SAP2-0=100, BT2-0=100, AP2-0=100, DK=1, SLP=0, STB=0 */ | ||
197 | lcd_write_reg(R_POWER_CONTROL1, 0x4444); | ||
198 | /* DC12-10=000, DC2-0=000, VC2-0=001 */ | ||
199 | lcd_write_reg(R_POWER_CONTROL2, 0x0001); | ||
200 | /* PON=0, VRH3-0=0011 */ | ||
201 | lcd_write_reg(R_POWER_CONTROL3, 0x0003); | ||
202 | /* VCOMG=0, VDV4-0=10001, VCM3-0=11001 */ | ||
203 | lcd_write_reg(R_POWER_CONTROL4, 0x1119); | ||
204 | /* PON=1, VRH3-0=0011 */ | ||
205 | lcd_write_reg(R_POWER_CONTROL3, 0x0013); | ||
206 | sleep(HZ/25); | ||
207 | |||
208 | /* SAP2-0=100, BT2-0=100, AP2-0=100, DK=0, SLP=0, STB=0 */ | ||
209 | lcd_write_reg(R_POWER_CONTROL1, 0x4440); | ||
210 | /* VCOMG=1, VDV4-0=10001, VCM3-0=11001 */ | ||
211 | lcd_write_reg(R_POWER_CONTROL4, 0x3119); | ||
212 | sleep(HZ/6); | ||
213 | |||
214 | /* VSPL=0, HSPL=0, DPL=1, EPL=0, SM=0, GS=x, SS=x, NL4-0=11011 */ | ||
215 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, r_drv_output_control); | ||
216 | /* FLD=0, FLD0=1, B/C=1, EOR=1, NW5-0=000000 */ | ||
217 | lcd_write_reg(R_DRV_WAVEFORM_CONTROL, 0x0700); | ||
218 | /* TRI=0, DFM1-0=11, BGR=0, HWM=1, ID1-0=10, AM=0, LG2-0=000 | ||
219 | * AM: horizontal update direction | ||
220 | * ID1-0: H decrement, V increment | ||
221 | */ | ||
222 | lcd_write_reg(R_ENTRY_MODE, 0x6020); | ||
223 | lcd_write_reg(R_COMPARE_REG1, 0x0000); | ||
224 | lcd_write_reg(R_COMPARE_REG2, 0x0000); | ||
225 | /* FP3-0=0001, BP3-0=0010 */ | ||
226 | lcd_write_reg(R_DISP_CONTROL2, 0x0102); | ||
227 | /* PTG1-0=00 (normal scan), ISC3-0=0000 (ignored) */ | ||
228 | lcd_write_reg(R_DISP_CONTROL3, 0x0000); | ||
229 | /* NO2-0=01, SDT1-0=00, EQ1-0=01, DIV1-0=00, RTN3-0=0000 */ | ||
230 | lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4400); | ||
231 | /* RM=1, DM1-0=01, RIM1-0=00 */ | ||
232 | lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110); | ||
233 | /* SCN4-0=00000 - G1 if GS=0, G240 if GS=1 */ | ||
234 | lcd_write_reg(R_GATE_SCAN_START_POS, 0x0000); | ||
235 | /* VL7-0=00000000 (0 lines) */ | ||
236 | lcd_write_reg(R_VERT_SCROLL_CONTROL, 0x0000); | ||
237 | /* SE17-10=219, SS17-10=0 - 220 gates */ | ||
238 | lcd_write_reg(R_1ST_SCR_DRIVE_POS, (219 << 8)); | ||
239 | /* SE27-10=0, SS27-10=0 - no second screen */ | ||
240 | lcd_write_reg(R_2ND_SCR_DRIVE_POS, 0x0000); | ||
241 | /* HEA=175, HSA=0 = H window from 0-175 */ | ||
242 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (175 << 8)); | ||
243 | /* VEA=219, VSA=0 = V window from 0-219 */ | ||
244 | lcd_write_reg(R_VERT_RAM_ADDR_POS, (219 << 8)); | ||
245 | /* PKP12-10=000, PKP02-00=000 */ | ||
246 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0000); | ||
247 | /* PKP32-30=111, PKP22-20=100 */ | ||
248 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS2, 0x0704); | ||
249 | /* PKP52-50=001, PKP42-40=111 */ | ||
250 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS3, 0x0107); | ||
251 | /* PRP12-10=111, PRP02-00=100 */ | ||
252 | lcd_write_reg(R_GAMMA_GRAD_ADJ_POS, 0x0704); | ||
253 | /* PKN12-10=001, PKN02-00=111 */ | ||
254 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1, 0x0107); | ||
255 | /* PKN32-30=000, PKN22-20=010 */ | ||
256 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2, 0x0002); | ||
257 | /* PKN52-50=111, PKN42-40=111 */ | ||
258 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3, 0x0707); | ||
259 | /* PRN12-10=101, PRN02-00=011 */ | ||
260 | lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG, 0x0503); | ||
261 | /* VRP14-10=00000, VRP03-00=0000 */ | ||
262 | lcd_write_reg(R_GAMMA_AMP_ADJ_POS, 0x0000); | ||
263 | /* WRN14-10=00000, VRN03-00=0000 */ | ||
264 | lcd_write_reg(R_GAMMA_AMP_ADJ_NEG, 0x0000); | ||
265 | /* AD15-0=175 (upper right corner) */ | ||
266 | lcd_write_reg(R_RAM_ADDR_SET, 175); | ||
267 | /* RM=1, DM1-0=01, RIM1-0=00 */ | ||
268 | lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110); | ||
269 | |||
270 | power_on = true; | ||
271 | } | ||
272 | |||
273 | /* Run the display on sequence for the driver IC */ | ||
274 | static void lcd_display_on(void) | ||
275 | { | ||
276 | if (!power_on) | ||
277 | { | ||
278 | /* Power has been turned off so full reinit is needed */ | ||
279 | lcd_power_on(); | ||
280 | } | ||
281 | else | ||
282 | { | ||
283 | /* Restore what we fiddled with when turning display off */ | ||
284 | /* PON=1, VRH3-0=0011 */ | ||
285 | lcd_write_reg(R_POWER_CONTROL3, 0x0013); | ||
286 | /* NO2-0=01, SDT1-0=00, EQ1-0=01, DIV1-0=00, RTN3-0=0000 */ | ||
287 | lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4400); | ||
288 | /* VCOMG=1, VDV4-0=10001, VCM3-0=11001 */ | ||
289 | lcd_write_reg(R_POWER_CONTROL4, 0x3119); | ||
290 | } | ||
291 | |||
292 | /* SAP2-0=100, BT2-0=111, AP2-0=100, DK=1, SLP=0, STB=0 */ | ||
293 | lcd_write_reg(R_POWER_CONTROL1, 0x4740); | ||
294 | |||
295 | sleep(HZ/25); | ||
296 | |||
297 | /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=0, DTE=0, CL=0, | ||
298 | REV=x, D1-0=01 */ | ||
299 | lcd_write_reg(R_DISP_CONTROL1, 0x0041 | r_disp_control_rev); | ||
300 | |||
301 | udelay(HZ/20); | ||
302 | |||
303 | /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0, | ||
304 | REV=x, D1-0=01 */ | ||
305 | lcd_write_reg(R_DISP_CONTROL1, 0x0061 | r_disp_control_rev); | ||
306 | /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0, | ||
307 | REV=x, D1-0=11 */ | ||
308 | lcd_write_reg(R_DISP_CONTROL1, 0x0063 | r_disp_control_rev); | ||
309 | |||
310 | udelay(HZ/20); | ||
311 | |||
312 | /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=1, CL=0, | ||
313 | REV=x, D1-0=11 */ | ||
314 | lcd_write_reg(R_DISP_CONTROL1, 0x0073 | r_disp_control_rev); | ||
315 | |||
316 | /* Go into write data mode */ | ||
317 | lcd_send_msg(0x70, R_RAM_WRITE_DATA); | ||
318 | |||
319 | /* tell that we're on now */ | ||
320 | display_on = true; | ||
321 | } | ||
322 | |||
323 | /* Turn off visible display operations */ | ||
324 | static void lcd_display_off(void) | ||
325 | { | ||
326 | /* block drawing operations and changing of first */ | ||
327 | display_on = false; | ||
328 | |||
329 | /* NO2-0=01, SDT1-0=00, EQ1-0=00, DIV1-0=00, RTN3-0=0000 */ | ||
330 | lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4000); | ||
331 | |||
332 | /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=1, CL=0, | ||
333 | REV=x, D1-0=10 */ | ||
334 | lcd_write_reg(R_DISP_CONTROL1, 0x0072 | r_disp_control_rev); | ||
335 | |||
336 | sleep(HZ/25); | ||
337 | |||
338 | /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0, | ||
339 | REV=x, D1-0=10 */ | ||
340 | lcd_write_reg(R_DISP_CONTROL1, 0x0062 | r_disp_control_rev); | ||
341 | |||
342 | sleep(HZ/25); | ||
343 | |||
344 | /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=0, GON=0, DTE=0, CL=0, | ||
345 | REV=0, D1-0=00 */ | ||
346 | lcd_write_reg(R_DISP_CONTROL1, 0x0000); | ||
347 | /* SAP2-0=000, BT2-0=000, AP2-0=000, DK=0, SLP=0, STBY=0 */ | ||
348 | lcd_write_reg(R_POWER_CONTROL1, 0x0000); | ||
349 | /* PON=0, VRH3-0=0011 */ | ||
350 | lcd_write_reg(R_POWER_CONTROL3, 0x0003); | ||
351 | /* VCOMG=0, VDV4-0=10001, VCM4-0=11001 */ | ||
352 | lcd_write_reg(R_POWER_CONTROL4, 0x1119); | ||
353 | } | ||
354 | |||
355 | void lcd_init_device(void) | ||
172 | { | 356 | { |
173 | /* All this is magic worked out by MrH */ | 357 | /* All this is magic worked out by MrH */ |
174 | 358 | ||
@@ -176,6 +360,7 @@ inline void lcd_init_device(void) | |||
176 | LCD_REG_6 &= ~1; | 360 | LCD_REG_6 &= ~1; |
177 | udelay(100000); | 361 | udelay(100000); |
178 | 362 | ||
363 | #ifdef BOOTLOADER /* Bother at all to do this again? */ | ||
179 | /* Init GPIO ports */ | 364 | /* Init GPIO ports */ |
180 | lcd_init_gpio(); | 365 | lcd_init_gpio(); |
181 | /* Controller init */ | 366 | /* Controller init */ |
@@ -227,145 +412,128 @@ inline void lcd_init_device(void) | |||
227 | udelay(100000); | 412 | udelay(100000); |
228 | 413 | ||
229 | /* LCD init */ | 414 | /* LCD init */ |
230 | 415 | /* Pull RESET low, then high to reset driver IC */ | |
231 | /* TODO: Eliminate some of this outside the bootloader since this | ||
232 | will already be setup and that will eliminate white-screen */ | ||
233 | |||
234 | /* Pull RESET low, then high */ | ||
235 | outl((inl(0x70000080) & ~(1 << 28)), 0x70000080); | 416 | outl((inl(0x70000080) & ~(1 << 28)), 0x70000080); |
236 | udelay(10000); | 417 | udelay(10000); |
237 | outl((inl(0x70000080) | (1 << 28)), 0x70000080); | 418 | outl((inl(0x70000080) | (1 << 28)), 0x70000080); |
238 | udelay(10000); | 419 | udelay(10000); |
239 | 420 | ||
240 | lcd_write_reg(R_POWER_CONTROL1, 0x4444); | 421 | lcd_display_on(); |
241 | lcd_write_reg(R_POWER_CONTROL2, 0x0001); | 422 | #else |
242 | lcd_write_reg(R_POWER_CONTROL3, 0x0003); | 423 | /* Power and display already ON - switch framebuffer address and reset |
243 | lcd_write_reg(R_POWER_CONTROL4, 0x1119); | 424 | settings */ |
244 | lcd_write_reg(R_POWER_CONTROL3, 0x0013); | 425 | LCD_FB_BASE_REG = phys_fb_address((unsigned long)lcd_driver_framebuffer); |
245 | udelay(50000); | ||
246 | |||
247 | lcd_write_reg(R_POWER_CONTROL1, 0x4440); | ||
248 | lcd_write_reg(R_POWER_CONTROL4, 0x3119); | ||
249 | udelay(150000); | ||
250 | |||
251 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, 0x101b); | ||
252 | lcd_write_reg(R_DRV_WAVEFORM_CONTROL, 0x0700); | ||
253 | lcd_write_reg(R_ENTRY_MODE, 0x6020); | ||
254 | lcd_write_reg(R_COMPARE_REG1, 0x0000); | ||
255 | lcd_write_reg(R_COMPARE_REG2, 0x0000); | ||
256 | lcd_write_reg(R_DISP_CONTROL2, 0x0102); | ||
257 | lcd_write_reg(R_DISP_CONTROL3, 0x0000); | ||
258 | lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4400); | ||
259 | lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110); | ||
260 | |||
261 | lcd_write_reg(R_GATE_SCAN_START_POS, 0x0000); | ||
262 | lcd_write_reg(R_VERT_SCROLL_CONTROL, 0x0000); | ||
263 | lcd_write_reg(R_1ST_SCR_DRIVE_POS, (219 << 8)); | ||
264 | lcd_write_reg(R_2ND_SCR_DRIVE_POS, 0x0000); | ||
265 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (175 << 8)); | ||
266 | lcd_write_reg(R_VERT_RAM_ADDR_POS, (219 << 8)); | ||
267 | |||
268 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0000); | ||
269 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS2, 0x0704); | ||
270 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS3, 0x0107); | ||
271 | lcd_write_reg(R_GAMMA_GRAD_ADJ_POS, 0x0704); | ||
272 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1, 0x0107); | ||
273 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2, 0x0002); | ||
274 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3, 0x0707); | ||
275 | lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG, 0x0503); | ||
276 | lcd_write_reg(R_GAMMA_AMP_ADJ_POS, 0x0000); | ||
277 | lcd_write_reg(R_GAMMA_AMP_ADJ_NEG, 0x0000); | ||
278 | |||
279 | lcd_write_reg(R_RAM_ADDR_SET, 175); | ||
280 | |||
281 | lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110); | ||
282 | |||
283 | lcd_write_reg(R_POWER_CONTROL1, 0x4740); | ||
284 | |||
285 | lcd_write_reg(R_DISP_CONTROL1, 0x0045); | ||
286 | |||
287 | udelay(50000); | ||
288 | |||
289 | lcd_write_reg(R_DISP_CONTROL1, 0x0065); | ||
290 | lcd_write_reg(R_DISP_CONTROL1, 0x0067); | ||
291 | |||
292 | udelay(50000); | ||
293 | 426 | ||
294 | lcd_write_reg(R_DISP_CONTROL1, 0x0077); | 427 | power_on = true; |
428 | display_on = true; | ||
295 | 429 | ||
296 | lcd_send_msg(0x70, R_RAM_WRITE_DATA); | 430 | lcd_set_invert_display(false); |
431 | lcd_set_flip(false); | ||
432 | #endif | ||
297 | 433 | ||
298 | LCD_REG_6 |= 1; /* Start DMA */ | 434 | LCD_REG_6 |= 1; /* Start DMA */ |
299 | } | 435 | } |
300 | 436 | ||
301 | void lcd_enable(bool on) | 437 | void lcd_enable(bool on) |
302 | { | 438 | { |
303 | if(on) | 439 | if (on == display_on) |
440 | return; | ||
441 | |||
442 | if (on) | ||
304 | { | 443 | { |
305 | if(!(DEV_EN & DEV_LCD)) | 444 | DEV_EN |= DEV_LCD; /* Enable LCD controller */ |
306 | { | 445 | lcd_display_on(); /* Turn on display */ |
307 | DEV_EN |= DEV_LCD; /* Enable LCD controller */ | 446 | lcd_update(); /* Resync display */ |
308 | lcd_update(); /* Resync display */ | 447 | LCD_REG_6 |= 1; /* Restart DMA */ |
309 | LCD_REG_6 |= 1; /* Restart DMA */ | 448 | sleep(HZ/25); /* Wait for a frame to be written by |
310 | } | 449 | DMA or a white flash will happen */ |
311 | } | 450 | } |
312 | else | 451 | else |
313 | { | 452 | { |
314 | if(DEV_EN & DEV_LCD) | 453 | LCD_REG_6 &= ~1; /* Disable DMA */ |
315 | { | 454 | sleep(HZ/50); /* Wait for dma end (assuming 50Hz) */ |
316 | LCD_REG_6 &= ~1; /* Disable DMA */ | 455 | lcd_display_off(); /* Turn off display */ |
317 | udelay(20000); /* Wait for dma end (assuming 50Hz) */ | 456 | DEV_EN &= ~DEV_LCD; /* Disable LCD controller */ |
318 | DEV_EN &= ~DEV_LCD; /* Disable LCD controller */ | ||
319 | } | ||
320 | } | 457 | } |
321 | } | 458 | } |
322 | 459 | ||
323 | void lcd_update_rect(int x, int y, int width, int height) | 460 | void lcd_sleep(void) |
324 | { | 461 | { |
325 | (void)x; | 462 | LCD_REG_6 &= ~1; |
326 | (void)width; | 463 | sleep(HZ/50); |
327 | 464 | ||
328 | if(DEV_EN & DEV_LCD) | 465 | if (power_on) |
329 | { | 466 | { |
330 | #if 0 | 467 | /* Turn off display */ |
331 | /* Turn off DMA and wait for the transfer to complete */ | 468 | if (display_on) |
332 | /* TODO: Work out the proper delay */ | 469 | lcd_display_off(); |
333 | LCD_REG_6 &= ~1; | 470 | |
334 | udelay(1000); | 471 | power_on = false; |
335 | #endif | ||
336 | /* Copy the Rockbox framebuffer to the second framebuffer */ | ||
337 | /* TODO: Move the second framebuffer into uncached SDRAM */ | ||
338 | memcpy(((char*)&lcd_driver_framebuffer)+(y * sizeof(fb_data) * LCD_WIDTH), | ||
339 | ((char *)&lcd_framebuffer)+(y * sizeof(fb_data) * LCD_WIDTH), | ||
340 | ((height * sizeof(fb_data) * LCD_WIDTH))); | ||
341 | flush_icache(); | ||
342 | #if 0 | ||
343 | /* Restart DMA */ | ||
344 | LCD_REG_6 |= 1; | ||
345 | #endif | ||
346 | } | 472 | } |
473 | |||
474 | /* Set standby mode */ | ||
475 | /* SAP2-0=000, BT2-0=000, AP2-0=000, DK=0, SLP=0, STB=1 */ | ||
476 | lcd_write_reg(R_POWER_CONTROL1, 0x0001); | ||
347 | } | 477 | } |
348 | 478 | ||
349 | void lcd_update(void) | 479 | /* Copies a rectangle from one framebuffer to another. Can be used in |
480 | single transfer mode with width = num pixels, and height = 1 which | ||
481 | allows a full-width rectangle to be copied more efficiently. */ | ||
482 | extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src, | ||
483 | int width, int height); | ||
484 | void lcd_update_rect(int x, int y, int width, int height) | ||
350 | { | 485 | { |
351 | if(DEV_EN & DEV_LCD) | 486 | fb_data *dst, *src; |
487 | |||
488 | if (!display_on) | ||
489 | return; | ||
490 | |||
491 | if (x + width > LCD_WIDTH) | ||
492 | width = LCD_WIDTH - x; /* Clip right */ | ||
493 | if (x < 0) | ||
494 | width += x, x = 0; /* Clip left */ | ||
495 | if (width <= 0) | ||
496 | return; /* nothing left to do */ | ||
497 | |||
498 | if (y + height > LCD_HEIGHT) | ||
499 | height = LCD_HEIGHT - y; /* Clip bottom */ | ||
500 | if (y < 0) | ||
501 | height += y, y = 0; /* Clip top */ | ||
502 | if (height <= 0) | ||
503 | return; /* nothing left to do */ | ||
504 | |||
505 | /* TODO: It may be faster to swap the addresses of lcd_driver_framebuffer | ||
506 | * and lcd_framebuffer */ | ||
507 | dst = &lcd_driver_framebuffer[y][x]; | ||
508 | src = &lcd_framebuffer[y][x]; | ||
509 | |||
510 | /* Copy part of the Rockbox framebuffer to the second framebuffer */ | ||
511 | if (width < LCD_WIDTH) | ||
352 | { | 512 | { |
353 | /* TODO: It may be faster to swap the addresses of lcd_driver_framebuffer | 513 | /* Not full width - do line-by-line */ |
354 | * and lcd_framebuffer */ | 514 | lcd_copy_buffer_rect(dst, src, width, height); |
355 | #if 0 | 515 | } |
356 | /* Turn off DMA and wait for the transfer to complete */ | 516 | else |
357 | LCD_REG_6 &= ~1; | 517 | { |
358 | udelay(1000); | 518 | /* Full width - copy as one line */ |
359 | #endif | 519 | lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1); |
360 | /* Copy the Rockbox framebuffer to the second framebuffer */ | ||
361 | memcpy(lcd_driver_framebuffer, lcd_framebuffer, | ||
362 | sizeof(fb_data) * LCD_WIDTH * LCD_HEIGHT); | ||
363 | flush_icache(); | ||
364 | #if 0 | ||
365 | /* Restart DMA */ | ||
366 | LCD_REG_6 |= 1; | ||
367 | #endif | ||
368 | } | 520 | } |
521 | |||
522 | flush_icache(); | ||
523 | } | ||
524 | |||
525 | void lcd_update(void) | ||
526 | { | ||
527 | if (!display_on) | ||
528 | return; | ||
529 | |||
530 | /* TODO: It may be faster to swap the addresses of lcd_driver_framebuffer | ||
531 | * and lcd_framebuffer */ | ||
532 | /* Copy the Rockbox framebuffer to the second framebuffer */ | ||
533 | lcd_copy_buffer_rect(&lcd_driver_framebuffer[0][0], | ||
534 | &lcd_framebuffer[0][0], LCD_WIDTH*LCD_HEIGHT, 1); | ||
535 | |||
536 | flush_icache(); | ||
369 | } | 537 | } |
370 | 538 | ||
371 | 539 | ||
@@ -379,15 +547,61 @@ void lcd_set_contrast(int val) | |||
379 | 547 | ||
380 | void lcd_set_invert_display(bool yesno) | 548 | void lcd_set_invert_display(bool yesno) |
381 | { | 549 | { |
382 | /* TODO: Implement lcd_set_invert_display() */ | 550 | bool dma_on = LCD_REG_6 & 1; |
383 | (void)yesno; | 551 | |
552 | if (dma_on) | ||
553 | { | ||
554 | LCD_REG_6 &= ~1; /* Disable DMA */ | ||
555 | sleep(HZ/50); /* Wait for dma end (assuming 50Hz) */ | ||
556 | DEV_EN &= ~DEV_LCD; /* Disable LCD controller */ | ||
557 | } | ||
558 | |||
559 | r_disp_control_rev = yesno ? R_DISP_CONTROL_REV : | ||
560 | R_DISP_CONTROL_NORMAL; | ||
561 | |||
562 | if (display_on) | ||
563 | { | ||
564 | /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, CL=0, | ||
565 | DTE=1, REV=x, D1-0=11 */ | ||
566 | lcd_write_reg(R_DISP_CONTROL1, 0x0073 | r_disp_control_rev); | ||
567 | } | ||
568 | |||
569 | if (dma_on) | ||
570 | { | ||
571 | DEV_EN |= DEV_LCD; /* Enable LCD controller */ | ||
572 | lcd_send_msg(0x70, R_RAM_WRITE_DATA); /* Set to RAM write mode */ | ||
573 | LCD_REG_6 |= 1; /* Restart DMA */ | ||
574 | } | ||
384 | } | 575 | } |
385 | 576 | ||
386 | /* turn the display upside down (call lcd_update() afterwards) */ | 577 | /* turn the display upside down (call lcd_update() afterwards) */ |
387 | void lcd_set_flip(bool yesno) | 578 | void lcd_set_flip(bool yesno) |
388 | { | 579 | { |
389 | /* TODO: Implement lcd_set_flip() */ | 580 | bool dma_on = LCD_REG_6 & 1; |
390 | (void)yesno; | 581 | |
582 | if (dma_on) | ||
583 | { | ||
584 | LCD_REG_6 &= ~1; /* Disable DMA */ | ||
585 | sleep(HZ/50); /* Wait for dma end (assuming 50Hz) */ | ||
586 | DEV_EN &= ~DEV_LCD; /* Disable LCD controller */ | ||
587 | } | ||
588 | |||
589 | r_drv_output_control = yesno ? R_DRV_OUTPUT_CONTROL_FLIPPED : | ||
590 | R_DRV_OUTPUT_CONTROL_NORMAL; | ||
591 | |||
592 | if (power_on) | ||
593 | { | ||
594 | /* VSPL=0, HSPL=0, DPL=1, EPL=0, SM=0, GS=x, SS=x, | ||
595 | NL4-0=11011 (G1-G224) */ | ||
596 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, r_drv_output_control); | ||
597 | } | ||
598 | |||
599 | if (dma_on) | ||
600 | { | ||
601 | DEV_EN |= DEV_LCD; /* Enable LCD controller */ | ||
602 | lcd_send_msg(0x70, R_RAM_WRITE_DATA); /* Set to RAM write mode */ | ||
603 | LCD_REG_6 |= 1; /* Restart DMA */ | ||
604 | } | ||
391 | } | 605 | } |
392 | 606 | ||
393 | /* Blitting functions */ | 607 | /* Blitting functions */ |
@@ -417,35 +631,35 @@ void lcd_yuv_blit(unsigned char * const src[3], | |||
417 | int src_x, int src_y, int stride, | 631 | int src_x, int src_y, int stride, |
418 | int x, int y, int width, int height) | 632 | int x, int y, int width, int height) |
419 | { | 633 | { |
420 | if(DEV_EN & DEV_LCD) | 634 | /* Caches for chroma data so it only need be recaculated every other |
421 | { | 635 | line */ |
422 | /* Caches for chroma data so it only need be recaculated every other | 636 | static unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 330 bytes */ |
423 | line */ | 637 | unsigned char const * yuv_src[3]; |
424 | static unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 330 bytes */ | 638 | off_t z; |
425 | unsigned char const * yuv_src[3]; | ||
426 | off_t z; | ||
427 | 639 | ||
428 | /* Sorry, but width and height must be >= 2 or else */ | 640 | if (!display_on) |
429 | width &= ~1; | 641 | return; |
430 | height >>= 1; | ||
431 | 642 | ||
432 | fb_data *dst = (fb_data*)lcd_driver_framebuffer + | 643 | /* Sorry, but width and height must be >= 2 or else */ |
433 | x * LCD_WIDTH + (LCD_WIDTH - y) - 1; | 644 | width &= ~1; |
645 | height >>= 1; | ||
434 | 646 | ||
435 | z = stride*src_y; | 647 | fb_data *dst = (fb_data*)lcd_driver_framebuffer + |
436 | yuv_src[0] = src[0] + z + src_x; | 648 | x * LCD_WIDTH + (LCD_WIDTH - y) - 1; |
437 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
438 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
439 | 649 | ||
440 | do | 650 | z = stride*src_y; |
441 | { | 651 | yuv_src[0] = src[0] + z + src_x; |
442 | lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width, | 652 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); |
443 | stride); | 653 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); |
444 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | 654 | |
445 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | 655 | do |
446 | yuv_src[2] += stride >> 1; | 656 | { |
447 | dst -= 2; | 657 | lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width, |
448 | } | 658 | stride); |
449 | while (--height > 0); | 659 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ |
660 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
661 | yuv_src[2] += stride >> 1; | ||
662 | dst -= 2; | ||
450 | } | 663 | } |
664 | while (--height > 0); | ||
451 | } | 665 | } |