summaryrefslogtreecommitdiff
path: root/firmware/target/arm/iriver/h10/lcd-h10_20gb.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/iriver/h10/lcd-h10_20gb.c')
-rw-r--r--firmware/target/arm/iriver/h10/lcd-h10_20gb.c203
1 files changed, 58 insertions, 145 deletions
diff --git a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c
index 2c527fa4d9..892adffea9 100644
--- a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c
+++ b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c
@@ -34,6 +34,8 @@ static unsigned short disp_control_rev;
34/* Contrast setting << 8 */ 34/* Contrast setting << 8 */
35static int lcd_contrast; 35static int lcd_contrast;
36 36
37static unsigned lcd_yuv_options NOCACHEBSS_ATTR = 0;
38
37/* Forward declarations */ 39/* Forward declarations */
38static void lcd_display_off(void); 40static void lcd_display_off(void);
39 41
@@ -166,8 +168,6 @@ void lcd_set_flip(bool yesno)
166 lcd_write_reg(R_GATE_SCAN_START_POS, yesno ? 0x0002 : 0x0000); 168 lcd_write_reg(R_GATE_SCAN_START_POS, yesno ? 0x0002 : 0x0000);
167 /* SM=0, GS=x, SS=x, NL4-0=10011 (G1-G160) */ 169 /* SM=0, GS=x, SS=x, NL4-0=10011 (G1-G160) */
168 lcd_write_reg(R_DRV_OUTPUT_CONTROL, yesno ? 0x0213 : 0x0113); 170 lcd_write_reg(R_DRV_OUTPUT_CONTROL, yesno ? 0x0213 : 0x0113);
169 /* HEA7-0=0xxx, HSA7-0=0xxx */
170 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, y_offset ? 0x8304 : 0x7f00);
171} 171}
172 172
173/* LCD init */ 173/* LCD init */
@@ -239,8 +239,8 @@ static void lcd_power_on(void)
239 lcd_write_reg(R_1ST_SCR_DRV_POS, 0x9f00); 239 lcd_write_reg(R_1ST_SCR_DRV_POS, 0x9f00);
240 /* SE27-20(End)=0x5c (92), SS27-20(Start)=0x00 */ 240 /* SE27-20(End)=0x5c (92), SS27-20(Start)=0x00 */
241 lcd_write_reg(R_2ND_SCR_DRV_POS, 0x5c00); 241 lcd_write_reg(R_2ND_SCR_DRV_POS, 0x5c00);
242 /* HEA7-0=0xxx, HSA7-0=0xxx */ 242 /* HEA7-0=7f, HSA7-0=00 */
243 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, y_offset ? 0x8304 : 0x7f00); 243 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 0x7f00);
244 /* PKP12-10=0x0, PKP02-00=0x0 */ 244 /* PKP12-10=0x0, PKP02-00=0x0 */
245 lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0003); 245 lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0003);
246 /* PKP32-30=0x4, PKP22-20=0x0 */ 246 /* PKP32-30=0x4, PKP22-20=0x0 */
@@ -395,177 +395,91 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
395 (void)stride; 395 (void)stride;
396} 396}
397 397
398#define CSUB_X 2 398void lcd_yuv_set_options(unsigned options)
399#define CSUB_Y 2 399{
400 400 lcd_yuv_options = options;
401#define RYFAC (31*257) 401}
402#define GYFAC (31*257)
403#define BYFAC (31*257)
404#define RVFAC 11170 /* 31 * 257 * 1.402 */
405#define GVFAC (-5690) /* 31 * 257 * -0.714136 */
406#define GUFAC (-2742) /* 31 * 257 * -0.344136 */
407#define BUFAC 14118 /* 31 * 257 * 1.772 */
408 402
409#define ROUNDOFFS (127*257) 403/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
410#define ROUNDOFFSG (63*257) 404extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
405 int width,
406 int stride);
407extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
408 int width,
409 int stride,
410 int x_screen, /* To align dither pattern */
411 int y_screen);
411 412
412/* Performance function to blit a YUV bitmap directly to the LCD */ 413/* Performance function to blit a YUV bitmap directly to the LCD */
413void lcd_yuv_blit(unsigned char * const src[3], 414void lcd_yuv_blit(unsigned char * const src[3],
414 int src_x, int src_y, int stride, 415 int src_x, int src_y, int stride,
415 int x, int y, int width, int height) 416 int x, int y, int width, int height)
416{ 417{
417 int y0, x0, y1, x1; 418 const unsigned char *yuv_src[3];
418 int ymax; 419 const unsigned char *ysrc_max;
420 int y0;
421 int options;
419 422
420 if (!display_on) 423 if (!display_on)
421 return; 424 return;
422 425
423 width = (width + 1) & ~1; 426 width &= ~1;
427 height &= ~1;
424 428
425 /* calculate the drawing region */ 429 /* calculate the drawing region */
426 x0 = x;
427 x1 = x + width - 1;
428 y0 = y;
429 y1 = y + height - 1;
430 430
431 /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin 431 /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin
432 * is actually the bottom left and horizontal and vertical are swapped. 432 * is actually the bottom left and horizontal and vertical are swapped.
433 * Rockbox expects the origin to be the top left so we need to use 433 * Rockbox expects the origin to be the top left so we need to use
434 * 127 - y instead of just y */ 434 * 127 - y instead of just y */
435
436 /* max horiz << 8 | start horiz */
437 lcd_send_cmd(R_HORIZ_RAM_ADDR_POS);
438 lcd_send_data( (((LCD_HEIGHT-1)-y0+y_offset) << 8) | ((LCD_HEIGHT-1)-y1+y_offset) );
439 435
440 /* max vert << 8 | start vert */ 436 /* max vert << 8 | start vert */
441 lcd_send_cmd(R_VERT_RAM_ADDR_POS); 437 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x);
442 lcd_send_data((x1 << 8) | x0);
443
444 /* position cursor (set AD0-AD15) */
445 /* start vert << 8 | start horiz */
446 lcd_send_cmd(R_RAM_ADDR_SET);
447 lcd_send_data( (x0 << 8) | ((LCD_HEIGHT-1)-y0+y_offset) );
448
449 /* start drawing */
450 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
451 438
452 ymax = y + height - 1 ; 439 y0 = LCD_HEIGHT - 1 - y + y_offset;
453 440
454 const int stride_div_csub_x = stride/CSUB_X; 441 /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=0, LG2-0=000 */
442 lcd_write_reg(R_ENTRY_MODE, 0x1020);
455 443
456 for (; y <= ymax ; y++) 444 yuv_src[0] = src[0] + src_y * stride + src_x;
457 { 445 yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1);
458 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ 446 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
459 const unsigned char *ysrc = src[0] + stride * src_y + src_x; 447 ysrc_max = yuv_src[0] + height * stride;
460 448
461 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) + 449 options = lcd_yuv_options;
462 (src_x/CSUB_X);
463 450
464 const unsigned char *usrc = src[1] + uvoffset; 451 do
465 const unsigned char *vsrc = src[2] + uvoffset; 452 {
466 const unsigned char *row_end = ysrc + width; 453 /* max horiz << 8 | start horiz */
454 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1));
467 455
468 int y, u, v; 456 /* position cursor (set AD0-AD15) */
469 int red1, green1, blue1; 457 /* start vert << 8 | start horiz */
470 int red2, green2, blue2; 458 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | y0);
471 unsigned rbits, gbits, bbits;
472 459
473 int rc, gc, bc; 460 /* start drawing */
461 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
474 462
475 do 463 if (options & LCD_YUV_DITHER)
464 {
465 lcd_write_yuv420_lines_odither(yuv_src, width, stride,
466 x, y);
467 y -= 2;
468 }
469 else
476 { 470 {
477 u = *usrc++ - 128; 471 lcd_write_yuv420_lines(yuv_src, width, stride);
478 v = *vsrc++ - 128;
479 rc = RVFAC * v + ROUNDOFFS;
480 gc = GVFAC * v + GUFAC * u + ROUNDOFFSG;
481 bc = BUFAC * u + ROUNDOFFS;
482
483 /* Pixel 1 */
484 y = *ysrc++;
485
486 red1 = RYFAC * y + rc;
487 green1 = GYFAC * y + gc;
488 blue1 = BYFAC * y + bc;
489
490 /* Pixel 2 */
491 y = *ysrc++;
492 red2 = RYFAC * y + rc;
493 green2 = GYFAC * y + gc;
494 blue2 = BYFAC * y + bc;
495
496 /* Since out of bounds errors are relatively rare, we check two
497 pixels at once to see if any components are out of bounds, and
498 then fix whichever is broken. This works due to high values and
499 negative values both becoming larger than the cutoff when
500 casted to unsigned. And ORing them together checks all of them
501 simultaneously. */
502 if (((unsigned)(red1 | green1 | blue1 |
503 red2 | green2 | blue2)) > (RYFAC*255+ROUNDOFFS)) {
504 if (((unsigned)(red1 | green1 | blue1)) >
505 (RYFAC*255+ROUNDOFFS)) {
506 if ((unsigned)red1 > (RYFAC*255+ROUNDOFFS))
507 {
508 if (red1 < 0)
509 red1 = 0;
510 else
511 red1 = (RYFAC*255+ROUNDOFFS);
512 }
513 if ((unsigned)green1 > (GYFAC*255+ROUNDOFFSG))
514 {
515 if (green1 < 0)
516 green1 = 0;
517 else
518 green1 = (GYFAC*255+ROUNDOFFSG);
519 }
520 if ((unsigned)blue1 > (BYFAC*255+ROUNDOFFS))
521 {
522 if (blue1 < 0)
523 blue1 = 0;
524 else
525 blue1 = (BYFAC*255+ROUNDOFFS);
526 }
527 }
528
529 if (((unsigned)(red2 | green2 | blue2)) >
530 (RYFAC*255+ROUNDOFFS)) {
531 if ((unsigned)red2 > (RYFAC*255+ROUNDOFFS))
532 {
533 if (red2 < 0)
534 red2 = 0;
535 else
536 red2 = (RYFAC*255+ROUNDOFFS);
537 }
538 if ((unsigned)green2 > (GYFAC*255+ROUNDOFFSG))
539 {
540 if (green2 < 0)
541 green2 = 0;
542 else
543 green2 = (GYFAC*255+ROUNDOFFSG);
544 }
545 if ((unsigned)blue2 > (BYFAC*255+ROUNDOFFS))
546 {
547 if (blue2 < 0)
548 blue2 = 0;
549 else
550 blue2 = (BYFAC*255+ROUNDOFFS);
551 }
552 }
553 }
554
555 rbits = red1 >> 16 ;
556 gbits = green1 >> 15 ;
557 bbits = blue1 >> 16 ;
558 lcd_send_data((rbits << 11) | (gbits << 5) | bbits);
559
560 rbits = red2 >> 16 ;
561 gbits = green2 >> 15 ;
562 bbits = blue2 >> 16 ;
563 lcd_send_data((rbits << 11) | (gbits << 5) | bbits);
564 } 472 }
565 while (ysrc < row_end);
566 473
567 src_y++; 474 y0 -= 2;
475 yuv_src[0] += stride << 1;
476 yuv_src[1] += stride >> 1;
477 yuv_src[2] += stride >> 1;
568 } 478 }
479 while (yuv_src[0] < ysrc_max);
480
481 /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=1, LG2-0=000 */
482 lcd_write_reg(R_ENTRY_MODE, 0x1028);
569} 483}
570 484
571 485
@@ -573,8 +487,7 @@ void lcd_yuv_blit(unsigned char * const src[3],
573void lcd_update_rect(int x0, int y0, int width, int height) 487void lcd_update_rect(int x0, int y0, int width, int height)
574{ 488{
575 int x1, y1; 489 int x1, y1;
576 490 unsigned short *addr;
577 unsigned short *addr = (unsigned short *)lcd_framebuffer;
578 491
579 if (!display_on) 492 if (!display_on)
580 return; 493 return;