diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/lcd-ipod.c | 231 |
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 */ | ||
417 | void 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. */ |
404 | void lcd_update_rect(int x, int y, int width, int height) | 635 | void lcd_update_rect(int x, int y, int width, int height) |
405 | { | 636 | { |