summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/lcdif-imx233.c
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 /firmware/target/arm/imx233/lcdif-imx233.c
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
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