diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2013-10-22 00:30:43 +0200 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2013-10-22 00:34:45 +0200 |
commit | a0728672bf07f626049f8dc0007772794ae95ee1 (patch) | |
tree | bb8ca610c9d0c8fb441a99ccf33102964cafd003 /firmware/target/arm/imx233/creative-zen/lcd-zen.c | |
parent | d3bc64833c76adca4d6300e5b5880ee8ea63de02 (diff) | |
download | rockbox-a0728672bf07f626049f8dc0007772794ae95ee1.tar.gz rockbox-a0728672bf07f626049f8dc0007772794ae95ee1.zip |
Initial commit for the Creative ZEN and ZEN X-Fi
Change-Id: Ibd7b1b0b957ef11c200cb63eff7da53f11774748
Diffstat (limited to 'firmware/target/arm/imx233/creative-zen/lcd-zen.c')
-rw-r--r-- | firmware/target/arm/imx233/creative-zen/lcd-zen.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/firmware/target/arm/imx233/creative-zen/lcd-zen.c b/firmware/target/arm/imx233/creative-zen/lcd-zen.c new file mode 100644 index 0000000000..8390d192c8 --- /dev/null +++ b/firmware/target/arm/imx233/creative-zen/lcd-zen.c | |||
@@ -0,0 +1,347 @@ | |||
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 "dma-imx233.h" | ||
31 | #include "regs/regs-uartdbg.h" | ||
32 | #include "logf.h" | ||
33 | #ifndef BOOTLOADER | ||
34 | #include "button.h" | ||
35 | #include "font.h" | ||
36 | #include "action.h" | ||
37 | #endif | ||
38 | |||
39 | #ifdef HAVE_LCD_ENABLE | ||
40 | static bool lcd_on; | ||
41 | #endif | ||
42 | |||
43 | /** | ||
44 | * DMA | ||
45 | */ | ||
46 | |||
47 | /* Used for DMA */ | ||
48 | struct lcdif_dma_command_t | ||
49 | { | ||
50 | struct apb_dma_command_t dma; | ||
51 | uint32_t pad; | ||
52 | } __attribute__((packed)) CACHEALIGN_ATTR; | ||
53 | |||
54 | __ENSURE_STRUCT_CACHE_FRIENDLY(struct lcdif_dma_command_t) | ||
55 | |||
56 | #define NR_CMDS ((IMX233_FRAMEBUFFER_SIZE + IMX233_MAX_SINGLE_DMA_XFER_SIZE - 1) / IMX233_MAX_SINGLE_DMA_XFER_SIZE) | ||
57 | |||
58 | struct lcdif_dma_command_t lcdif_dma[NR_CMDS]; | ||
59 | |||
60 | /** | ||
61 | * Utils | ||
62 | */ | ||
63 | static int g_wait_nr_frame = 0; | ||
64 | static struct semaphore g_wait_sema; | ||
65 | |||
66 | static void wait_frames_cb(void) | ||
67 | { | ||
68 | if(--g_wait_nr_frame == 0) | ||
69 | semaphore_release(&g_wait_sema); | ||
70 | } | ||
71 | |||
72 | static void wait_nr_frames(int nr) | ||
73 | { | ||
74 | g_wait_nr_frame = 1 + nr; // +1 because we want entire frames | ||
75 | imx233_lcdif_set_vsync_edge_cb(wait_frames_cb); | ||
76 | imx233_lcdif_enable_vsync_edge_irq(true); | ||
77 | semaphore_wait(&g_wait_sema, TIMEOUT_BLOCK); | ||
78 | imx233_lcdif_enable_vsync_edge_irq(false); | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * SPI | ||
83 | */ | ||
84 | |||
85 | #define SPI_CS(v) imx233_pinctrl_set_gpio(1, 11, v) | ||
86 | #define SPI_SCL(v) imx233_pinctrl_set_gpio(1, 10, v) | ||
87 | #define SPI_SDO(v) imx233_pinctrl_set_gpio(1, 9, v) | ||
88 | |||
89 | #define DEV_ID 0x74 | ||
90 | #define RS 0x2 | ||
91 | #define RW 0x1 | ||
92 | |||
93 | static void spi_init(void) | ||
94 | { | ||
95 | imx233_pinctrl_acquire(1, 9, "lcd_spi_sdo"); | ||
96 | imx233_pinctrl_acquire(1, 10, "lcd_spi_scl"); | ||
97 | imx233_pinctrl_acquire(1, 11, "lcd_spi_cs"); | ||
98 | imx233_pinctrl_set_function(1, 9, PINCTRL_FUNCTION_GPIO); | ||
99 | imx233_pinctrl_set_function(1, 10, PINCTRL_FUNCTION_GPIO); | ||
100 | imx233_pinctrl_set_function(1, 11, PINCTRL_FUNCTION_GPIO); | ||
101 | imx233_pinctrl_set_gpio(1, 9, true); | ||
102 | imx233_pinctrl_set_gpio(1, 10, true); | ||
103 | imx233_pinctrl_set_gpio(1, 11, true); | ||
104 | imx233_pinctrl_enable_gpio(1, 9, true); | ||
105 | imx233_pinctrl_enable_gpio(1, 10, true); | ||
106 | imx233_pinctrl_enable_gpio(1, 11, true); | ||
107 | } | ||
108 | |||
109 | static void spi_delay(void) | ||
110 | { | ||
111 | udelay(1); | ||
112 | } | ||
113 | |||
114 | static void spi_begin(void) | ||
115 | { | ||
116 | SPI_CS(false); | ||
117 | spi_delay(); | ||
118 | } | ||
119 | |||
120 | static void spi_write(unsigned char b) | ||
121 | { | ||
122 | for(int i = 7; i >= 0; i--) | ||
123 | { | ||
124 | SPI_SCL(false); | ||
125 | spi_delay(); | ||
126 | SPI_SDO((b >> i) & 1); | ||
127 | spi_delay(); | ||
128 | SPI_SCL(true); | ||
129 | spi_delay(); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void spi_end(void) | ||
134 | { | ||
135 | SPI_CS(true); | ||
136 | spi_delay(); | ||
137 | } | ||
138 | |||
139 | static void spi_write_reg(uint8_t reg, uint16_t value) | ||
140 | { | ||
141 | spi_begin(); | ||
142 | spi_write(DEV_ID); | ||
143 | spi_write(0); | ||
144 | spi_write(reg); | ||
145 | spi_end(); | ||
146 | spi_begin(); | ||
147 | spi_write(DEV_ID | RS); | ||
148 | spi_write(value >> 8); | ||
149 | spi_write(value & 0xff); | ||
150 | spi_end(); | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * LCD control | ||
155 | */ | ||
156 | |||
157 | static void lcd_power(bool en) | ||
158 | { | ||
159 | imx233_pinctrl_set_gpio(1, 8, en); | ||
160 | mdelay(10); | ||
161 | } | ||
162 | |||
163 | static void lcd_power_seq(void) | ||
164 | { | ||
165 | spi_write_reg(0x7, 0); | ||
166 | mdelay(10); | ||
167 | spi_write_reg(0x12, 0x1618); | ||
168 | spi_write_reg(0x11, 0x2227); | ||
169 | spi_write_reg(0x13, 0x61d1); | ||
170 | spi_write_reg(0x10, 0x550c); | ||
171 | wait_nr_frames(5); | ||
172 | spi_write_reg(0x12, 0x0c58); | ||
173 | } | ||
174 | |||
175 | static void lcd_init_seq(void) | ||
176 | { | ||
177 | /* NOTE I don't understand why I have to use BGR, logic would say I should not */ | ||
178 | spi_write_reg(0x1, 0x2b1d);// inversion | ||
179 | spi_write_reg(0x2, 0x300); | ||
180 | /* NOTE by default stmp3700 has vsync/hsync active low and data launch | ||
181 | * at negative edge of dotclk, reflect this in the polarity settings */ | ||
182 | spi_write_reg(0x3, 0xd040);// polarity (OF uses 0xc040, seems incorrect) | ||
183 | spi_write_reg(0x8, 0); // vsync back porch (0=3H) | ||
184 | spi_write_reg(0x9, 0); // hsync back porhc (0=24clk) | ||
185 | spi_write_reg(0x76, 0x2213); | ||
186 | spi_write_reg(0xb, 0x33e1); | ||
187 | spi_write_reg(0xc, 0x23); | ||
188 | spi_write_reg(0x76, 0); | ||
189 | spi_write_reg(0xd, 7); | ||
190 | spi_write_reg(0xe, 0); | ||
191 | spi_write_reg(0x15, 0x803); | ||
192 | spi_write_reg(0x14, 0); | ||
193 | spi_write_reg(0x16, 0); | ||
194 | spi_write_reg(0x30, 0x706); | ||
195 | spi_write_reg(0x31, 0x406); | ||
196 | spi_write_reg(0x32, 0xc09); | ||
197 | spi_write_reg(0x33, 0x606); | ||
198 | spi_write_reg(0x34, 0x706); | ||
199 | spi_write_reg(0x35, 0x406); | ||
200 | spi_write_reg(0x36, 0xc06); | ||
201 | spi_write_reg(0x37, 0x601); | ||
202 | spi_write_reg(0x38, 0x504); | ||
203 | spi_write_reg(0x39, 0x504); | ||
204 | } | ||
205 | |||
206 | static void lcd_display_on_seq(void) | ||
207 | { | ||
208 | spi_write_reg(0x7, 1); | ||
209 | wait_nr_frames(1); | ||
210 | spi_write_reg(0x7, 0x101); | ||
211 | wait_nr_frames(2); | ||
212 | spi_write_reg(0x76, 0x2213); | ||
213 | spi_write_reg(0x1c, 0x6650); | ||
214 | spi_write_reg(0xb, 0x33e1); | ||
215 | spi_write_reg(0x76, 0); | ||
216 | spi_write_reg(0x7, 0x103); | ||
217 | } | ||
218 | |||
219 | static void lcd_display_off_seq(void) | ||
220 | { | ||
221 | spi_write_reg(0xb, 0x30e1); | ||
222 | spi_write_reg(0x7, 0x102); | ||
223 | wait_nr_frames(2); | ||
224 | spi_write_reg(0x7, 0); | ||
225 | spi_write_reg(0x12, 0); | ||
226 | spi_write_reg(0x10, 0x100); | ||
227 | } | ||
228 | |||
229 | static void lcd_standby_in_seq(void) | ||
230 | { | ||
231 | lcd_display_off_seq(); | ||
232 | spi_write_reg(0x10, 0x1); | ||
233 | } | ||
234 | |||
235 | static void lcd_standby_out_seq(void) | ||
236 | { | ||
237 | spi_write_reg(0x10, 0); | ||
238 | lcd_power_seq(); | ||
239 | lcd_display_on_seq(); | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * Rockbox | ||
244 | */ | ||
245 | |||
246 | void lcd_init_device(void) | ||
247 | { | ||
248 | semaphore_init(&g_wait_sema, 1, 0); | ||
249 | #ifdef HAVE_LCD_ENABLE | ||
250 | lcd_on = true; | ||
251 | #endif | ||
252 | /** lcd is 320x240, data bus is 8-bit, depth is 24-bit so we need 3clk/pix | ||
253 | * by running PIX clock at 24MHz we can sustain ~100 fps */ | ||
254 | imx233_clkctrl_enable(CLK_PIX, false); | ||
255 | imx233_clkctrl_set_div(CLK_PIX, 2); | ||
256 | imx233_clkctrl_set_bypass(CLK_PIX, true); /* use XTAL */ | ||
257 | imx233_clkctrl_enable(CLK_PIX, true); | ||
258 | imx233_dma_reset_channel(APB_LCDIF); | ||
259 | imx233_dma_clkgate_channel(APB_LCDIF, true); | ||
260 | imx233_lcdif_init(); | ||
261 | imx233_lcdif_setup_dotclk_pins(8, false); | ||
262 | imx233_lcdif_set_word_length(8); | ||
263 | /** Datasheet states: | ||
264 | * 257H >= VBP >= 3H, VBP > VLW, VFP > 1H | ||
265 | * 1533clk >= HBP >= 24clk, HBP > HLW, HFP >= 4clk | ||
266 | * | ||
267 | * Take VLW=1H, VBP=3H, VFP=2H, HLW=8, HBP=24, HFP=4 | ||
268 | * Take 3clk/pix because we send 24-bit/pix with 8-bit data bus | ||
269 | * Keep consistent with register setting in lcd_init_seq | ||
270 | */ | ||
271 | imx233_lcdif_setup_dotclk_ex(/*v_pulse_width*/1, /*v_back_porch*/3, | ||
272 | /*v_front_porch*/1, /*h_pulse_width*/8, /*h_back_porch*/24, | ||
273 | /*h_front_porch*/4, LCD_WIDTH, LCD_HEIGHT, /*clk_per_pix*/3, | ||
274 | /*enable_present*/false); | ||
275 | imx233_lcdif_set_byte_packing_format(0xf); | ||
276 | // prepare pins | ||
277 | spi_init(); | ||
278 | imx233_pinctrl_acquire(1, 8, "lcd_power"); | ||
279 | imx233_pinctrl_set_function(1, 8, PINCTRL_FUNCTION_GPIO); | ||
280 | imx233_pinctrl_enable_gpio(1, 8, true); | ||
281 | // power up | ||
282 | lcd_power(true); | ||
283 | // reset lcd | ||
284 | imx233_lcdif_reset_lcd(true); | ||
285 | mdelay(1); | ||
286 | imx233_lcdif_reset_lcd(false); | ||
287 | mdelay(1); | ||
288 | imx233_lcdif_reset_lcd(true); | ||
289 | mdelay(1); | ||
290 | // setup registers | ||
291 | imx233_lcdif_enable_sync_signals(true); // we need frame signals during init | ||
292 | lcd_power_seq(); | ||
293 | lcd_init_seq(); | ||
294 | lcd_display_on_seq(); | ||
295 | // setup refresh | ||
296 | unsigned size = IMX233_FRAMEBUFFER_SIZE; | ||
297 | uint8_t *frame_p = FRAME; | ||
298 | for(int i = 0; i < NR_CMDS; i++) | ||
299 | { | ||
300 | unsigned xfer = MIN(IMX233_MAX_SINGLE_DMA_XFER_SIZE, size); | ||
301 | lcdif_dma[i].dma.next = &lcdif_dma[(i + 1) % NR_CMDS].dma; | ||
302 | lcdif_dma[i].dma.cmd = BF_OR3(APB_CHx_CMD, CHAIN(1), | ||
303 | COMMAND(BV_APB_CHx_CMD_COMMAND__READ), XFER_COUNT(xfer)); | ||
304 | lcdif_dma[i].dma.buffer = frame_p; | ||
305 | size -= xfer; | ||
306 | frame_p += xfer; | ||
307 | } | ||
308 | imx233_dma_start_command(APB_LCDIF, &lcdif_dma[0].dma); | ||
309 | BF_SET(LCDIF_CTRL, RUN); | ||
310 | } | ||
311 | |||
312 | #ifdef HAVE_LCD_ENABLE | ||
313 | bool lcd_active(void) | ||
314 | { | ||
315 | return lcd_on; | ||
316 | } | ||
317 | |||
318 | void lcd_enable(bool enable) | ||
319 | { | ||
320 | if(lcd_on == enable) | ||
321 | return; | ||
322 | |||
323 | lcd_on = enable; | ||
324 | } | ||
325 | #endif | ||
326 | |||
327 | void lcd_update(void) | ||
328 | { | ||
329 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); | ||
330 | } | ||
331 | |||
332 | void lcd_update_rect(int x, int y, int w, int h) | ||
333 | { | ||
334 | #ifdef HAVE_LCD_ENABLE | ||
335 | if(!lcd_on) | ||
336 | return; | ||
337 | #endif | ||
338 | uint8_t *p = FRAME; | ||
339 | for(int y = 0; y < LCD_HEIGHT; y++) | ||
340 | for(int x = 0; x < LCD_WIDTH; x++) | ||
341 | { | ||
342 | uint16_t pix = *FBADDR(x,y); | ||
343 | *p++ = RGB_UNPACK_RED(pix); | ||
344 | *p++ = RGB_UNPACK_GREEN(pix); | ||
345 | *p++ = RGB_UNPACK_BLUE(pix); | ||
346 | } | ||
347 | } | ||