summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c283
-rw-r--r--firmware/target/arm/imx233/sansa-fuzeplus/lcd-target.h6
3 files changed, 259 insertions, 31 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 87a2df4b1f..18e76a895b 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1322,7 +1322,6 @@ target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S
1322#endif /* SANSA_FUZEV2 */ 1322#endif /* SANSA_FUZEV2 */
1323 1323
1324#ifdef SANSA_FUZEPLUS 1324#ifdef SANSA_FUZEPLUS
1325drivers/lcd-memframe.c
1326drivers/synaptics-rmi.c 1325drivers/synaptics-rmi.c
1327drivers/generic_i2c.c 1326drivers/generic_i2c.c
1328target/arm/imx233/sansa-fuzeplus/fmradio-i2c-fuzeplus.c 1327target/arm/imx233/sansa-fuzeplus/fmradio-i2c-fuzeplus.c
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 */