summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c')
-rw-r--r--firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c311
1 files changed, 311 insertions, 0 deletions
diff --git a/firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c b/firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c
new file mode 100644
index 0000000000..5a4542ca67
--- /dev/null
+++ b/firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c
@@ -0,0 +1,311 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2013 by Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <sys/types.h> /* off_t */
22#include <string.h>
23#include "cpu.h"
24#include "system.h"
25#include "backlight-target.h"
26#include "lcd.h"
27#include "lcdif-imx233.h"
28#include "clkctrl-imx233.h"
29#include "pinctrl-imx233.h"
30#include "logf.h"
31
32#ifdef HAVE_LCD_ENABLE
33static bool lcd_on;
34#endif
35static int lcd_model;
36
37static inline uint32_t encode_16_to_18(uint32_t a)
38{
39 return ((a & 0xff) << 1) | (((a >> 8) & 0xff) << 10);
40}
41
42static void lcd_write_reg(uint32_t reg, uint32_t data)
43{
44 uint32_t old_reg = reg;
45 /* get back to 18-bit word length */
46 imx233_lcdif_set_word_length(18);
47 reg = encode_16_to_18(reg);
48 data = encode_16_to_18(data);
49
50 imx233_lcdif_pio_send(false, 1, &reg);
51 if(old_reg != 0x22)
52 imx233_lcdif_pio_send(true, 1, &data);
53}
54
55static void lcd_init_seq(void)
56{
57 if(lcd_model == 0)
58 {
59 lcd_write_reg(0xe3, 0x3008);
60 lcd_write_reg(0xe7, 0x12);
61 lcd_write_reg(0xef, 0x1231);
62 lcd_write_reg(0x01, 0x100);
63 lcd_write_reg(0x02, 0x700);
64 lcd_write_reg(0x03, 0x1028);
65 lcd_write_reg(0x04, 0);
66 lcd_write_reg(0x08, 0x207);
67 lcd_write_reg(0x09, 0);
68 lcd_write_reg(0x0a, 0);
69 lcd_write_reg(0x0c, 0);
70 lcd_write_reg(0x0d, 0);
71 lcd_write_reg(0x0f, 0);
72 lcd_write_reg(0x10, 0);
73 lcd_write_reg(0x11, 7);
74 lcd_write_reg(0x12, 0);
75 lcd_write_reg(0x13, 0);
76 mdelay(200);
77 lcd_write_reg(0x10, 0x1490);
78 lcd_write_reg(0x11, 0x227);
79 mdelay(50);
80 lcd_write_reg(0x12, 0x9c);
81 mdelay(50);
82 lcd_write_reg(0x13, 0xc00);
83 lcd_write_reg(0x29, 5);
84 lcd_write_reg(0x2b, 0xc);
85 lcd_write_reg(0x20, 0xef);
86 lcd_write_reg(0x21, 0);
87 lcd_write_reg(0x30, 6);
88 lcd_write_reg(0x31, 0x703);
89 lcd_write_reg(0x32, 0x206);
90 lcd_write_reg(0x35, 4);
91 lcd_write_reg(0x36, 0x1a05);
92 lcd_write_reg(0x37, 0x600);
93 lcd_write_reg(0x38, 0x307);
94 lcd_write_reg(0x39, 0x707);
95 lcd_write_reg(0x3c, 0x400);
96 lcd_write_reg(0x3d, 0x50f);
97 lcd_write_reg(0x50, 0);
98 lcd_write_reg(0x51, 0xef);
99 lcd_write_reg(0x52, 0);
100 lcd_write_reg(0x53, 0x13f);
101 lcd_write_reg(0x60, 0xa700);
102 lcd_write_reg(0x61, 1);
103 lcd_write_reg(0x6a, 0);
104 lcd_write_reg(0x80, 0);
105 lcd_write_reg(0x81, 0);
106 lcd_write_reg(0x82, 0);
107 lcd_write_reg(0x83, 0);
108 lcd_write_reg(0x84, 0);
109 lcd_write_reg(0x85, 0);
110 lcd_write_reg(0x90, 0x10);
111 lcd_write_reg(0x92, 0x600);
112 lcd_write_reg(0x07, 0x133);
113 }
114 else
115 {
116 lcd_write_reg(0x01, 0x100);
117 lcd_write_reg(0x02, 0x700);
118 lcd_write_reg(0x03, 0x1028);
119 lcd_write_reg(0x04, 0);
120 lcd_write_reg(0x08, 0x207);
121 lcd_write_reg(0x09, 0);
122 lcd_write_reg(0x0a, 0);
123 lcd_write_reg(0x0c, 0);
124 lcd_write_reg(0x0d, 0);
125 lcd_write_reg(0x0f, 0);
126 lcd_write_reg(0x10, 0);
127 lcd_write_reg(0x11, 7);
128 lcd_write_reg(0x12, 0);
129 lcd_write_reg(0x13, 0);
130 mdelay(200);
131 lcd_write_reg(0x10, 0x1290);
132 lcd_write_reg(0x11, 0x227);
133 mdelay(50);
134 lcd_write_reg(0x12, 0x9c);
135 mdelay(50);
136 lcd_write_reg(0x13, 0x1f00);
137 lcd_write_reg(0x29, 0x30);
138 lcd_write_reg(0x2b, 0xd);
139 lcd_write_reg(0x20, 0xef);
140 lcd_write_reg(0x21, 0);
141 lcd_write_reg(0x30, 0x404);
142 lcd_write_reg(0x31, 0x404);
143 lcd_write_reg(0x32, 0x404);
144 lcd_write_reg(0x37, 0x303);
145 lcd_write_reg(0x38, 0x303);
146 lcd_write_reg(0x39, 0x303);
147 lcd_write_reg(0x35, 0x103);
148 lcd_write_reg(0x3c, 0x301);
149 lcd_write_reg(0x36, 0x1e00);
150 lcd_write_reg(0x3d, 0xf);
151 lcd_write_reg(0x50, 0);
152 lcd_write_reg(0x51, 0xef);
153 lcd_write_reg(0x52, 0);
154 lcd_write_reg(0x53, 0x13f);
155 lcd_write_reg(0x60, 0xa700);
156 lcd_write_reg(0x61, 0);
157 lcd_write_reg(0x6a, 0);
158 lcd_write_reg(0x80, 0);
159 lcd_write_reg(0x81, 0);
160 lcd_write_reg(0x82, 0);
161 lcd_write_reg(0x83, 0);
162 lcd_write_reg(0x84, 0);
163 lcd_write_reg(0x85, 0);
164 lcd_write_reg(0x2b, 0xd);
165 mdelay(50);
166 lcd_write_reg(0x90, 0x17);
167 lcd_write_reg(0x92, 0);
168 lcd_write_reg(0x93, 3);
169 lcd_write_reg(0x95, 0x110);
170 lcd_write_reg(0x97, 0);
171 lcd_write_reg(0x98, 0);
172 lcd_write_reg(0x07, 0x133);
173 }
174}
175
176void lcd_init_device(void)
177{
178 /* clock at 24MHZ */
179 imx233_clkctrl_enable(CLK_PIX, false);
180 imx233_clkctrl_set_div(CLK_PIX, 1);
181 imx233_clkctrl_set_bypass(CLK_PIX, true); /* use XTAL */
182 imx233_clkctrl_enable(CLK_PIX, true);
183 imx233_lcdif_init();
184 imx233_lcdif_set_lcd_databus_width(18);
185 imx233_lcdif_enable_underflow_recover(true);
186 imx233_lcdif_setup_system_pins(18);
187 imx233_lcdif_set_timings(2, 2, 2, 2);
188
189 imx233_pinctrl_acquire(2, 8, "lcd_model");
190 imx233_pinctrl_set_function(2, 8, PINCTRL_FUNCTION_GPIO);
191 imx233_pinctrl_enable_gpio(2, 8, false);
192 lcd_model = imx233_pinctrl_get_gpio(2, 8);
193
194 // reset device
195 imx233_lcdif_reset_lcd(true);
196 mdelay(50);
197 imx233_lcdif_reset_lcd(false);
198 mdelay(10);
199 imx233_lcdif_reset_lcd(true);
200
201 lcd_init_seq();
202#ifdef HAVE_LCD_ENABLE
203 lcd_on = true;
204#endif
205}
206
207#ifdef HAVE_LCD_ENABLE
208bool lcd_active(void)
209{
210 return lcd_on;
211}
212
213static void lcd_enable_seq(bool enable)
214{
215 if(!enable)
216 {
217 }
218 else
219 {
220 }
221}
222
223void lcd_enable(bool enable)
224{
225 if(lcd_on == enable)
226 return;
227
228 lcd_on = enable;
229
230 lcd_enable_seq(enable);
231 if(enable)
232 send_event(LCD_EVENT_ACTIVATION, NULL);
233}
234#endif
235
236void lcd_update(void)
237{
238 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
239}
240
241/* NOTE the LCD is rotated: it's a 240x320 panel with (0,0) being the bottom-left
242 * corner when the player is hold in landscape mode. This means x and y axis and
243 * exchanged and the y axis is reversed. */
244
245void lcd_update_rect(int x, int y, int w, int h)
246{
247#ifdef HAVE_LCD_ENABLE
248 if(!lcd_on)
249 return;
250#endif
251 /* make sure the rectangle is included in the screen */
252 x = MIN(x, LCD_WIDTH);
253 y = MIN(y, LCD_HEIGHT);
254 w = MIN(w, LCD_WIDTH - x);
255 h = MIN(h, LCD_HEIGHT - y);
256
257 imx233_lcdif_wait_ready();
258 lcd_write_reg(0x50, LCD_HEIGHT - y - h);
259 lcd_write_reg(0x51, LCD_HEIGHT - y - 1);
260 lcd_write_reg(0x52, x);
261 lcd_write_reg(0x53, x + w - 1);
262 lcd_write_reg(0x20, LCD_HEIGHT - y - 1);
263 lcd_write_reg(0x21, x);
264 lcd_write_reg(0x22, 0);
265 imx233_lcdif_wait_ready();
266 imx233_lcdif_set_word_length(16);
267 imx233_lcdif_set_byte_packing_format(0xf); /* two pixels per 32-bit word */
268
269 /* there are two cases here:
270 * - either width = LCD_WIDTH and we can directly memcopy a part of lcd_framebuffer to FRAME
271 * and send it
272 * - either width != LCD_WIDTH and we have to build a contiguous copy of the rectangular area
273 * into FRAME before sending it (which is slower and doesn't use the hardware)
274 * In all cases, FRAME just acts as a temporary buffer.
275 * NOTE It's more interesting to do a copy to FRAME in all cases since in system mode
276 * the clock runs at 24MHz which provides barely 10MB/s bandwidth compared to >100MB/s
277 * for memcopy operations
278 */
279 if(w == LCD_WIDTH)
280 {
281 memcpy((void *)FRAME, FBADDR(x,y), w * h * sizeof(fb_data));
282 }
283 else
284 {
285 for(int i = 0; i < h; i++)
286 memcpy((fb_data *)FRAME + i * w, FBADDR(x,y + i), w * sizeof(fb_data));
287 }
288 /* WARNING The LCDIF has a limitation on the vertical count ! In 16-bit packed mode
289 * (which we used, ie 16-bit per pixel, 2 pixels per 32-bit words), the v_count
290 * field must be a multiple of 2. Furthermore, it seems the lcd controller doesn't
291 * really like when both w and h are even, probably because the writes to the GRAM
292 * are done on several words and the controller requires dummy writes.
293 * The workaround is to always make sure that we send a number of pixels which is
294 * a multiple of 4 so that both the lcdif and the controller are happy. If any
295 * of w or h is odd, we will send a copy of the first pixels as dummy writes. We will
296 * send at most 3 bytes. We then send (w * h + 3) / 4 x 4 bytes.
297 */
298 if(w % 2 == 1 || h % 2 == 1)
299 {
300 /* copy three pixel after the last one */
301 for(int i = 0; i < 3; i++)
302 *((fb_data *)FRAME + w * h + i) = *((fb_data *)FRAME + i);
303 /* WARNING we need to update w and h to reflect the pixel count BUT it
304 * has no relation to w * h (it can even be 2 * prime). Hopefully, w <= 240 and
305 * h <= 320 so w * h <= 76800 and (w * h + 3) / 4 <= 38400 which fits into
306 * a 16-bit integer (horizontal count). */
307 h = (w * h + 3) / 4;
308 w = 4;
309 }
310 imx233_lcdif_dma_send((void *)FRAME_PHYS_ADDR, w, h);
311}