summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-ipod.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-ipod.c')
-rw-r--r--firmware/drivers/lcd-ipod.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/firmware/drivers/lcd-ipod.c b/firmware/drivers/lcd-ipod.c
index 52fde25bf0..875bf8ffa0 100644
--- a/firmware/drivers/lcd-ipod.c
+++ b/firmware/drivers/lcd-ipod.c
@@ -400,6 +400,237 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
400 (void)stride; 400 (void)stride;
401} 401}
402 402
403#define CSUB_X 2
404#define CSUB_Y 2
405
406#define RYFAC (31*257)
407#define GYFAC (63*257)
408#define BYFAC (31*257)
409#define RVFAC 11170 /* 31 * 257 * 1.402 */
410#define GVFAC (-11563) /* 63 * 257 * -0.714136 */
411#define GUFAC (-5572) /* 63 * 257 * -0.344136 */
412#define BUFAC 14118 /* 31 * 257 * 1.772 */
413
414#define ROUNDOFFS (127*257)
415
416/* Performance function to blit a YUV bitmap directly to the LCD */
417void lcd_yuv_blit(unsigned char * const src[3],
418 int src_x, int src_y, int stride,
419 int x, int y, int width, int height)
420{
421 int y0, x0, y1, x1;
422 int h;
423
424 /* nothing to draw? */
425 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
426 || (x + width <= 0) || (y + height <= 0))
427 return;
428
429 /* clipping */
430 if (x < 0)
431 {
432 width += x;
433 src_x -= x;
434 x = 0;
435 }
436 if (y < 0)
437 {
438 height += y;
439 src_y -= y;
440 y = 0;
441 }
442 if (x + width > LCD_WIDTH)
443 width = LCD_WIDTH - x;
444 if (y + height > LCD_HEIGHT)
445 height = LCD_HEIGHT - y;
446
447 /* calculate the drawing region */
448#if CONFIG_LCD == LCD_IPODNANO
449 y0 = x; /* start horiz */
450 x0 = y; /* start vert */
451 y1 = (x + width) - 1; /* max horiz */
452 x1 = (y + height) - 1; /* max vert */
453#elif CONFIG_LCD == LCD_IPODCOLOR
454 y0 = y; /* start vert */
455 x0 = (LCD_WIDTH - 1) - x; /* start horiz */
456 y1 = (y + height) - 1; /* end vert */
457 x1 = (x0 - width) + 1; /* end horiz */
458#endif
459
460 /* setup the drawing region */
461 if (lcd_type == 0) {
462 lcd_cmd_data(0x12, y0); /* start vert */
463 lcd_cmd_data(0x13, x0); /* start horiz */
464 lcd_cmd_data(0x15, y1); /* end vert */
465 lcd_cmd_data(0x16, x1); /* end horiz */
466 } else {
467 /* swap max horiz < start horiz */
468 if (y1 < y0) {
469 int t;
470 t = y0;
471 y0 = y1;
472 y1 = t;
473 }
474
475 /* swap max vert < start vert */
476 if (x1 < x0) {
477 int t;
478 t = x0;
479 x0 = x1;
480 x1 = t;
481 }
482
483 /* max horiz << 8 | start horiz */
484 lcd_cmd_data(LCD_CNTL_HORIZ_RAM_ADDR_POS, (y1 << 8) | y0);
485 /* max vert << 8 | start vert */
486 lcd_cmd_data(LCD_CNTL_VERT_RAM_ADDR_POS, (x1 << 8) | x0);
487
488 /* start vert = max vert */
489#if CONFIG_LCD == LCD_IPODCOLOR
490 x0 = x1;
491#endif
492
493 /* position cursor (set AD0-AD15) */
494 /* start vert << 8 | start horiz */
495 lcd_cmd_data(LCD_CNTL_RAM_ADDR_SET, ((x0 << 8) | y0));
496
497 /* start drawing */
498 lcd_send_lo(0x0);
499 lcd_send_lo(LCD_CNTL_WRITE_TO_GRAM);
500 }
501
502 h=0;
503 while (1) {
504 int pixels_to_write;
505 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
506 const unsigned char *row_end = ysrc + width;
507 int y, u, v;
508 int red, green, blue;
509 unsigned rbits, gbits, bbits;
510 fb_data pixel1,pixel2;
511
512 if (h==0) {
513 while ((inl(0x70008a20) & 0x4000000) == 0);
514 outl(0x0, 0x70008a24);
515
516 if (height == 0) break;
517
518 pixels_to_write = (width * height) * 2;
519 h = height;
520
521 /* calculate how much we can do in one go */
522 if (pixels_to_write > 64000) {
523 h = (64000/2) / width;
524 pixels_to_write = (width * h) * 2;
525 }
526
527 height -= h;
528 outl(0x10000080, 0x70008a20);
529 outl((pixels_to_write - 1) | 0xc0010000, 0x70008a24);
530 outl(0x34000000, 0x70008a20);
531 }
532
533 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
534 const unsigned char *usrc = src[1] + (stride/CSUB_X) * (src_y/CSUB_Y)
535 + (src_x/CSUB_X);
536 const unsigned char *vsrc = src[2] + (stride/CSUB_X) * (src_y/CSUB_Y)
537 + (src_x/CSUB_X);
538 int rc, gc, bc;
539
540 u = *usrc++ - 128;
541 v = *vsrc++ - 128;
542 rc = RVFAC * v + ROUNDOFFS;
543 gc = GVFAC * v + GUFAC * u + ROUNDOFFS;
544 bc = BUFAC * u + ROUNDOFFS;
545
546 do
547 {
548 y = *ysrc++;
549 red = RYFAC * y + rc;
550 green = GYFAC * y + gc;
551 blue = BYFAC * y + bc;
552
553 if ((unsigned)red > (RYFAC*255+ROUNDOFFS))
554 {
555 if (red < 0)
556 red = 0;
557 else
558 red = (RYFAC*255+ROUNDOFFS);
559 }
560 if ((unsigned)green > (GYFAC*255+ROUNDOFFS))
561 {
562 if (green < 0)
563 green = 0;
564 else
565 green = (GYFAC*255+ROUNDOFFS);
566 }
567 if ((unsigned)blue > (BYFAC*255+ROUNDOFFS))
568 {
569 if (blue < 0)
570 blue = 0;
571 else
572 blue = (BYFAC*255+ROUNDOFFS);
573 }
574 rbits = ((unsigned)red) >> 16 ;
575 gbits = ((unsigned)green) >> 16 ;
576 bbits = ((unsigned)blue) >> 16 ;
577
578 pixel1 = swap16((rbits << 11) | (gbits << 5) | bbits);
579
580 y = *ysrc++;
581 red = RYFAC * y + rc;
582 green = GYFAC * y + gc;
583 blue = BYFAC * y + bc;
584
585 if ((unsigned)red > (RYFAC*255+ROUNDOFFS))
586 {
587 if (red < 0)
588 red = 0;
589 else
590 red = (RYFAC*255+ROUNDOFFS);
591 }
592 if ((unsigned)green > (GYFAC*255+ROUNDOFFS))
593 {
594 if (green < 0)
595 green = 0;
596 else
597 green = (GYFAC*255+ROUNDOFFS);
598 }
599 if ((unsigned)blue > (BYFAC*255+ROUNDOFFS))
600 {
601 if (blue < 0)
602 blue = 0;
603 else
604 blue = (BYFAC*255+ROUNDOFFS);
605 }
606 rbits = ((unsigned)red) >> 16 ;
607 gbits = ((unsigned)green) >> 16 ;
608 bbits = ((unsigned)blue) >> 16 ;
609
610 pixel2 = swap16((rbits << 11) | (gbits << 5) | bbits);
611
612 u = *usrc++ - 128;
613 v = *vsrc++ - 128;
614 rc = RVFAC * v + ROUNDOFFS;
615 gc = GVFAC * v + GUFAC * u + ROUNDOFFS;
616 bc = BUFAC * u + ROUNDOFFS;
617
618 while ((inl(0x70008a20) & 0x1000000) == 0);
619
620 /* output 2 pixels */
621 outl((pixel2<<16)|pixel1, 0x70008b00);
622 }
623 while (ysrc < row_end);
624
625 src_y++;
626 h--;
627 }
628
629 while ((inl(0x70008a20) & 0x4000000) == 0);
630 outl(0x0, 0x70008a24);
631}
632
633
403/* Update a fraction of the display. */ 634/* Update a fraction of the display. */
404void lcd_update_rect(int x, int y, int width, int height) 635void lcd_update_rect(int x, int y, int width, int height)
405{ 636{