summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/lcdif-imx233.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx233/lcdif-imx233.c')
-rw-r--r--firmware/target/arm/imx233/lcdif-imx233.c366
1 files changed, 294 insertions, 72 deletions
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