summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/sansa-fuzeplus
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2012-01-27 19:51:18 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2012-01-27 20:08:33 +0100
commitd32891fa5940bb4eda47e513c2c7d0be27f38ecb (patch)
tree06085abeed64e9f7ae9f9df90c5143ef69195272 /firmware/target/arm/imx233/sansa-fuzeplus
parent05ba5c19712250b27cc78e8316b93690fd948a03 (diff)
downloadrockbox-d32891fa5940bb4eda47e513c2c7d0be27f38ecb.tar.gz
rockbox-d32891fa5940bb4eda47e513c2c7d0be27f38ecb.zip
fuze+: change rendering scheme, do not rely on generic framebuffer and implement rect updating and yuv blitting correctly.
Now lcd_framebuffer is the only framebuffer in the system. We still use a ARM-buffered buffer which serve as an intermediate buffer for copying, to accomodate the requirement of the controller. We implement lcd_update_rect() properly using this new scheme (this requires two little quirks), this allows to implement lcd_blit_yuv with the right semantic (bypasses the framebuffer). YUV to RGB conversion is still done in software but the DCP CSC should be able to do that but the hardware rotation scheme is not the same as our software so it will require some tricks. Change-Id: I0752e9c2f1a705d2e6a6010084e1f150965d8370
Diffstat (limited to 'firmware/target/arm/imx233/sansa-fuzeplus')
-rw-r--r--firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c283
-rw-r--r--firmware/target/arm/imx233/sansa-fuzeplus/lcd-target.h6
2 files changed, 259 insertions, 30 deletions
diff --git a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c
index 8edc4b7758..c84c29c22d 100644
--- a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c
+++ b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c
@@ -27,15 +27,14 @@
27#include "lcdif-imx233.h" 27#include "lcdif-imx233.h"
28#include "clkctrl-imx233.h" 28#include "clkctrl-imx233.h"
29#include "pinctrl-imx233.h" 29#include "pinctrl-imx233.h"
30#include "dcp-imx233.h"
30#include "logf.h" 31#include "logf.h"
31 32
32extern bool lcd_on; /* lcd-memframe.c */ 33#ifdef HAVE_LCD_ENABLE
33 34bool lcd_on; /* framebuffer-imx233.c */
34/* Copies a rectangle from one framebuffer to another. Can be used in 35#endif
35 single transfer mode with width = num pixels, and height = 1 which 36static unsigned lcd_yuv_options = 0;
36 allows a full-width rectangle to be copied more efficiently. */ 37static int lcd_dcp_channel = -1;
37extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src,
38 int width, int height);
39 38
40static enum lcd_kind_t 39static enum lcd_kind_t
41{ 40{
@@ -357,6 +356,9 @@ static void lcd_init_seq_9325(void)
357 356
358void lcd_init_device(void) 357void lcd_init_device(void)
359{ 358{
359 lcd_dcp_channel = imx233_dcp_acquire_channel(TIMEOUT_NOBLOCK);
360 if(lcd_dcp_channel < 0)
361 panicf("imx233_framebuffer_init: imx233_dcp_acquire_channel failed!");
360 setup_lcdif(); 362 setup_lcdif();
361 setup_lcdif_clock(); 363 setup_lcdif_clock();
362 364
@@ -387,6 +389,11 @@ void lcd_init_device(void)
387} 389}
388 390
389#ifdef HAVE_LCD_ENABLE 391#ifdef HAVE_LCD_ENABLE
392bool lcd_active(void)
393{
394 return lcd_on;
395}
396
390static void lcd_enable_7783(bool enable) 397static void lcd_enable_7783(bool enable)
391{ 398{
392 if(!enable) 399 if(!enable)
@@ -485,32 +492,260 @@ void lcd_enable(bool enable)
485 492
486void lcd_update(void) 493void lcd_update(void)
487{ 494{
488#ifdef HAVE_LCD_ENABLE 495 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
496}
497
498void lcd_update_rect(int x, int y, int w, int h)
499{
500 #ifdef HAVE_LCD_ENABLE
489 if(!lcd_on) 501 if(!lcd_on)
490 return; 502 return;
491#endif 503 #endif
492 imx233_lcdif_wait_ready(); 504 imx233_lcdif_wait_ready();
493 lcd_write_reg(0x50, 0); 505 lcd_write_reg(0x50, x);
494 lcd_write_reg(0x51, LCD_WIDTH - 1); 506 lcd_write_reg(0x51, x + w - 1);
495 lcd_write_reg(0x52, 0); 507 lcd_write_reg(0x52, y);
496 lcd_write_reg(0x53, LCD_HEIGHT - 1); 508 lcd_write_reg(0x53, y + h - 1);
497 lcd_write_reg(0x20, 0); 509 lcd_write_reg(0x20, x);
498 lcd_write_reg(0x21, 0); 510 lcd_write_reg(0x21, y);
499 lcd_write_reg(0x22, 0); 511 lcd_write_reg(0x22, 0);
500 imx233_lcdif_wait_ready(); 512 imx233_lcdif_wait_ready();
501 imx233_lcdif_set_word_length(HW_LCDIF_CTRL__WORD_LENGTH_16_BIT); 513 imx233_lcdif_set_word_length(HW_LCDIF_CTRL__WORD_LENGTH_16_BIT);
502 imx233_lcdif_set_byte_packing_format(0xf); /* two pixels per 32-bit word */ 514 imx233_lcdif_set_byte_packing_format(0xf); /* two pixels per 32-bit word */
503 imx233_lcdif_set_data_format(false, false, false); /* RGB565, don't care, don't care */ 515 imx233_lcdif_set_data_format(false, false, false); /* RGB565, don't care, don't care */
504 lcd_copy_buffer_rect((fb_data *)FRAME, &lcd_framebuffer[0][0], 516 /* there are two cases here:
505 LCD_WIDTH * LCD_HEIGHT, 1); 517 * - either width = LCD_WIDTH and we can directly memcopy a part of lcd_framebuffer to FRAME
506 imx233_lcdif_dma_send((void *)FRAME_PHYS_ADDR, LCD_WIDTH, LCD_HEIGHT); 518 * and send it
519 * - either width != LCD_WIDTH and we have to build a contiguous copy of the rectangular area
520 * into FRAME before sending it (which is slower and doesn't use the hardware)
521 * In all cases, FRAME just acts as a temporary buffer.
522 * NOTE It's more interesting to do a copy to FRAME in all cases since in system mode
523 * the clock runs at 24MHz which provides barely 10MB/s bandwidth compared to >100MB/s
524 * for memcopy operations
525 */
526 if(w == LCD_WIDTH)
527 {
528 imx233_dcp_memcpy_ex(lcd_dcp_channel, false, &lcd_framebuffer[y][x],
529 (void *)FRAME, h * w * sizeof(fb_data));
530 }
531 else
532 {
533 for(int i = 0; i < h; i++)
534 memcpy((fb_data *)FRAME + i * w, &lcd_framebuffer[y + i][x], w * sizeof(fb_data));
535 }
536 /* WARNING The LCDIF has a limitation on the vertical count ! In 16-bit packed mode
537 * (which we used, ie 16-bit per pixel, 2 pixels per 32-bit words), the v_count
538 * field must be a multiple of 2. Furthermore, it seems the lcd controller doesn't
539 * really like when both w and h are even, probably because the writes to the GRAM
540 * are done on several words and the controller requires dummy writes.
541 * The workaround is to always make sure that we send a number of pixels which is
542 * a multiple of 4 so that both the lcdif and the controller are happy. If any
543 * of w or h is odd, we will send a copy of the first pixels as dummy writes. We will
544 * send at most 3 bytes. We then send (w * h + 3) / 4 x 4 bytes.
545 */
546 if(w % 2 == 1 || h % 2 == 1)
547 {
548 /* copy three pixel after the last one */
549 for(int i = 0; i < 3; i++)
550 *((fb_data *)FRAME + w * h + i) = *((fb_data *)FRAME + i);
551 /* WARNING we need to update w and h to reflect the pixel count BUT it
552 * has no relation to w * h (it can even be 2 * prime). Hopefully, w <= 240 and
553 * h <= 320 so w * h <= 76800 and (w * h + 3) / 4 <= 38400 which fits into
554 * a 16-bit integer (horizontal count). */
555 h = (w * h + 3) / 4;
556 w = 4;
557 }
558 imx233_lcdif_dma_send((void *)FRAME_PHYS_ADDR, w, h);
507} 559}
508 560
509void lcd_update_rect(int x, int y, int width, int height) 561void lcd_yuv_set_options(unsigned options)
562{
563 lcd_yuv_options = options;
564}
565
566#define YFAC (74)
567#define RVFAC (101)
568#define GUFAC (-24)
569#define GVFAC (-51)
570#define BUFAC (128)
571
572static inline int clamp(int val, int min, int max)
510{ 573{
511 (void) x; 574 if (val < min)
512 (void) y; 575 val = min;
513 (void) width; 576 else if (val > max)
514 (void) height; 577 val = max;
515 lcd_update(); 578 return val;
579}
580
581void lcd_blit_yuv(unsigned char * const src[3],
582 int src_x, int src_y, int stride,
583 int x, int y, int width, int height)
584{
585 const unsigned char *ysrc, *usrc, *vsrc;
586 int linecounter;
587 fb_data *dst, *row_end;
588 long z;
589
590 /* width and height must be >= 2 and an even number */
591 width &= ~1;
592 linecounter = height >> 1;
593
594 #if LCD_WIDTH >= LCD_HEIGHT
595 dst = &lcd_framebuffer[y][x];
596 row_end = dst + width;
597 #else
598 dst = &lcd_framebuffer[x][LCD_WIDTH - y - 1];
599 row_end = dst + LCD_WIDTH * width;
600 #endif
601
602 z = stride * src_y;
603 ysrc = src[0] + z + src_x;
604 usrc = src[1] + (z >> 2) + (src_x >> 1);
605 vsrc = src[2] + (usrc - src[1]);
606
607 /* stride => amount to jump from end of last row to start of next */
608 stride -= width;
609
610 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
611
612 do
613 {
614 do
615 {
616 int y, cb, cr, rv, guv, bu, r, g, b;
617
618 y = YFAC*(*ysrc++ - 16);
619 cb = *usrc++ - 128;
620 cr = *vsrc++ - 128;
621
622 rv = RVFAC*cr;
623 guv = GUFAC*cb + GVFAC*cr;
624 bu = BUFAC*cb;
625
626 r = y + rv;
627 g = y + guv;
628 b = y + bu;
629
630 if ((unsigned)(r | g | b) > 64*256-1)
631 {
632 r = clamp(r, 0, 64*256-1);
633 g = clamp(g, 0, 64*256-1);
634 b = clamp(b, 0, 64*256-1);
635 }
636
637 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
638
639 #if LCD_WIDTH >= LCD_HEIGHT
640 dst++;
641 #else
642 dst += LCD_WIDTH;
643 #endif
644
645 y = YFAC*(*ysrc++ - 16);
646 r = y + rv;
647 g = y + guv;
648 b = y + bu;
649
650 if ((unsigned)(r | g | b) > 64*256-1)
651 {
652 r = clamp(r, 0, 64*256-1);
653 g = clamp(g, 0, 64*256-1);
654 b = clamp(b, 0, 64*256-1);
655 }
656
657 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
658
659 #if LCD_WIDTH >= LCD_HEIGHT
660 dst++;
661 #else
662 dst += LCD_WIDTH;
663 #endif
664 }
665 while (dst < row_end);
666
667 ysrc += stride;
668 usrc -= width >> 1;
669 vsrc -= width >> 1;
670
671 #if LCD_WIDTH >= LCD_HEIGHT
672 row_end += LCD_WIDTH;
673 dst += LCD_WIDTH - width;
674 #else
675 row_end -= 1;
676 dst -= LCD_WIDTH*width + 1;
677 #endif
678
679 do
680 {
681 int y, cb, cr, rv, guv, bu, r, g, b;
682
683 y = YFAC*(*ysrc++ - 16);
684 cb = *usrc++ - 128;
685 cr = *vsrc++ - 128;
686
687 rv = RVFAC*cr;
688 guv = GUFAC*cb + GVFAC*cr;
689 bu = BUFAC*cb;
690
691 r = y + rv;
692 g = y + guv;
693 b = y + bu;
694
695 if ((unsigned)(r | g | b) > 64*256-1)
696 {
697 r = clamp(r, 0, 64*256-1);
698 g = clamp(g, 0, 64*256-1);
699 b = clamp(b, 0, 64*256-1);
700 }
701
702 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
703
704 #if LCD_WIDTH >= LCD_HEIGHT
705 dst++;
706 #else
707 dst += LCD_WIDTH;
708 #endif
709
710 y = YFAC*(*ysrc++ - 16);
711 r = y + rv;
712 g = y + guv;
713 b = y + bu;
714
715 if ((unsigned)(r | g | b) > 64*256-1)
716 {
717 r = clamp(r, 0, 64*256-1);
718 g = clamp(g, 0, 64*256-1);
719 b = clamp(b, 0, 64*256-1);
720 }
721
722 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
723
724 #if LCD_WIDTH >= LCD_HEIGHT
725 dst++;
726 #else
727 dst += LCD_WIDTH;
728 #endif
729 }
730 while (dst < row_end);
731
732 ysrc += stride;
733 usrc += stride >> 1;
734 vsrc += stride >> 1;
735
736 #if LCD_WIDTH >= LCD_HEIGHT
737 row_end += LCD_WIDTH;
738 dst += LCD_WIDTH - width;
739 #else
740 row_end -= 1;
741 dst -= LCD_WIDTH*width + 1;
742 #endif
743 }
744 while (--linecounter > 0);
745
746 #if LCD_WIDTH >= LCD_HEIGHT
747 lcd_update_rect(x, y, width, height);
748 #else
749 lcd_update_rect(LCD_WIDTH - y - height, x, height, width);
750 #endif
516} 751}
diff --git a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-target.h b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-target.h
index 89959244a4..5c1ecdd406 100644
--- a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-target.h
+++ b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-target.h
@@ -21,10 +21,4 @@
21#ifndef LCD_TARGET_H 21#ifndef LCD_TARGET_H
22#define LCD_TARGET_H 22#define LCD_TARGET_H
23 23
24#define LCD_FRAMEBUF_ADDR(col, row) ((fb_data *)lcd_framebuffer + (row)*LCD_WIDTH + (col))
25
26/* Not really optimized, but are unusual */
27#define LCD_OPTIMIZED_UPDATE
28#define LCD_OPTIMIZED_UPDATE_RECT
29
30#endif /* LCD_TARGET_H */ 24#endif /* LCD_TARGET_H */