summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-06-17 00:06:24 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-06-17 00:29:25 +0200
commit069a0269a922ad466d35611d128dda377ef305c1 (patch)
tree2873857099d2f7f5ee2bf16c73b245fa821c8597
parent52426d08918eadfba178f74e1bd5d1663f9c73e0 (diff)
downloadrockbox-069a0269a922ad466d35611d128dda377ef305c1.tar.gz
rockbox-069a0269a922ad466d35611d128dda377ef305c1.zip
imx233: fix/improve lcdif for stmp3600 and stmp4700, fix drivers
Factorise pin setup, rewrite PIO code, add support for lcdif irq, handle all the various differences between the stmps, drop yuv blitting code since it already exists in the common lcd drivers. Change-Id: Ifc40aed9b3b12f16611ce960602e46a5bc87ae53
-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{