summaryrefslogtreecommitdiff
path: root/firmware/target/arm/philips/sa9200/lcd-sa9200.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/philips/sa9200/lcd-sa9200.c')
-rw-r--r--firmware/target/arm/philips/sa9200/lcd-sa9200.c111
1 files changed, 96 insertions, 15 deletions
diff --git a/firmware/target/arm/philips/sa9200/lcd-sa9200.c b/firmware/target/arm/philips/sa9200/lcd-sa9200.c
index 51a3cf0f71..47fbfa3843 100644
--- a/firmware/target/arm/philips/sa9200/lcd-sa9200.c
+++ b/firmware/target/arm/philips/sa9200/lcd-sa9200.c
@@ -97,9 +97,9 @@ static void lcd_send_data(unsigned data)
97static void lcd_send_command(unsigned cmd) 97static void lcd_send_command(unsigned cmd)
98{ 98{
99 lcd_wait_write(); 99 lcd_wait_write();
100 LCD1_CMD = cmd >> 8; 100 LCD1_CMD = 0;
101 lcd_wait_write(); 101 lcd_wait_write();
102 LCD1_CMD = cmd & 0xff; 102 LCD1_CMD = cmd;
103} 103}
104 104
105static void lcd_write_reg(unsigned reg, unsigned data) 105static void lcd_write_reg(unsigned reg, unsigned data)
@@ -401,25 +401,101 @@ void lcd_yuv_set_options(unsigned options)
401} 401}
402 402
403/* Performance function to blit a YUV bitmap directly to the LCD */ 403/* Performance function to blit a YUV bitmap directly to the LCD */
404void lcd_write_yuv420_lines(unsigned char const * const src[3],
405 int width,
406 int stride);
407void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
408 int width,
409 int stride,
410 int x_screen,
411 int y_screen);
404void lcd_blit_yuv(unsigned char * const src[3], 412void lcd_blit_yuv(unsigned char * const src[3],
405 int src_x, int src_y, int stride, 413 int src_x, int src_y, int stride,
406 int x, int y, int width, int height) 414 int x, int y, int width, int height)
407{ 415{
408 (void)src; 416 const unsigned char *yuv_src[3];
409 (void)src_x; 417 const unsigned char *ysrc_max;
410 (void)src_y; 418 int options;
411 (void)stride; 419
412 (void)x; 420 if (!display_on)
413 (void)y; 421 return;
414 (void)width; 422
415 (void)height; 423 width &= ~1;
424 height &= ~1;
425
426 /* calculate the drawing region */
427 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x);
428
429 /* convert YUV coordinates to screen coordinates */
430 y = LCD_WIDTH - 1 - y;
431
432 /* 2px strip: cursor moves left, then down in gram */
433 /* BGR=1, MDT1-0=00, I/D1-0=10, AM=0 */
434 lcd_write_reg(R_ENTRY_MODE, 0x1020);
435
436 yuv_src[0] = src[0] + src_y * stride + src_x;
437 yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1);
438 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
439 ysrc_max = yuv_src[0] + height * stride;
440
441 /* cache options setting */
442 options = lcd_yuv_options;
443
444 do
445 {
446 /* max horiz << 8 | start horiz */
447 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y << 8) | (y - 1));
448
449 /* position cursor (set AD0-AD15) */
450 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | y);
451
452 /* start drawing */
453 lcd_send_command(R_WRITE_DATA_2_GRAM);
454
455 if (options & LCD_YUV_DITHER)
456 {
457 lcd_write_yuv420_lines_odither(yuv_src, width, stride,
458 y, x);
459 }
460 else
461 {
462 lcd_write_yuv420_lines(yuv_src, width, stride);
463 }
464
465 y -= 2; /* move strip by "down" 2 px */
466 yuv_src[0] += stride << 1;
467 yuv_src[1] += stride >> 1;
468 yuv_src[2] += stride >> 1;
469 }
470 while (yuv_src[0] < ysrc_max);
471
472 /* back to normal right, then down cursor in gram */
473 /* BGR=1, MDT1-0=00, I/D1-0=11, AM=0 */
474 lcd_write_reg(R_ENTRY_MODE, 0x1030);
416} 475}
417 476
418/* Update the display. 477/* Update the display.
419 This must be called after all other LCD functions that change the display. */ 478 This must be called after all other LCD functions that change the display. */
420void lcd_update(void) 479void lcd_update(void)
421{ 480{
422 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); 481 const fb_data *addr, *end;
482
483 if (!display_on)
484 return;
485
486 addr = &lcd_framebuffer[0][0];
487 end = &lcd_framebuffer[LCD_HEIGHT - 1][LCD_WIDTH];
488
489 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (LCD_WIDTH - 1) << 8);
490 lcd_write_reg(R_VERT_RAM_ADDR_POS, (LCD_HEIGHT - 1) << 8);
491 lcd_write_reg(R_RAM_ADDR_SET, 0);
492 lcd_send_command(R_WRITE_DATA_2_GRAM);
493
494 do
495 {
496 lcd_send_data(*addr++);
497 }
498 while (addr < end);
423} 499}
424 500
425/* Update a fraction of the display. */ 501/* Update a fraction of the display. */
@@ -432,18 +508,23 @@ void lcd_update_rect(int x, int y, int width, int height)
432 508
433 if (x + width > LCD_WIDTH) 509 if (x + width > LCD_WIDTH)
434 width = LCD_WIDTH - x; 510 width = LCD_WIDTH - x;
511 if (x < 0)
512 width += x, x = 0;
513 if (width <= 0)
514 return; /* Nothing left to do. */
435 515
436 if (y + height > LCD_HEIGHT) 516 if (y + height > LCD_HEIGHT)
437 height = LCD_HEIGHT - y; 517 height = LCD_HEIGHT - y;
438 518 if (y < 0)
439 if ((width <= 0) || (height <= 0)) 519 height += y, y = 0;
520 if (height <= 0)
440 return; /* Nothing left to do. */ 521 return; /* Nothing left to do. */
441 522
442 addr = &lcd_framebuffer[y][x]; 523 addr = &lcd_framebuffer[y][x];
443 524
444 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, ((x + width - 1) << 8) | x); 525 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, ((x + width - 1) << 8) | x);
445 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((y + height -1) << 8) | y); 526 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((y + height - 1) << 8) | y);
446 lcd_write_reg(R_RAM_ADDR_SET, ((y & 0xff) << 8) | (x & 0xff)); 527 lcd_write_reg(R_RAM_ADDR_SET, (y << 8) | x);
447 lcd_send_command(R_WRITE_DATA_2_GRAM); 528 lcd_send_command(R_WRITE_DATA_2_GRAM);
448 529
449 do { 530 do {