summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/target/arm/imx233/creative-zenxfi2/lcd-zenxfi2.c84
-rw-r--r--firmware/target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c395
-rw-r--r--firmware/target/arm/imx233/lcdif-imx233.c366
-rw-r--r--firmware/target/arm/imx233/lcdif-imx233.h46
-rw-r--r--firmware/target/arm/imx233/pins/pins-imx233.h4
-rw-r--r--firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c216
6 files changed, 418 insertions, 693 deletions
diff --git a/firmware/target/arm/imx233/creative-zenxfi2/lcd-zenxfi2.c b/firmware/target/arm/imx233/creative-zenxfi2/lcd-zenxfi2.c
index 9ff64c4c14..0131a39233 100644
--- a/firmware/target/arm/imx233/creative-zenxfi2/lcd-zenxfi2.c
+++ b/firmware/target/arm/imx233/creative-zenxfi2/lcd-zenxfi2.c
@@ -34,66 +34,15 @@ static bool lcd_on;
34#endif 34#endif
35static unsigned lcd_yuv_options = 0; 35static unsigned lcd_yuv_options = 0;
36 36
37static void setup_parameters(void) 37static void setup_lcdif(void)
38{ 38{
39 imx233_lcdif_reset(); 39 imx233_lcdif_init();
40 imx233_lcdif_set_lcd_databus_width(BV_LCDIF_CTRL_LCD_DATABUS_WIDTH__18_BIT); 40 imx233_lcdif_set_lcd_databus_width(18);
41 imx233_lcdif_set_word_length(BV_LCDIF_CTRL_WORD_LENGTH__18_BIT); 41 imx233_lcdif_set_word_length(18);
42 imx233_lcdif_set_timings(2, 2, 3, 3); 42 imx233_lcdif_set_timings(2, 2, 3, 3);
43 imx233_lcdif_enable_underflow_recover(true); 43 imx233_lcdif_enable_underflow_recover(true);
44} 44 imx233_lcdif_enable(true);
45 45 imx233_lcdif_setup_system_pins(18);
46static void setup_lcd_pins(bool use_lcdif)
47{
48 imx233_pinctrl_acquire(1, 18, "lcd reset");
49 imx233_pinctrl_acquire(1, 19, "lcd rs");
50 imx233_pinctrl_acquire(1, 20, "lcd wr");
51 imx233_pinctrl_acquire(1, 21, "lcd cs");
52 imx233_pinctrl_acquire(1, 22, "lcd dotclk");
53 imx233_pinctrl_acquire(1, 23, "lcd enable");
54 imx233_pinctrl_acquire(1, 24, "lcd hsync");
55 imx233_pinctrl_acquire(1, 25, "lcd vsync");
56 //imx233_pinctrl_acquire_mask(1, 0x3ffff, "lcd data");
57 if(use_lcdif)
58 {
59 imx233_pinctrl_set_function(1, 25, PINCTRL_FUNCTION_MAIN); /* lcd_vsync */
60 imx233_pinctrl_set_function(1, 21, PINCTRL_FUNCTION_MAIN); /* lcd_cs */
61 imx233_pinctrl_set_function(1, 22, PINCTRL_FUNCTION_MAIN); /* lcd_dotclk */
62 imx233_pinctrl_set_function(1, 23, PINCTRL_FUNCTION_MAIN); /* lcd_enable */
63 imx233_pinctrl_set_function(1, 24, PINCTRL_FUNCTION_MAIN); /* lcd_hsync */
64 imx233_pinctrl_set_function(1, 18, PINCTRL_FUNCTION_MAIN); /* lcd_reset */
65 imx233_pinctrl_set_function(1, 19, PINCTRL_FUNCTION_MAIN); /* lcd_rs */
66 imx233_pinctrl_set_function(1, 16, PINCTRL_FUNCTION_MAIN); /* lcd_d16 */
67 imx233_pinctrl_set_function(1, 17, PINCTRL_FUNCTION_MAIN); /* lcd_d17 */
68 imx233_pinctrl_set_function(1, 20, PINCTRL_FUNCTION_MAIN); /* lcd_wr */
69 HW_PINCTRL_MUXSELn_CLR(2) = 0xffffffff; /* lcd_d{0-15} */
70 }
71 else
72 {
73 HW_PINCTRL_MUXSELn_SET(2) = 0xffffffff; /* lcd_d{0-15} */
74 HW_PINCTRL_DOEn_CLR(1) = 0x3ffffff; /* lcd_{d{0-17},reset,rs,wr,cs,dotclk,enable,hsync,vsync} */
75 imx233_pinctrl_set_function(1, 16, PINCTRL_FUNCTION_GPIO); /* lcd_d16 */
76 imx233_pinctrl_set_function(1, 17, PINCTRL_FUNCTION_GPIO); /* lcd_d17 */
77 imx233_pinctrl_set_function(1, 19, PINCTRL_FUNCTION_GPIO); /* lcd_rs */
78 imx233_pinctrl_set_function(1, 20, PINCTRL_FUNCTION_GPIO); /* lcd_wr */
79 imx233_pinctrl_set_function(1, 21, PINCTRL_FUNCTION_GPIO); /* lcd_cs */
80 imx233_pinctrl_set_function(1, 22, PINCTRL_FUNCTION_GPIO); /* lcd_dotclk */
81 imx233_pinctrl_set_function(1, 23, PINCTRL_FUNCTION_GPIO); /* lcd_enable */
82 imx233_pinctrl_set_function(1, 24, PINCTRL_FUNCTION_GPIO); /* lcd_hsync */
83 imx233_pinctrl_set_function(1, 25, PINCTRL_FUNCTION_GPIO); /* lcd_vsync */
84 }
85}
86
87static void common_lcd_enable(bool enable)
88{
89 imx233_lcdif_enable(enable);
90 setup_lcd_pins(enable); /* use GPIO pins when disable */
91}
92
93static void setup_lcdif(void)
94{
95 setup_parameters();
96 common_lcd_enable(true);
97 imx233_lcdif_enable_bus_master(true); 46 imx233_lcdif_enable_bus_master(true);
98} 47}
99 48
@@ -120,13 +69,13 @@ static void lcd_write_reg(uint32_t reg, uint32_t data)
120{ 69{
121 uint32_t old_reg = reg; 70 uint32_t old_reg = reg;
122 /* get back to 18-bit word length */ 71 /* get back to 18-bit word length */
123 imx233_lcdif_set_word_length(BV_LCDIF_CTRL_WORD_LENGTH__18_BIT); 72 imx233_lcdif_set_word_length(18);
124 reg = encode_16_to_18(reg); 73 reg = encode_16_to_18(reg);
125 data = encode_16_to_18(data); 74 data = encode_16_to_18(data);
126 75
127 imx233_lcdif_pio_send(false, 2, &reg); 76 imx233_lcdif_pio_send(false, 1, &reg);
128 if(old_reg != 0 && old_reg != 0x202) 77 if(old_reg != 0 && old_reg != 0x202)
129 imx233_lcdif_pio_send(true, 2, &data); 78 imx233_lcdif_pio_send(true, 1, &data);
130} 79}
131 80
132#define REG_MDELAY 0xffffffff 81#define REG_MDELAY 0xffffffff
@@ -208,11 +157,11 @@ void lcd_init_device(void)
208 setup_lcdif_clock(); 157 setup_lcdif_clock();
209 158
210 // reset device 159 // reset device
211 BF_SET(LCDIF_CTRL1, RESET); 160 imx233_lcdif_reset_lcd(true);
212 mdelay(50); 161 mdelay(50);
213 BF_CLR(LCDIF_CTRL1, RESET); 162 imx233_lcdif_reset_lcd(false);
214 mdelay(10); 163 mdelay(10);
215 BF_SET(LCDIF_CTRL1, RESET); 164 imx233_lcdif_reset_lcd(true);
216 165
217 lcd_init_seq(); 166 lcd_init_seq();
218#ifdef HAVE_LCD_ENABLE 167#ifdef HAVE_LCD_ENABLE
@@ -247,12 +196,8 @@ void lcd_enable(bool enable)
247 196
248 lcd_on = enable; 197 lcd_on = enable;
249 198
250 if(enable)
251 common_lcd_enable(true);
252 lcd_enable_seq(enable); 199 lcd_enable_seq(enable);
253 if(!enable) 200 if(enable)
254 common_lcd_enable(false);
255 else
256 send_event(LCD_EVENT_ACTIVATION, NULL); 201 send_event(LCD_EVENT_ACTIVATION, NULL);
257} 202}
258#endif 203#endif
@@ -283,9 +228,8 @@ void lcd_update_rect(int x, int y, int w, int h)
283 lcd_write_reg(0x201, 0); 228 lcd_write_reg(0x201, 0);
284 lcd_write_reg(0x202, 0); 229 lcd_write_reg(0x202, 0);
285 imx233_lcdif_wait_ready(); 230 imx233_lcdif_wait_ready();
286 imx233_lcdif_set_word_length(BV_LCDIF_CTRL_WORD_LENGTH__16_BIT); 231 imx233_lcdif_set_word_length(16);
287 imx233_lcdif_set_byte_packing_format(0xf); /* two pixels per 32-bit word */ 232 imx233_lcdif_set_byte_packing_format(0xf); /* two pixels per 32-bit word */
288 imx233_lcdif_set_data_format(false, false, false); /* RGB565, don't care, don't care */
289 233
290 /* there are two cases here: 234 /* there are two cases here:
291 * - either width = LCD_WIDTH and we can directly memcopy a part of lcd_framebuffer to FRAME 235 * - either width = LCD_WIDTH and we can directly memcopy a part of lcd_framebuffer to FRAME
diff --git a/firmware/target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c b/firmware/target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c
index 7afdaa316e..59496f2d24 100644
--- a/firmware/target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c
+++ b/firmware/target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c
@@ -32,161 +32,76 @@
32#ifdef HAVE_LCD_ENABLE 32#ifdef HAVE_LCD_ENABLE
33static bool lcd_on; 33static bool lcd_on;
34#endif 34#endif
35static unsigned lcd_yuv_options = 0;
36 35
37static void setup_parameters(void) 36static void lcd_write_reg(uint16_t reg, uint16_t data)
38{ 37{
39 imx233_lcdif_reset(); 38 imx233_lcdif_pio_send(false, 1, &reg);
40 imx233_lcdif_set_lcd_databus_width(BV_LCDIF_CTRL_LCD_DATABUS_WIDTH__16_BIT); 39 if(reg != 0x22)
41 imx233_lcdif_set_word_length(BV_LCDIF_CTRL_WORD_LENGTH__16_BIT); 40 imx233_lcdif_pio_send(true, 1, &data);
42 imx233_lcdif_set_timings(2, 2, 3, 3);
43 imx233_lcdif_enable_underflow_recover(true);
44}
45
46static void setup_lcd_pins(bool use_lcdif)
47{
48 /* WARNING
49 * the B1P22 pins is used to gate the speaker! Do NOT drive
50 * them as lcd_dotclk and lcd_hsync or it will break audio */
51 imx233_pinctrl_acquire(1, 18, "lcd reset");
52 imx233_pinctrl_acquire(1, 19, "lcd rs");
53 imx233_pinctrl_acquire(1, 20, "lcd wr");
54 imx233_pinctrl_acquire(1, 21, "lcd cs");
55 imx233_pinctrl_acquire(1, 23, "lcd enable");
56 imx233_pinctrl_acquire(1, 25, "lcd vsync");
57 //imx233_pinctrl_acquire_mask(1, 0x3ffff, "lcd data");
58 if(use_lcdif)
59 {
60 imx233_pinctrl_set_function(1, 25, PINCTRL_FUNCTION_MAIN); /* lcd_vsync */
61 imx233_pinctrl_set_function(1, 21, PINCTRL_FUNCTION_MAIN); /* lcd_cs */
62 imx233_pinctrl_set_function(1, 23, PINCTRL_FUNCTION_MAIN); /* lcd_enable */
63 imx233_pinctrl_set_function(1, 18, PINCTRL_FUNCTION_MAIN); /* lcd_reset */
64 imx233_pinctrl_set_function(1, 19, PINCTRL_FUNCTION_MAIN); /* lcd_rs */
65 imx233_pinctrl_set_function(1, 16, PINCTRL_FUNCTION_MAIN); /* lcd_d16 */
66 imx233_pinctrl_set_function(1, 17, PINCTRL_FUNCTION_MAIN); /* lcd_d17 */
67 imx233_pinctrl_set_function(1, 20, PINCTRL_FUNCTION_MAIN); /* lcd_wr */
68 HW_PINCTRL_MUXSELn_CLR(2) = 0xffffffff; /* lcd_d{0-15} */
69 }
70 else
71 {
72 HW_PINCTRL_MUXSELn_SET(2) = 0xffffffff; /* lcd_d{0-15} */
73 HW_PINCTRL_DOEn_CLR(1) = 0x2bfffff;
74 imx233_pinctrl_set_function(1, 16, PINCTRL_FUNCTION_GPIO); /* lcd_d16 */
75 imx233_pinctrl_set_function(1, 17, PINCTRL_FUNCTION_GPIO); /* lcd_d17 */
76 imx233_pinctrl_set_function(1, 19, PINCTRL_FUNCTION_GPIO); /* lcd_rs */
77 imx233_pinctrl_set_function(1, 20, PINCTRL_FUNCTION_GPIO); /* lcd_wr */
78 imx233_pinctrl_set_function(1, 21, PINCTRL_FUNCTION_GPIO); /* lcd_cs */
79 imx233_pinctrl_set_function(1, 23, PINCTRL_FUNCTION_GPIO); /* lcd_enable */
80 imx233_pinctrl_set_function(1, 25, PINCTRL_FUNCTION_GPIO); /* lcd_vsync */
81 }
82}
83
84static void common_lcd_enable(bool enable)
85{
86 imx233_lcdif_enable(enable);
87 setup_lcd_pins(enable); /* use GPIO pins when disable */
88} 41}
89 42
90static void setup_lcdif(void) 43static void lcd_init_seq(void)
91{ 44{
92 setup_parameters(); 45 lcd_write_reg(1, 0x11c);
93 common_lcd_enable(true); 46 lcd_write_reg(2, 0x100);
94 imx233_lcdif_enable_bus_master(true); 47 lcd_write_reg(3, 0x1030);
48 lcd_write_reg(8, 0x808);
49 lcd_write_reg(0xc, 0);
50 lcd_write_reg(0xf, 0xc01);
51 lcd_write_reg(0x20, 0);
52 lcd_write_reg(0x21, 0);
53 udelay(30);
54 lcd_write_reg(0x10, 0xa00);
55 lcd_write_reg(0x11, 0x1038);
56 udelay(30);
57 lcd_write_reg(0x12, 0x1010);
58 lcd_write_reg(0x13, 0x50);
59 lcd_write_reg(0x14, 0x4f58);
60 lcd_write_reg(0x30, 0);
61 lcd_write_reg(0x31, 0xdb);
62 lcd_write_reg(0x32, 0);
63 lcd_write_reg(0x33, 0);
64 lcd_write_reg(0x34, 0xdb);
65 lcd_write_reg(0x35, 0);
66 lcd_write_reg(0x36, 0xaf);
67 lcd_write_reg(0x37, 0);
68 lcd_write_reg(0x38, 0xdb);
69 lcd_write_reg(0x39, 0);
70 lcd_write_reg(0x50, 0);
71 lcd_write_reg(0x51, 0x705);
72 lcd_write_reg(0x52, 0xe0a);
73 lcd_write_reg(0x53, 0x300);
74 lcd_write_reg(0x54, 0xa0e);
75 lcd_write_reg(0x55, 0x507);
76 lcd_write_reg(0x56, 0);
77 lcd_write_reg(0x57, 3);
78 lcd_write_reg(0x58, 0x90a);
79 lcd_write_reg(0x59, 0xa09);
80 udelay(30);
81 lcd_write_reg(7, 0x1017);
82 udelay(40);
95} 83}
96 84
97static void setup_lcdif_clock(void) 85void lcd_init_device(void)
98{ 86{
99 /* the LCD seems to work at 24Mhz, so use the xtal clock with no divider */ 87 /* the LCD seems to work at 24Mhz, so use the xtal clock with no divider */
100 imx233_clkctrl_enable(CLK_PIX, false); 88 imx233_clkctrl_enable(CLK_PIX, false);
101 imx233_clkctrl_set_div(CLK_PIX, 1); 89 imx233_clkctrl_set_div(CLK_PIX, 1);
102 imx233_clkctrl_set_bypass(CLK_PIX, true); /* use XTAL */ 90 imx233_clkctrl_set_bypass(CLK_PIX, true); /* use XTAL */
103 imx233_clkctrl_enable(CLK_PIX, true); 91 imx233_clkctrl_enable(CLK_PIX, true);
104} 92 imx233_lcdif_init();
105 93 imx233_lcdif_set_lcd_databus_width(16);
106static void lcd_write_reg(uint32_t reg, uint32_t data) 94 imx233_lcdif_set_word_length(16);
107{ 95 imx233_lcdif_set_timings(2, 2, 3, 3);
108 imx233_lcdif_pio_send(false, 2, &reg); 96 imx233_lcdif_enable_underflow_recover(true);
109 if(reg != 0x22) 97 imx233_lcdif_setup_system_pins(16);
110 imx233_lcdif_pio_send(true, 2, &data);
111}
112
113#define REG_UDELAY 0xffffffff
114struct lcd_sequence_entry_t
115{
116 uint32_t reg, data;
117};
118
119static void lcd_send_sequence(struct lcd_sequence_entry_t *seq, unsigned count)
120{
121 for(;count-- > 0; seq++)
122 {
123 if(seq->reg == REG_UDELAY)
124 udelay(seq->data);
125 else
126 lcd_write_reg(seq->reg, seq->data);
127 }
128}
129
130#define _begin_seq() static struct lcd_sequence_entry_t __seq[] = {
131#define _udelay(a) {REG_UDELAY, a},
132#define _lcd_write_reg(a, b) {a, b},
133#define _end_seq() }; lcd_send_sequence(__seq, sizeof(__seq) / sizeof(__seq[0]));
134
135static void lcd_init_seq(void)
136{
137 _begin_seq()
138 _lcd_write_reg(1, 0x11c)
139 _lcd_write_reg(2, 0x100)
140 _lcd_write_reg(3, 0x1030)
141 _lcd_write_reg(8, 0x808)
142 _lcd_write_reg(0xc, 0)
143 _lcd_write_reg(0xf, 0xc01)
144 _lcd_write_reg(0x20, 0)
145 _lcd_write_reg(0x21, 0)
146 _udelay(30)
147 _lcd_write_reg(0x10, 0xa00)
148 _lcd_write_reg(0x11, 0x1038)
149 _udelay(30)
150 _lcd_write_reg(0x12, 0x1010)
151 _lcd_write_reg(0x13, 0x50)
152 _lcd_write_reg(0x14, 0x4f58)
153 _lcd_write_reg(0x30, 0)
154 _lcd_write_reg(0x31, 0xdb)
155 _lcd_write_reg(0x32, 0)
156 _lcd_write_reg(0x33, 0)
157 _lcd_write_reg(0x34, 0xdb)
158 _lcd_write_reg(0x35, 0)
159 _lcd_write_reg(0x36, 0xaf)
160 _lcd_write_reg(0x37, 0)
161 _lcd_write_reg(0x38, 0xdb)
162 _lcd_write_reg(0x39, 0)
163 _lcd_write_reg(0x50, 0)
164 _lcd_write_reg(0x51, 0x705)
165 _lcd_write_reg(0x52, 0xe0a)
166 _lcd_write_reg(0x53, 0x300)
167 _lcd_write_reg(0x54, 0xa0e)
168 _lcd_write_reg(0x55, 0x507)
169 _lcd_write_reg(0x56, 0)
170 _lcd_write_reg(0x57, 3)
171 _lcd_write_reg(0x58, 0x90a)
172 _lcd_write_reg(0x59, 0xa09)
173 _udelay(30)
174 _lcd_write_reg(7, 0x1017)
175 _udelay(40)
176 _end_seq()
177}
178
179void lcd_init_device(void)
180{
181 setup_lcdif();
182 setup_lcdif_clock();
183 98
184 // reset device 99 // reset device
185 BF_SET(LCDIF_CTRL1, RESET); 100 imx233_lcdif_reset_lcd(true);
186 mdelay(50); 101 mdelay(50);
187 BF_CLR(LCDIF_CTRL1, RESET); 102 imx233_lcdif_reset_lcd(false);
188 mdelay(10); 103 mdelay(10);
189 BF_SET(LCDIF_CTRL1, RESET); 104 imx233_lcdif_reset_lcd(true);
190 105
191 lcd_init_seq(); 106 lcd_init_seq();
192#ifdef HAVE_LCD_ENABLE 107#ifdef HAVE_LCD_ENABLE
@@ -204,13 +119,9 @@ static void lcd_enable_seq(bool enable)
204{ 119{
205 if(!enable) 120 if(!enable)
206 { 121 {
207 _begin_seq()
208 _end_seq()
209 } 122 }
210 else 123 else
211 { 124 {
212 _begin_seq()
213 _end_seq()
214 } 125 }
215} 126}
216 127
@@ -220,12 +131,12 @@ void lcd_enable(bool enable)
220 return; 131 return;
221 132
222 lcd_on = enable; 133 lcd_on = enable;
223 134
224 if(enable) 135 if(enable)
225 common_lcd_enable(true); 136 imx233_lcdif_enable(true);
226 lcd_enable_seq(enable); 137 lcd_enable_seq(enable);
227 if(!enable) 138 if(!enable)
228 common_lcd_enable(false); 139 imx233_lcdif_enable(false);
229 else 140 else
230 send_event(LCD_EVENT_ACTIVATION, NULL); 141 send_event(LCD_EVENT_ACTIVATION, NULL);
231} 142}
@@ -258,9 +169,8 @@ void lcd_update_rect(int x, int y, int w, int h)
258 lcd_write_reg(0x22, 0); 169 lcd_write_reg(0x22, 0);
259 170
260 imx233_lcdif_wait_ready(); 171 imx233_lcdif_wait_ready();
261 imx233_lcdif_set_word_length(BV_LCDIF_CTRL_WORD_LENGTH__16_BIT); 172 imx233_lcdif_set_word_length(16);
262 imx233_lcdif_set_byte_packing_format(0xf); /* two pixels per 32-bit word */ 173 imx233_lcdif_set_byte_packing_format(0xf); /* two pixels per 32-bit word */
263 imx233_lcdif_set_data_format(false, false, false); /* RGB565, don't care, don't care */
264 174
265 /* there are two cases here: 175 /* there are two cases here:
266 * - either width = LCD_WIDTH and we can directly memcopy a part of lcd_framebuffer to FRAME 176 * - either width = LCD_WIDTH and we can directly memcopy a part of lcd_framebuffer to FRAME
@@ -306,194 +216,3 @@ void lcd_update_rect(int x, int y, int w, int h)
306 imx233_lcdif_dma_send((void *)FRAME_PHYS_ADDR, w, h); 216 imx233_lcdif_dma_send((void *)FRAME_PHYS_ADDR, w, h);
307} 217}
308 218
309void lcd_yuv_set_options(unsigned options)
310{
311 lcd_yuv_options = options;
312}
313
314#define YFAC (74)
315#define RVFAC (101)
316#define GUFAC (-24)
317#define GVFAC (-51)
318#define BUFAC (128)
319
320static inline int clamp(int val, int min, int max)
321{
322 if (val < min)
323 val = min;
324 else if (val > max)
325 val = max;
326 return val;
327}
328
329void lcd_blit_yuv(unsigned char * const src[3],
330 int src_x, int src_y, int stride,
331 int x, int y, int width, int height)
332{
333 const unsigned char *ysrc, *usrc, *vsrc;
334 int linecounter;
335 fb_data *dst, *row_end;
336 long z;
337
338 /* width and height must be >= 2 and an even number */
339 width &= ~1;
340 linecounter = height >> 1;
341
342 #if LCD_WIDTH >= LCD_HEIGHT
343 dst = FBADDR(x,y);
344 row_end = dst + width;
345 #else
346 dst = FBADDR(LCD_WIDTH - y - 1,x);
347 row_end = dst + LCD_WIDTH * width;
348 #endif
349
350 z = stride * src_y;
351 ysrc = src[0] + z + src_x;
352 usrc = src[1] + (z >> 2) + (src_x >> 1);
353 vsrc = src[2] + (usrc - src[1]);
354
355 /* stride => amount to jump from end of last row to start of next */
356 stride -= width;
357
358 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
359
360 do
361 {
362 do
363 {
364 int y, cb, cr, rv, guv, bu, r, g, b;
365
366 y = YFAC*(*ysrc++ - 16);
367 cb = *usrc++ - 128;
368 cr = *vsrc++ - 128;
369
370 rv = RVFAC*cr;
371 guv = GUFAC*cb + GVFAC*cr;
372 bu = BUFAC*cb;
373
374 r = y + rv;
375 g = y + guv;
376 b = y + bu;
377
378 if ((unsigned)(r | g | b) > 64*256-1)
379 {
380 r = clamp(r, 0, 64*256-1);
381 g = clamp(g, 0, 64*256-1);
382 b = clamp(b, 0, 64*256-1);
383 }
384
385 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
386
387 #if LCD_WIDTH >= LCD_HEIGHT
388 dst++;
389 #else
390 dst += LCD_WIDTH;
391 #endif
392
393 y = YFAC*(*ysrc++ - 16);
394 r = y + rv;
395 g = y + guv;
396 b = y + bu;
397
398 if ((unsigned)(r | g | b) > 64*256-1)
399 {
400 r = clamp(r, 0, 64*256-1);
401 g = clamp(g, 0, 64*256-1);
402 b = clamp(b, 0, 64*256-1);
403 }
404
405 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
406
407 #if LCD_WIDTH >= LCD_HEIGHT
408 dst++;
409 #else
410 dst += LCD_WIDTH;
411 #endif
412 }
413 while (dst < row_end);
414
415 ysrc += stride;
416 usrc -= width >> 1;
417 vsrc -= width >> 1;
418
419 #if LCD_WIDTH >= LCD_HEIGHT
420 row_end += LCD_WIDTH;
421 dst += LCD_WIDTH - width;
422 #else
423 row_end -= 1;
424 dst -= LCD_WIDTH*width + 1;
425 #endif
426
427 do
428 {
429 int y, cb, cr, rv, guv, bu, r, g, b;
430
431 y = YFAC*(*ysrc++ - 16);
432 cb = *usrc++ - 128;
433 cr = *vsrc++ - 128;
434
435 rv = RVFAC*cr;
436 guv = GUFAC*cb + GVFAC*cr;
437 bu = BUFAC*cb;
438
439 r = y + rv;
440 g = y + guv;
441 b = y + bu;
442
443 if ((unsigned)(r | g | b) > 64*256-1)
444 {
445 r = clamp(r, 0, 64*256-1);
446 g = clamp(g, 0, 64*256-1);
447 b = clamp(b, 0, 64*256-1);
448 }
449
450 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
451
452 #if LCD_WIDTH >= LCD_HEIGHT
453 dst++;
454 #else
455 dst += LCD_WIDTH;
456 #endif
457
458 y = YFAC*(*ysrc++ - 16);
459 r = y + rv;
460 g = y + guv;
461 b = y + bu;
462
463 if ((unsigned)(r | g | b) > 64*256-1)
464 {
465 r = clamp(r, 0, 64*256-1);
466 g = clamp(g, 0, 64*256-1);
467 b = clamp(b, 0, 64*256-1);
468 }
469
470 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
471
472 #if LCD_WIDTH >= LCD_HEIGHT
473 dst++;
474 #else
475 dst += LCD_WIDTH;
476 #endif
477 }
478 while (dst < row_end);
479
480 ysrc += stride;
481 usrc += stride >> 1;
482 vsrc += stride >> 1;
483
484 #if LCD_WIDTH >= LCD_HEIGHT
485 row_end += LCD_WIDTH;
486 dst += LCD_WIDTH - width;
487 #else
488 row_end -= 1;
489 dst -= LCD_WIDTH*width + 1;
490 #endif
491 }
492 while (--linecounter > 0);
493
494 #if LCD_WIDTH >= LCD_HEIGHT
495 lcd_update_rect(x, y, width, height);
496 #else
497 lcd_update_rect(LCD_WIDTH - y - height, x, height, width);
498 #endif
499}
diff --git a/firmware/target/arm/imx233/lcdif-imx233.c b/firmware/target/arm/imx233/lcdif-imx233.c
index f947fa69f1..da58270498 100644
--- a/firmware/target/arm/imx233/lcdif-imx233.c
+++ b/firmware/target/arm/imx233/lcdif-imx233.c
@@ -19,36 +19,62 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "lcdif-imx233.h" 21#include "lcdif-imx233.h"
22#include "pinctrl-imx233.h"
23#include "icoll-imx233.h"
22 24
23static unsigned lcdif_word_length = 0; 25#if IMX233_SUBTARGET >= 3700
26static lcdif_irq_cb_t g_cur_frame_cb = NULL;
27static lcdif_irq_cb_t g_vsync_edge_cb = NULL;
28#endif
24 29
25void imx233_lcdif_enable_underflow_recover(bool enable) 30/* for some crazy reason, all "non-dma" interrupts are routed to the ERROR irq */
31#if IMX233_SUBTARGET >= 3700
32void INT_LCDIF_ERROR(void)
26{ 33{
27 if(enable) 34 if(BF_RD(LCDIF_CTRL1, CUR_FRAME_DONE_IRQ))
28 BF_SET(LCDIF_CTRL1, RECOVER_ON_UNDERFLOW); 35 {
29 else 36 if(g_cur_frame_cb)
30 BF_CLR(LCDIF_CTRL1, RECOVER_ON_UNDERFLOW); 37 g_cur_frame_cb();
38 BF_CLR(LCDIF_CTRL1, CUR_FRAME_DONE_IRQ);
39 }
40 if(BF_RD(LCDIF_CTRL1, VSYNC_EDGE_IRQ))
41 {
42 if(g_vsync_edge_cb)
43 g_vsync_edge_cb();
44 BF_CLR(LCDIF_CTRL1, VSYNC_EDGE_IRQ);
45 }
31} 46}
47#endif
32 48
33void imx233_lcdif_enable_bus_master(bool enable) 49void imx233_lcdif_enable(bool enable)
34{ 50{
35 if(enable) 51 if(enable)
36 BF_SET(LCDIF_CTRL, LCDIF_MASTER); 52 BF_CLR(LCDIF_CTRL, CLKGATE);
37 else 53 else
38 BF_CLR(LCDIF_CTRL, LCDIF_MASTER); 54 BF_SET(LCDIF_CTRL, CLKGATE);
39} 55}
40 56
41void imx233_lcdif_enable(bool enable) 57void imx233_lcdif_reset_lcd(bool enable)
42{ 58{
59#if IMX233_SUBTARGET < 3700
43 if(enable) 60 if(enable)
44 BF_CLR(LCDIF_CTRL, CLKGATE); 61 BF_SET(LCDIF_CTRL, RESET);
45 else 62 else
46 BF_SET(LCDIF_CTRL, CLKGATE); 63 BF_CLR(LCDIF_CTRL, RESET);
64#else
65 if(enable)
66 BF_SET(LCDIF_CTRL1, RESET);
67 else
68 BF_CLR(LCDIF_CTRL1, RESET);
69#endif
47} 70}
48 71
49void imx233_lcdif_reset(void) 72void imx233_lcdif_init(void)
50{ 73{
51 imx233_reset_block(&HW_LCDIF_CTRL); 74 imx233_reset_block(&HW_LCDIF_CTRL);
75#if IMX233_SUBTARGET >= 3700
76 imx233_icoll_enable_interrupt(INT_SRC_LCDIF_ERROR, true);
77#endif
52} 78}
53 79
54void imx233_lcdif_set_timings(unsigned data_setup, unsigned data_hold, 80void imx233_lcdif_set_timings(unsigned data_setup, unsigned data_hold,
@@ -58,90 +84,286 @@ void imx233_lcdif_set_timings(unsigned data_setup, unsigned data_hold,
58 DATA_HOLD(data_hold), CMD_SETUP(cmd_setup), CMD_HOLD(cmd_hold)); 84 DATA_HOLD(data_hold), CMD_SETUP(cmd_setup), CMD_HOLD(cmd_hold));
59} 85}
60 86
61void imx233_lcdif_set_lcd_databus_width(unsigned width) 87void imx233_lcdif_set_word_length(unsigned word_length)
62{ 88{
63 BF_WR(LCDIF_CTRL, LCD_DATABUS_WIDTH, width); 89 switch(word_length)
90 {
91 case 8: BF_WR_V(LCDIF_CTRL, WORD_LENGTH, 8_BIT); break;
92 case 16: BF_WR_V(LCDIF_CTRL, WORD_LENGTH, 16_BIT); break;
93#if IMX233_SUBTARGET >= 3780
94 case 18: BF_WR_V(LCDIF_CTRL, WORD_LENGTH, 18_BIT); break;
95 case 24: BF_WR_V(LCDIF_CTRL, WORD_LENGTH, 24_BIT); break;
96#endif
97 default:
98 panicf("this chip cannot handle a lcd word length of %d", word_length);
99 break;
100 }
64} 101}
65 102
66void imx233_lcdif_set_word_length(unsigned word_length) 103void imx233_lcdif_wait_ready(void)
67{ 104{
68 BF_WR(LCDIF_CTRL, WORD_LENGTH, word_length); 105 while(BF_RD(LCDIF_CTRL, RUN));
69 lcdif_word_length = word_length;
70} 106}
71 107
72void imx233_lcdif_set_byte_packing_format(unsigned byte_packing) 108void imx233_lcdif_set_data_swizzle(unsigned swizzle)
73{ 109{
74 BF_WR(LCDIF_CTRL1, BYTE_PACKING_FORMAT, byte_packing); 110#if IMX233_SUBTARGET >= 3780
111 BF_WR(LCDIF_CTRL, INPUT_DATA_SWIZZLE, swizzle);
112#else
113 BF_WR(LCDIF_CTRL, DATA_SWIZZLE, swizzle);
114#endif
75} 115}
76 116
77void imx233_lcdif_set_data_format(bool data_fmt_16, bool data_fmt_18, bool data_fmt_24) 117void imx233_lcdif_wait_fifo(void)
78{ 118{
79 if(data_fmt_16) 119#if IMX233_SUBTARGET >= 3700
80 BF_SET(LCDIF_CTRL, DATA_FORMAT_16_BIT); 120 while(BF_RD(LCDIF_STAT, TXFIFO_FULL));
81 else 121#else
82 BF_CLR(LCDIF_CTRL, DATA_FORMAT_16_BIT); 122 while(!BF_RD(LCDIF_CTRL, FIFO_STATUS));
83 if(data_fmt_18) 123#endif
84 BF_SET(LCDIF_CTRL, DATA_FORMAT_18_BIT);
85 else
86 BF_CLR(LCDIF_CTRL, DATA_FORMAT_18_BIT);
87 if(data_fmt_24)
88 BF_SET(LCDIF_CTRL, DATA_FORMAT_24_BIT);
89 else
90 BF_CLR(LCDIF_CTRL, DATA_FORMAT_24_BIT);
91} 124}
92 125
93void imx233_lcdif_wait_ready(void) 126/* The following function set byte packing often, ifdefing everytime is painful */
127#if IMX233_SUBTARGET < 3700
128#define imx233_lcdif_set_byte_packing_format(a)
129#endif
130
131// bbp = bytes per pixel
132static void pio_send(unsigned len, unsigned bpp, uint8_t *buf)
94{ 133{
95 while(BF_RD(LCDIF_CTRL, RUN)); 134 /* WARNING: the imx233 has a limitation on count wrt to byte packing, the
135 * count must be a multiple of 2 with maximum packing when word-length is
136 * 16-bit!
137 * On the other hand, 8-bit word length doesn't seem to have any limitations,
138 * for example one can send 3 bytes with a packing format of 0xf
139 * WARNING for this function to work properly with any swizzle, we have to
140 * make sure we pack as many 32-bits as possible even when the data is not
141 * word-aligned */
142 imx233_lcdif_set_byte_packing_format(0xf);
143 /* compute shift between buf and next word-aligned pointer */
144 int shift = 0;
145 uint32_t temp_buf = 0;
146 int count = len * bpp; // number of bytes
147 while(0x3 & (intptr_t)buf)
148 {
149 temp_buf = temp_buf | *buf++ << shift;
150 shift += 8;
151 count--;
152 }
153 /* starting from now, all read are 32-bit */
154 uint32_t *wbuf = (void *)buf;
155#if IMX233_SUBTARGET >= 3780
156 HW_LCDIF_TRANSFER_COUNT = BF_OR2(LCDIF_TRANSFER_COUNT, V_COUNT(1), H_COUNT(len));
157#else
158 BF_WR(LCDIF_CTRL, COUNT, len);
159#endif
160 BF_SET(LCDIF_CTRL, RUN);
161 while(count > 0)
162 {
163 uint32_t val = *wbuf++;
164 imx233_lcdif_wait_fifo();
165 HW_LCDIF_DATA = temp_buf | val << shift;
166 if(shift != 0)
167 temp_buf = val >> (32 - shift);
168 count -= 4;
169 }
170 /* send remaining bytes if any */
171 if(shift != 0)
172 {
173 imx233_lcdif_wait_fifo();
174 HW_LCDIF_DATA = temp_buf;
175 }
176 imx233_lcdif_wait_ready();
96} 177}
97 178
98void imx233_lcdif_pio_send(bool data_mode, unsigned len, uint32_t *buf) 179void imx233_lcdif_pio_send(bool data_mode, unsigned len, void *buf)
99{ 180{
100 unsigned max_xfer_size = 0xffff;
101 if(len == 0)
102 return;
103 if(lcdif_word_length == BV_LCDIF_CTRL_WORD_LENGTH__16_BIT)
104 max_xfer_size = 0x1fffe;
105 imx233_lcdif_wait_ready(); 181 imx233_lcdif_wait_ready();
182#if IMX233_SUBTARGET >= 3780
106 imx233_lcdif_enable_bus_master(false); 183 imx233_lcdif_enable_bus_master(false);
184#endif
185 if(data_mode)
186 BF_SET(LCDIF_CTRL, DATA_SELECT);
187 else
188 BF_CLR(LCDIF_CTRL, DATA_SELECT);
107 189
108 do 190 switch(BF_RD(LCDIF_CTRL, WORD_LENGTH))
109 { 191 {
110 unsigned burst = MIN(len, max_xfer_size); 192 case BV_LCDIF_CTRL_WORD_LENGTH__8_BIT: pio_send(len, 1, buf); break;
111 len -= burst; 193 case BV_LCDIF_CTRL_WORD_LENGTH__16_BIT: pio_send(len, 2, buf); break;
112 unsigned count = burst; 194#if IMX233_SUBTARGET >= 3780
113 if(lcdif_word_length != BV_LCDIF_CTRL_WORD_LENGTH__8_BIT) 195 case BV_LCDIF_CTRL_WORD_LENGTH__18_BIT: pio_send(len, 4, buf); break;
114 { 196#endif
115 if(burst & 1) 197 default: panicf("Don't know how to handle this word length");
116 burst++; 198 }
117 count = burst / 2;
118 }
119 else
120 count = burst;
121 HW_LCDIF_TRANSFER_COUNT = 0;
122 HW_LCDIF_TRANSFER_COUNT = 0x10000 | count;
123 BF_CLR(LCDIF_CTRL, DATA_SELECT);
124 BF_CLR(LCDIF_CTRL, RUN);
125 if(data_mode)
126 BF_SET(LCDIF_CTRL, DATA_SELECT);
127 BF_SET(LCDIF_CTRL, RUN);
128 burst = (burst + 3) / 4;
129 while(burst-- > 0)
130 {
131 while(BF_RD(LCDIF_STAT, LFIFO_FULL));
132 HW_LCDIF_DATA = *buf++;
133 }
134 imx233_lcdif_wait_ready();
135 }while(len > 0);
136 imx233_lcdif_enable_bus_master(true);
137} 199}
138 200
139void imx233_lcdif_dma_send(void *buf, unsigned width, unsigned height) 201void imx233_lcdif_dma_send(void *buf, unsigned width, unsigned height)
140{ 202{
203#if IMX233_SUBTARGET >= 3780
204 imx233_lcdif_enable_bus_master(true);
141 HW_LCDIF_CUR_BUF = (uint32_t)buf; 205 HW_LCDIF_CUR_BUF = (uint32_t)buf;
142 HW_LCDIF_TRANSFER_COUNT = 0; 206 HW_LCDIF_TRANSFER_COUNT = BF_OR2(LCDIF_TRANSFER_COUNT, V_COUNT(height), H_COUNT(width));
143 HW_LCDIF_TRANSFER_COUNT = (height << 16) | width;
144 BF_CLR(LCDIF_CTRL, RUN);
145 BF_SET(LCDIF_CTRL, DATA_SELECT); 207 BF_SET(LCDIF_CTRL, DATA_SELECT);
146 BF_SET(LCDIF_CTRL, RUN); 208 BF_SET(LCDIF_CTRL, RUN);
209#endif
210}
211
212static void setup_data_pins(unsigned bus_width)
213{
214 imx233_pinctrl_setup_vpin(VPIN_LCD_D0, "lcd d0", PINCTRL_DRIVE_4mA, false);
215 imx233_pinctrl_setup_vpin(VPIN_LCD_D1, "lcd d1", PINCTRL_DRIVE_4mA, false);
216 imx233_pinctrl_setup_vpin(VPIN_LCD_D2, "lcd d2", PINCTRL_DRIVE_4mA, false);
217 imx233_pinctrl_setup_vpin(VPIN_LCD_D3, "lcd d3", PINCTRL_DRIVE_4mA, false);
218 imx233_pinctrl_setup_vpin(VPIN_LCD_D4, "lcd d4", PINCTRL_DRIVE_4mA, false);
219 imx233_pinctrl_setup_vpin(VPIN_LCD_D5, "lcd d5", PINCTRL_DRIVE_4mA, false);
220 imx233_pinctrl_setup_vpin(VPIN_LCD_D6, "lcd d6", PINCTRL_DRIVE_4mA, false);
221 imx233_pinctrl_setup_vpin(VPIN_LCD_D7, "lcd d7", PINCTRL_DRIVE_4mA, false);
222 if(bus_width >= 16)
223 {
224 imx233_pinctrl_setup_vpin(VPIN_LCD_D8, "lcd d8", PINCTRL_DRIVE_4mA, false);
225 imx233_pinctrl_setup_vpin(VPIN_LCD_D9, "lcd d9", PINCTRL_DRIVE_4mA, false);
226 imx233_pinctrl_setup_vpin(VPIN_LCD_D10, "lcd d10", PINCTRL_DRIVE_4mA, false);
227 imx233_pinctrl_setup_vpin(VPIN_LCD_D11, "lcd d11", PINCTRL_DRIVE_4mA, false);
228 imx233_pinctrl_setup_vpin(VPIN_LCD_D12, "lcd d12", PINCTRL_DRIVE_4mA, false);
229 imx233_pinctrl_setup_vpin(VPIN_LCD_D13, "lcd d13", PINCTRL_DRIVE_4mA, false);
230 imx233_pinctrl_setup_vpin(VPIN_LCD_D14, "lcd d14", PINCTRL_DRIVE_4mA, false);
231 imx233_pinctrl_setup_vpin(VPIN_LCD_D15, "lcd d15", PINCTRL_DRIVE_4mA, false);
232 }
233#if IMX233_SUBTARGET >= 3780
234 if(bus_width >= 18)
235 {
236 imx233_pinctrl_setup_vpin(VPIN_LCD_D16, "lcd d16", PINCTRL_DRIVE_4mA, false);
237 imx233_pinctrl_setup_vpin(VPIN_LCD_D17, "lcd d17", PINCTRL_DRIVE_4mA, false);
238 }
239#endif
240}
241
242void imx233_lcdif_setup_system_pins(unsigned bus_width)
243{
244 imx233_pinctrl_setup_vpin(VPIN_LCD_RESET, "lcd reset", PINCTRL_DRIVE_4mA, false);
245 imx233_pinctrl_setup_vpin(VPIN_LCD_RS, "lcd rs", PINCTRL_DRIVE_4mA, false);
246 imx233_pinctrl_setup_vpin(VPIN_LCD_WR, "lcd wr", PINCTRL_DRIVE_4mA, false);
247#ifdef VPIN_LCD_RD
248 imx233_pinctrl_setup_vpin(VPIN_LCD_RD, "lcd rd", PINCTRL_DRIVE_4mA, false);
249#endif
250 imx233_pinctrl_setup_vpin(VPIN_LCD_CS, "lcd cs", PINCTRL_DRIVE_4mA, false);
251
252 setup_data_pins(bus_width);
253}
254
255#if IMX233_SUBTARGET >= 3700
256void imx233_lcdif_setup_dotclk_pins(unsigned bus_width, bool have_enable)
257{
258 if(have_enable)
259 imx233_pinctrl_setup_vpin(VPIN_LCD_ENABLE, "lcd enable", PINCTRL_DRIVE_4mA, false);
260 imx233_pinctrl_setup_vpin(VPIN_LCD_RESET, "lcd reset", PINCTRL_DRIVE_4mA, false);
261 imx233_pinctrl_setup_vpin(VPIN_LCD_HSYNC, "lcd hsync", PINCTRL_DRIVE_4mA, false);
262 imx233_pinctrl_setup_vpin(VPIN_LCD_VSYNC, "lcd vsync", PINCTRL_DRIVE_4mA, false);
263 imx233_pinctrl_setup_vpin(VPIN_LCD_DOTCLK, "lcd dotclk", PINCTRL_DRIVE_4mA, false);
264
265 setup_data_pins(bus_width);
266}
267
268void imx233_lcdif_set_byte_packing_format(unsigned byte_packing)
269{
270 BF_WR(LCDIF_CTRL1, BYTE_PACKING_FORMAT, byte_packing);
271}
272#endif
273
274#if IMX233_SUBTARGET >= 3700 && IMX233_SUBTARGET < 3780
275void imx233_lcdif_enable_sync_signals(bool en)
276{
277 BF_WR(LCDIF_VDCTRL3, SYNC_SIGNALS_ON, en);
278}
279
280void imx233_lcdif_setup_dotclk(unsigned v_pulse_width, unsigned v_period,
281 unsigned v_wait_cnt, unsigned v_active, unsigned h_pulse_width,
282 unsigned h_period, unsigned h_wait_cnt, unsigned h_active, bool enable_present)
283{
284 HW_LCDIF_VDCTRL0 = BF_OR4(LCDIF_VDCTRL0, ENABLE_PRESENT(enable_present),
285 VSYNC_PERIOD_UNIT(1), VSYNC_PULSE_WIDTH_UNIT(1),
286 DOTCLK_V_VALID_DATA_CNT(v_active));
287 HW_LCDIF_VDCTRL1 = BF_OR2(LCDIF_VDCTRL1, VSYNC_PERIOD(v_period),
288 VSYNC_PULSE_WIDTH(v_pulse_width));
289 HW_LCDIF_VDCTRL2 = BF_OR3(LCDIF_VDCTRL2, HSYNC_PULSE_WIDTH(h_pulse_width),
290 HSYNC_PERIOD(h_period), DOTCLK_H_VALID_DATA_CNT(h_active));
291 HW_LCDIF_VDCTRL3 = BF_OR2(LCDIF_VDCTRL3, VERTICAL_WAIT_CNT(v_wait_cnt),
292 HORIZONTAL_WAIT_CNT(h_wait_cnt));
293 // setup dotclk mode, always bypass count, apparently data select is needed
294 HW_LCDIF_CTRL_SET = BM_OR3(LCDIF_CTRL, DOTCLK_MODE, BYPASS_COUNT, DATA_SELECT);
295}
296
297void imx233_lcdif_setup_dotclk_ex(unsigned v_pulse_width, unsigned v_back_porch,
298 unsigned v_front_porch, unsigned h_pulse_width, unsigned h_back_porch,
299 unsigned h_front_porch, unsigned width, unsigned height, unsigned clk_per_pix,
300 bool enable_present)
301{
302 unsigned h_active = clk_per_pix * width;
303 unsigned h_period = h_active + h_back_porch + h_front_porch;
304 unsigned v_active = height;
305 unsigned v_period = v_active + v_back_porch + v_front_porch;
306 imx233_lcdif_setup_dotclk(v_pulse_width, v_period, v_back_porch, v_active,
307 h_pulse_width, h_period, h_back_porch, h_active, enable_present);
308}
309
310void imx233_lcdif_enable_frame_done_irq(bool en)
311{
312 if(en)
313 BF_SET(LCDIF_CTRL1, CUR_FRAME_DONE_IRQ_EN);
314 else
315 BF_CLR(LCDIF_CTRL1, CUR_FRAME_DONE_IRQ_EN);
316 BF_CLR(LCDIF_CTRL1, CUR_FRAME_DONE_IRQ);
317}
318
319void imx233_lcdif_set_frame_done_cb(lcdif_irq_cb_t cb)
320{
321 g_cur_frame_cb = cb;
322}
323
324void imx233_lcdif_enable_vsync_edge_irq(bool en)
325{
326 if(en)
327 BF_SET(LCDIF_CTRL1, VSYNC_EDGE_IRQ_EN);
328 else
329 BF_CLR(LCDIF_CTRL1, VSYNC_EDGE_IRQ_EN);
330 BF_CLR(LCDIF_CTRL1, VSYNC_EDGE_IRQ);
331}
332
333void imx233_lcdif_set_vsync_edge_cb(lcdif_irq_cb_t cb)
334{
335 g_vsync_edge_cb = cb;
336}
337#endif
338
339#if IMX233_SUBTARGET >= 3780
340void imx233_lcdif_set_lcd_databus_width(unsigned width)
341{
342 switch(width)
343 {
344 case 8: BF_WR_V(LCDIF_CTRL, LCD_DATABUS_WIDTH, 8_BIT); break;
345 case 16: BF_WR_V(LCDIF_CTRL, LCD_DATABUS_WIDTH, 16_BIT); break;
346 case 18: BF_WR_V(LCDIF_CTRL, LCD_DATABUS_WIDTH, 18_BIT); break;
347 case 24: BF_WR_V(LCDIF_CTRL, LCD_DATABUS_WIDTH, 24_BIT); break;
348 default:
349 panicf("this chip cannot handle a lcd bus width of %d", width);
350 break;
351 }
352}
353
354void imx233_lcdif_enable_underflow_recover(bool enable)
355{
356 if(enable)
357 BF_SET(LCDIF_CTRL1, RECOVER_ON_UNDERFLOW);
358 else
359 BF_CLR(LCDIF_CTRL1, RECOVER_ON_UNDERFLOW);
360}
361
362void imx233_lcdif_enable_bus_master(bool enable)
363{
364 if(enable)
365 BF_SET(LCDIF_CTRL, LCDIF_MASTER);
366 else
367 BF_CLR(LCDIF_CTRL, LCDIF_MASTER);
147} 368}
369#endif \ No newline at end of file
diff --git a/firmware/target/arm/imx233/lcdif-imx233.h b/firmware/target/arm/imx233/lcdif-imx233.h
index 1aee72bce4..dabc1f4c71 100644
--- a/firmware/target/arm/imx233/lcdif-imx233.h
+++ b/firmware/target/arm/imx233/lcdif-imx233.h
@@ -28,19 +28,49 @@
28 28
29#include "regs/regs-lcdif.h" 29#include "regs/regs-lcdif.h"
30 30
31void imx233_lcdif_enable_underflow_recover(bool enable); 31typedef void (*lcdif_irq_cb_t)(void);
32void imx233_lcdif_enable_bus_master(bool enable); 32
33void imx233_lcdif_enable(bool enable); 33void imx233_lcdif_enable(bool enable);
34void imx233_lcdif_reset(void);// reset lcdif block 34void imx233_lcdif_init(void);// reset lcdif block
35void imx233_lcdif_reset_lcd(bool enable);// set/clr reset line
35void imx233_lcdif_set_timings(unsigned data_setup, unsigned data_hold, 36void imx233_lcdif_set_timings(unsigned data_setup, unsigned data_hold,
36 unsigned cmd_setup, unsigned cmd_hold); 37 unsigned cmd_setup, unsigned cmd_hold);
37void imx233_lcdif_set_lcd_databus_width(unsigned width);
38void imx233_lcdif_set_word_length(unsigned word_length); 38void imx233_lcdif_set_word_length(unsigned word_length);
39void imx233_lcdif_set_byte_packing_format(unsigned byte_packing);
40void imx233_lcdif_set_data_format(bool data_fmt_16, bool data_fmt_18, bool data_fmt_24);
41unsigned imx233_lcdif_enable_irqs(unsigned irq_bm); /* return old mask */
42void imx233_lcdif_wait_ready(void); 39void imx233_lcdif_wait_ready(void);
43void imx233_lcdif_pio_send(bool data_mode, unsigned len, uint32_t *buf); 40void imx233_lcdif_set_data_swizzle(unsigned swizzle);
41/* This function assumes the data is packed in 8/16-bit mode and unpacked in
42 * 18-bit mode.
43 * WARNING: doesn't support 24-bit mode
44 * WARNING: count must be lower than or equal to 0xffff
45 * Note that this function might affect the byte packing format and bus master.
46 * Note that count is number of pixels, NOT the number of bytes ! */
47void imx233_lcdif_pio_send(bool data_mode, unsigned count, void *buf);
44void imx233_lcdif_dma_send(void *buf, unsigned width, unsigned height); 48void imx233_lcdif_dma_send(void *buf, unsigned width, unsigned height);
49void imx233_lcdif_setup_system_pins(unsigned bus_width);
50void imx233_lcdif_setup_dotclk_pins(unsigned bus_width, bool have_enable);
51
52#if IMX233_SUBTARGET >= 3700
53void imx233_lcdif_set_byte_packing_format(unsigned byte_packing);
54/* low-level function */
55void imx233_lcdif_setup_dotclk(unsigned v_pulse_width, unsigned v_period,
56 unsigned v_wait_cnt, unsigned v_active, unsigned h_pulse_width,
57 unsigned h_period, unsigned h_wait_cnt, unsigned h_active, bool enable_present);
58/* high-level function */
59void imx233_lcdif_setup_dotclk_ex(unsigned v_pulse_width, unsigned v_back_porch,
60 unsigned v_front_porch, unsigned h_pulse_width, unsigned h_back_porch,
61 unsigned h_front_porch, unsigned width, unsigned height, unsigned clk_per_pix,
62 bool enable_present);
63void imx233_lcdif_enable_frame_done_irq(bool en);
64void imx233_lcdif_set_frame_done_cb(lcdif_irq_cb_t cb);
65void imx233_lcdif_enable_vsync_edge_irq(bool en);
66void imx233_lcdif_set_vsync_edge_cb(lcdif_irq_cb_t cb);
67void imx233_lcdif_enable_sync_signals(bool en);
68#endif
69
70#if IMX233_SUBTARGET >= 3780
71void imx233_lcdif_enable_underflow_recover(bool enable);
72void imx233_lcdif_enable_bus_master(bool enable);
73void imx233_lcdif_set_lcd_databus_width(unsigned width);
74#endif
45 75
46#endif /* __LCDIF_IMX233_H__ */ 76#endif /* __LCDIF_IMX233_H__ */
diff --git a/firmware/target/arm/imx233/pins/pins-imx233.h b/firmware/target/arm/imx233/pins/pins-imx233.h
index 12231a60d8..7a97ea7f11 100644
--- a/firmware/target/arm/imx233/pins/pins-imx233.h
+++ b/firmware/target/arm/imx233/pins/pins-imx233.h
@@ -79,5 +79,9 @@
79#define VPIN_LCD_RS VPIN_PACK(1, 19, MAIN) 79#define VPIN_LCD_RS VPIN_PACK(1, 19, MAIN)
80#define VPIN_LCD_WR VPIN_PACK(1, 20, MAIN) 80#define VPIN_LCD_WR VPIN_PACK(1, 20, MAIN)
81#define VPIN_LCD_CS VPIN_PACK(1, 21, MAIN) 81#define VPIN_LCD_CS VPIN_PACK(1, 21, MAIN)
82#define VPIN_LCD_DOTCLK VPIN_PACK(1, 22, MAIN)
83#define VPIN_LCD_ENABLE VPIN_PACK(1, 23, MAIN)
84#define VPIN_LCD_HSYNC VPIN_PACK(1, 24, MAIN)
85#define VPIN_LCD_VSYNC VPIN_PACK(1, 25, MAIN)
82 86
83#endif /* __PINS_IMX233__ */ 87#endif /* __PINS_IMX233__ */
diff --git a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c
index 3fd63de623..79a4151682 100644
--- a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c
+++ b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c
@@ -38,7 +38,6 @@
38#ifdef HAVE_LCD_ENABLE 38#ifdef HAVE_LCD_ENABLE
39static bool lcd_on; 39static bool lcd_on;
40#endif 40#endif
41static unsigned lcd_yuv_options = 0;
42static int lcd_dcp_channel = -1; 41static int lcd_dcp_channel = -1;
43#ifdef HAVE_LCD_INVERT 42#ifdef HAVE_LCD_INVERT
44static int lcd_reg_0x61_val = 1; /* used to invert display */ 43static int lcd_reg_0x61_val = 1; /* used to invert display */
@@ -55,9 +54,9 @@ static enum lcd_kind_t
55 54
56static void setup_parameters(void) 55static void setup_parameters(void)
57{ 56{
58 imx233_lcdif_reset(); 57 imx233_lcdif_init();
59 imx233_lcdif_set_lcd_databus_width(BV_LCDIF_CTRL_LCD_DATABUS_WIDTH__18_BIT); 58 imx233_lcdif_set_lcd_databus_width(18);
60 imx233_lcdif_set_word_length(BV_LCDIF_CTRL_WORD_LENGTH__18_BIT); 59 imx233_lcdif_set_word_length(18);
61 imx233_lcdif_set_timings(1, 2, 2, 2); 60 imx233_lcdif_set_timings(1, 2, 2, 2);
62 imx233_lcdif_enable_underflow_recover(true); 61 imx233_lcdif_enable_underflow_recover(true);
63} 62}
@@ -126,7 +125,7 @@ static void setup_lcd_pins_i80(bool i80)
126 else 125 else
127 { 126 {
128 HW_PINCTRL_DOUTn_SET(1) = (1 << 19) | (1 << 20) | (1 << 21) | (1 << 23); 127 HW_PINCTRL_DOUTn_SET(1) = (1 << 19) | (1 << 20) | (1 << 21) | (1 << 23);
129 128
130 imx233_pinctrl_set_drive(1, 19, PINCTRL_DRIVE_4mA); /* lcd_rs */ 129 imx233_pinctrl_set_drive(1, 19, PINCTRL_DRIVE_4mA); /* lcd_rs */
131 imx233_pinctrl_set_drive(1, 20, PINCTRL_DRIVE_4mA); /* lcd_wr */ 130 imx233_pinctrl_set_drive(1, 20, PINCTRL_DRIVE_4mA); /* lcd_wr */
132 imx233_pinctrl_set_drive(1, 21, PINCTRL_DRIVE_4mA); /* lcd_cs */ 131 imx233_pinctrl_set_drive(1, 21, PINCTRL_DRIVE_4mA); /* lcd_cs */
@@ -219,13 +218,13 @@ static void lcd_write_reg(uint32_t reg, uint32_t data)
219 uint32_t old_reg = reg; 218 uint32_t old_reg = reg;
220 imx233_lcdif_wait_ready(); 219 imx233_lcdif_wait_ready();
221 /* get back to 18-bit word length */ 220 /* get back to 18-bit word length */
222 imx233_lcdif_set_word_length(BV_LCDIF_CTRL_WORD_LENGTH__18_BIT); 221 imx233_lcdif_set_word_length(18);
223 reg = encode_16_to_18(reg); 222 reg = encode_16_to_18(reg);
224 data = encode_16_to_18(data); 223 data = encode_16_to_18(data);
225 224
226 imx233_lcdif_pio_send(false, 2, &reg); 225 imx233_lcdif_pio_send(false, 1, &reg);
227 if(old_reg != 0x22) 226 if(old_reg != 0x22)
228 imx233_lcdif_pio_send(true, 2, &data); 227 imx233_lcdif_pio_send(true, 1, &data);
229} 228}
230 229
231static uint32_t lcd_read_reg(uint32_t reg) 230static uint32_t lcd_read_reg(uint32_t reg)
@@ -399,11 +398,11 @@ void lcd_init_device(void)
399 break; 398 break;
400 } 399 }
401 // reset device 400 // reset device
402 BF_SET(LCDIF_CTRL1, RESET); 401 imx233_lcdif_reset_lcd(true);
403 mdelay(50); 402 mdelay(50);
404 BF_CLR(LCDIF_CTRL1, RESET); 403 imx233_lcdif_reset_lcd(false);
405 mdelay(10); 404 mdelay(10);
406 BF_SET(LCDIF_CTRL1, RESET); 405 imx233_lcdif_reset_lcd(true);
407 406
408 switch(lcd_kind) 407 switch(lcd_kind)
409 { 408 {
@@ -579,9 +578,8 @@ void lcd_update_rect(int x, int y, int w, int h)
579 lcd_write_reg(0x21, y); 578 lcd_write_reg(0x21, y);
580 lcd_write_reg(0x22, 0); 579 lcd_write_reg(0x22, 0);
581 imx233_lcdif_wait_ready(); 580 imx233_lcdif_wait_ready();
582 imx233_lcdif_set_word_length(BV_LCDIF_CTRL_WORD_LENGTH__16_BIT); 581 imx233_lcdif_set_word_length(16);
583 imx233_lcdif_set_byte_packing_format(0xf); /* two pixels per 32-bit word */ 582 imx233_lcdif_set_byte_packing_format(0xf); /* two pixels per 32-bit word */
584 imx233_lcdif_set_data_format(false, false, false); /* RGB565, don't care, don't care */
585 /* there are two cases here: 583 /* there are two cases here:
586 * - either width = LCD_WIDTH and we can directly memcopy a part of lcd_framebuffer to FRAME 584 * - either width = LCD_WIDTH and we can directly memcopy a part of lcd_framebuffer to FRAME
587 * and send it 585 * and send it
@@ -626,198 +624,6 @@ void lcd_update_rect(int x, int y, int w, int h)
626 imx233_lcdif_dma_send((void *)FRAME_PHYS_ADDR, w, h); 624 imx233_lcdif_dma_send((void *)FRAME_PHYS_ADDR, w, h);
627} 625}
628 626
629void lcd_yuv_set_options(unsigned options)
630{
631 lcd_yuv_options = options;
632}
633
634#define YFAC (74)
635#define RVFAC (101)
636#define GUFAC (-24)
637#define GVFAC (-51)
638#define BUFAC (128)
639
640static inline int clamp(int val, int min, int max)
641{
642 if (val < min)
643 val = min;
644 else if (val > max)
645 val = max;
646 return val;
647}
648
649void lcd_blit_yuv(unsigned char * const src[3],
650 int src_x, int src_y, int stride,
651 int x, int y, int width, int height)
652{
653 const unsigned char *ysrc, *usrc, *vsrc;
654 int linecounter;
655 fb_data *dst, *row_end;
656 long z;
657
658 /* width and height must be >= 2 and an even number */
659 width &= ~1;
660 linecounter = height >> 1;
661
662 #if LCD_WIDTH >= LCD_HEIGHT
663 dst = FBADDR(x,y);
664 row_end = dst + width;
665 #else
666 dst = FBADDR(LCD_WIDTH - y - 1,x);
667 row_end = dst + LCD_WIDTH * width;
668 #endif
669
670 z = stride * src_y;
671 ysrc = src[0] + z + src_x;
672 usrc = src[1] + (z >> 2) + (src_x >> 1);
673 vsrc = src[2] + (usrc - src[1]);
674
675 /* stride => amount to jump from end of last row to start of next */
676 stride -= width;
677
678 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
679
680 do
681 {
682 do
683 {
684 int y, cb, cr, rv, guv, bu, r, g, b;
685
686 y = YFAC*(*ysrc++ - 16);
687 cb = *usrc++ - 128;
688 cr = *vsrc++ - 128;
689
690 rv = RVFAC*cr;
691 guv = GUFAC*cb + GVFAC*cr;
692 bu = BUFAC*cb;
693
694 r = y + rv;
695 g = y + guv;
696 b = y + bu;
697
698 if ((unsigned)(r | g | b) > 64*256-1)
699 {
700 r = clamp(r, 0, 64*256-1);
701 g = clamp(g, 0, 64*256-1);
702 b = clamp(b, 0, 64*256-1);
703 }
704
705 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
706
707 #if LCD_WIDTH >= LCD_HEIGHT
708 dst++;
709 #else
710 dst += LCD_WIDTH;
711 #endif
712
713 y = YFAC*(*ysrc++ - 16);
714 r = y + rv;
715 g = y + guv;
716 b = y + bu;
717
718 if ((unsigned)(r | g | b) > 64*256-1)
719 {
720 r = clamp(r, 0, 64*256-1);
721 g = clamp(g, 0, 64*256-1);
722 b = clamp(b, 0, 64*256-1);
723 }
724
725 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
726
727 #if LCD_WIDTH >= LCD_HEIGHT
728 dst++;
729 #else
730 dst += LCD_WIDTH;
731 #endif
732 }
733 while (dst < row_end);
734
735 ysrc += stride;
736 usrc -= width >> 1;
737 vsrc -= width >> 1;
738
739 #if LCD_WIDTH >= LCD_HEIGHT
740 row_end += LCD_WIDTH;
741 dst += LCD_WIDTH - width;
742 #else
743 row_end -= 1;
744 dst -= LCD_WIDTH*width + 1;
745 #endif
746
747 do
748 {
749 int y, cb, cr, rv, guv, bu, r, g, b;
750
751 y = YFAC*(*ysrc++ - 16);
752 cb = *usrc++ - 128;
753 cr = *vsrc++ - 128;
754
755 rv = RVFAC*cr;
756 guv = GUFAC*cb + GVFAC*cr;
757 bu = BUFAC*cb;
758
759 r = y + rv;
760 g = y + guv;
761 b = y + bu;
762
763 if ((unsigned)(r | g | b) > 64*256-1)
764 {
765 r = clamp(r, 0, 64*256-1);
766 g = clamp(g, 0, 64*256-1);
767 b = clamp(b, 0, 64*256-1);
768 }
769
770 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
771
772 #if LCD_WIDTH >= LCD_HEIGHT
773 dst++;
774 #else
775 dst += LCD_WIDTH;
776 #endif
777
778 y = YFAC*(*ysrc++ - 16);
779 r = y + rv;
780 g = y + guv;
781 b = y + bu;
782
783 if ((unsigned)(r | g | b) > 64*256-1)
784 {
785 r = clamp(r, 0, 64*256-1);
786 g = clamp(g, 0, 64*256-1);
787 b = clamp(b, 0, 64*256-1);
788 }
789
790 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
791
792 #if LCD_WIDTH >= LCD_HEIGHT
793 dst++;
794 #else
795 dst += LCD_WIDTH;
796 #endif
797 }
798 while (dst < row_end);
799
800 ysrc += stride;
801 usrc += stride >> 1;
802 vsrc += stride >> 1;
803
804 #if LCD_WIDTH >= LCD_HEIGHT
805 row_end += LCD_WIDTH;
806 dst += LCD_WIDTH - width;
807 #else
808 row_end -= 1;
809 dst -= LCD_WIDTH*width + 1;
810 #endif
811 }
812 while (--linecounter > 0);
813
814 #if LCD_WIDTH >= LCD_HEIGHT
815 lcd_update_rect(x, y, width, height);
816 #else
817 lcd_update_rect(LCD_WIDTH - y - height, x, height, width);
818 #endif
819}
820
821#ifndef BOOTLOADER 627#ifndef BOOTLOADER
822bool lcd_debug_screen(void) 628bool lcd_debug_screen(void)
823{ 629{