diff options
Diffstat (limited to 'firmware/target/arm/tms320dm320/creative-zvm/lcd-creativezvm.c')
-rw-r--r-- | firmware/target/arm/tms320dm320/creative-zvm/lcd-creativezvm.c | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/firmware/target/arm/tms320dm320/creative-zvm/lcd-creativezvm.c b/firmware/target/arm/tms320dm320/creative-zvm/lcd-creativezvm.c new file mode 100644 index 0000000000..dec20ad72f --- /dev/null +++ b/firmware/target/arm/tms320dm320/creative-zvm/lcd-creativezvm.c | |||
@@ -0,0 +1,405 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2008 by Maurus Cuelenaere | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "config.h" | ||
20 | |||
21 | #include "hwcompat.h" | ||
22 | #include "kernel.h" | ||
23 | #include "lcd.h" | ||
24 | #include "system.h" | ||
25 | #include "memory.h" | ||
26 | #include "cpu.h" | ||
27 | #include "spi.h" | ||
28 | #include "spi-target.h" | ||
29 | #include "lcd-target.h" | ||
30 | |||
31 | /* Power and display status */ | ||
32 | static bool display_on = true; /* Is the display turned on? */ | ||
33 | static bool direct_fb_access = false; /* Does the DM320 has direct access to the FB? */ | ||
34 | |||
35 | int lcd_default_contrast(void) | ||
36 | { | ||
37 | return 0x1f; | ||
38 | } | ||
39 | |||
40 | void lcd_set_contrast(int val) | ||
41 | { | ||
42 | /* iirc there is an ltv250qv command to do this */ | ||
43 | #warning function not implemented | ||
44 | (void)val; | ||
45 | } | ||
46 | |||
47 | void lcd_set_invert_display(bool yesno) { | ||
48 | (void) yesno; | ||
49 | // TODO: | ||
50 | } | ||
51 | |||
52 | void lcd_set_flip(bool yesno) { | ||
53 | (void) yesno; | ||
54 | // TODO: | ||
55 | } | ||
56 | |||
57 | |||
58 | /* LTV250QV panel functions */ | ||
59 | |||
60 | static void lcd_write_reg(unsigned char reg, unsigned short val) | ||
61 | { | ||
62 | unsigned char block[3]; | ||
63 | block[0] = 0x74; | ||
64 | block[1] = 0; | ||
65 | block[2] = reg | 0xFF; | ||
66 | spi_block_transfer(SPI_target_LTV250QV, block, sizeof(block), NULL, 0); | ||
67 | block[0] = 0x76; | ||
68 | block[1] = (val >> 8) & 0xFF; | ||
69 | block[2] = val & 0xFF; | ||
70 | spi_block_transfer(SPI_target_LTV250QV, block, sizeof(block), NULL, 0); | ||
71 | } | ||
72 | |||
73 | static void sleep_ms(unsigned int ms) | ||
74 | { | ||
75 | sleep(ms*HZ/1000); | ||
76 | } | ||
77 | |||
78 | static void lcd_display_on(void) | ||
79 | { | ||
80 | /* Enable main power */ | ||
81 | IO_GIO_BITSET2 |= (1 << 3); | ||
82 | |||
83 | /* power on sequence as per the ZVM firmware */ | ||
84 | sleep_ms(250); | ||
85 | IO_GIO_BITSET1 = (1 << 13); | ||
86 | sleep_ms(5); | ||
87 | IO_GIO_BITSET2 = (1 << 5); | ||
88 | IO_GIO_BITSET2 = (1 << 8); | ||
89 | sleep_ms(1); | ||
90 | |||
91 | //Init SPI here... | ||
92 | sleep_ms(32); | ||
93 | |||
94 | IO_GIO_BITSET2 = (1 << 0); | ||
95 | sleep_ms(5); | ||
96 | IO_GIO_BITSET2 = (1 << 7); | ||
97 | sleep_ms(5); | ||
98 | IO_GIO_BITSET2 = (1 << 4); | ||
99 | sleep_ms(5); | ||
100 | IO_GIO_BITCLR2 = (1 << 8); | ||
101 | //TODO: figure out what OF does after this... | ||
102 | IO_GIO_BITSET2 = (1 << 8); | ||
103 | sleep_ms(1); | ||
104 | |||
105 | lcd_write_reg(1, 0x1D); | ||
106 | lcd_write_reg(2, 0x0); | ||
107 | lcd_write_reg(3, 0x0); | ||
108 | lcd_write_reg(4, 0x0); | ||
109 | lcd_write_reg(5, 0x40A3); | ||
110 | lcd_write_reg(6, 0x0); | ||
111 | lcd_write_reg(7, 0x0); | ||
112 | lcd_write_reg(8, 0x0); | ||
113 | lcd_write_reg(9, 0x0); | ||
114 | lcd_write_reg(10, 0x0); | ||
115 | lcd_write_reg(16, 0x0); | ||
116 | lcd_write_reg(17, 0x0); | ||
117 | lcd_write_reg(18, 0x0); | ||
118 | lcd_write_reg(19, 0x0); | ||
119 | lcd_write_reg(20, 0x0); | ||
120 | lcd_write_reg(21, 0x0); | ||
121 | lcd_write_reg(22, 0x0); | ||
122 | lcd_write_reg(23, 0x0); | ||
123 | lcd_write_reg(24, 0x0); | ||
124 | lcd_write_reg(25, 0x0); | ||
125 | sleep_ms(10); | ||
126 | |||
127 | lcd_write_reg(9, 0x4055); | ||
128 | lcd_write_reg(10, 0x0); | ||
129 | sleep_ms(40); | ||
130 | |||
131 | lcd_write_reg(10, 0x2000); | ||
132 | sleep_ms(40); | ||
133 | |||
134 | lcd_write_reg(1, 0x401D); | ||
135 | lcd_write_reg(2, 0x204); | ||
136 | lcd_write_reg(3, 0x100); | ||
137 | lcd_write_reg(4, 0x1000); | ||
138 | lcd_write_reg(5, 0x5033); | ||
139 | lcd_write_reg(6, 0x5); | ||
140 | lcd_write_reg(7, 0x1B); | ||
141 | lcd_write_reg(8, 0x800); | ||
142 | lcd_write_reg(16, 0x203); | ||
143 | lcd_write_reg(17, 0x302); | ||
144 | lcd_write_reg(18, 0xC08); | ||
145 | lcd_write_reg(19, 0xC08); | ||
146 | lcd_write_reg(20, 0x707); | ||
147 | lcd_write_reg(21, 0x707); | ||
148 | lcd_write_reg(22, 0x104); | ||
149 | lcd_write_reg(23, 0x306); | ||
150 | lcd_write_reg(24, 0x0); | ||
151 | lcd_write_reg(25, 0x0); | ||
152 | sleep_ms(60); | ||
153 | |||
154 | lcd_write_reg(9, 0xA55); | ||
155 | lcd_write_reg(10, 0x111A); | ||
156 | sleep_ms(10); | ||
157 | |||
158 | //TODO: other stuff! | ||
159 | |||
160 | /* tell that we're on now */ | ||
161 | display_on = true; | ||
162 | } | ||
163 | |||
164 | static void lcd_display_off(void) | ||
165 | { | ||
166 | display_on = false; | ||
167 | |||
168 | /* LQV shutdown sequence */ | ||
169 | lcd_write_reg(9, 0x855); | ||
170 | sleep_ms(20); | ||
171 | |||
172 | lcd_write_reg(9, 0x55); | ||
173 | lcd_write_reg(5, 0x4033); | ||
174 | lcd_write_reg(10, 0x0); | ||
175 | sleep_ms(20); | ||
176 | |||
177 | lcd_write_reg(9, 0x0); | ||
178 | sleep_ms(10); | ||
179 | unsigned char temp[1]; | ||
180 | temp[0] = 0; | ||
181 | spi_block_transfer(SPI_target_LTV250QV, temp, sizeof(temp), NULL, 0); | ||
182 | |||
183 | IO_GIO_BITCLR2 = (1 << 4); | ||
184 | sleep_ms(5); | ||
185 | IO_GIO_BITCLR2 = (1 << 7); | ||
186 | sleep_ms(5); | ||
187 | IO_GIO_BITCLR2 = (1 << 0); | ||
188 | sleep_ms(2); | ||
189 | IO_GIO_BITCLR2 = (1 << 8); | ||
190 | IO_GIO_BITCLR2 = (1 << 5); | ||
191 | |||
192 | /* Disable main power */ | ||
193 | IO_GIO_BITCLR2 |= (1 << 3); | ||
194 | } | ||
195 | |||
196 | |||
197 | |||
198 | void lcd_enable(bool on) | ||
199 | { | ||
200 | if (on == display_on) | ||
201 | return; | ||
202 | |||
203 | if (on) | ||
204 | { | ||
205 | display_on = true; //TODO: remove me! | ||
206 | //lcd_display_on(); /* Turn on display */ | ||
207 | lcd_update(); /* Resync display */ | ||
208 | } | ||
209 | else | ||
210 | { | ||
211 | display_on = false; //TODO: remove me! | ||
212 | //lcd_display_off(); /* Turn off display */ | ||
213 | } | ||
214 | } | ||
215 | |||
216 | bool lcd_enabled(void) | ||
217 | { | ||
218 | return display_on; | ||
219 | } | ||
220 | |||
221 | void lcd_set_direct_fb(bool yes) | ||
222 | { | ||
223 | unsigned int addr; | ||
224 | direct_fb_access = yes; | ||
225 | if(yes) | ||
226 | addr = ((unsigned int)&lcd_framebuffer-CONFIG_SDRAM_START) / 32; | ||
227 | else | ||
228 | addr = ((unsigned int)FRAME-CONFIG_SDRAM_START) / 32; | ||
229 | IO_OSD_OSDWINADH = addr >> 16; | ||
230 | IO_OSD_OSDWIN0ADL = addr & 0xFFFF; | ||
231 | } | ||
232 | |||
233 | bool lcd_get_direct_fb(void) | ||
234 | { | ||
235 | return direct_fb_access; | ||
236 | } | ||
237 | |||
238 | void lcd_init_device(void) | ||
239 | { | ||
240 | /* Based on lcd-mr500.c from Catalin Patulea */ | ||
241 | unsigned int addr; | ||
242 | |||
243 | /* Clear the Frame */ | ||
244 | memset16(FRAME, 0x0000, LCD_WIDTH*LCD_HEIGHT); | ||
245 | |||
246 | IO_OSD_MODE = 0x00ff; | ||
247 | IO_OSD_VIDWINMD = 0x0002; | ||
248 | IO_OSD_OSDWINMD0 = 0x2001; | ||
249 | IO_OSD_OSDWINMD1 = 0x0002; | ||
250 | IO_OSD_ATRMD = 0x0000; | ||
251 | IO_OSD_RECTCUR = 0x0000; | ||
252 | |||
253 | IO_OSD_OSDWIN0OFST = (LCD_WIDTH*16) / 256; | ||
254 | addr = ((unsigned int)FRAME-CONFIG_SDRAM_START) / 32; | ||
255 | IO_OSD_OSDWINADH = addr >> 16; | ||
256 | IO_OSD_OSDWIN0ADL = addr & 0xFFFF; | ||
257 | |||
258 | #ifndef ZEN_VISION | ||
259 | IO_OSD_BASEPX=26; | ||
260 | IO_OSD_BASEPY=5; | ||
261 | #else | ||
262 | IO_OSD_BASEPX=80; | ||
263 | IO_OSD_BASEPY=0; | ||
264 | #endif | ||
265 | |||
266 | IO_OSD_OSDWIN0XP = 0; | ||
267 | IO_OSD_OSDWIN0YP = 0; | ||
268 | IO_OSD_OSDWIN0XL = LCD_WIDTH; | ||
269 | IO_OSD_OSDWIN0YL = LCD_HEIGHT; | ||
270 | #if 0 | ||
271 | //TODO: set LCD clock! | ||
272 | IO_CLK_MOD1 &= ~0x18; // disable OSD clock and VENC clock | ||
273 | IO_CLK_02DIV = 3; | ||
274 | IO_CLK_OSEL = (IO_CLK_OSEL & ~0xF00) | 0x400; // reset 'General purpose clock output (GIO26, GIO34)' and set to 'PLLIN clock' | ||
275 | IO_CLK_SEL1 = (IO_CLK_SEL1 | 7) | 0x1000; // set to 'GP clock output 2 (GIO26, GIO34)' and turn on 'VENC clock' | ||
276 | IO_CLK_MOD1 |= 0x18; // enable OSD clock and VENC clock | ||
277 | |||
278 | /* Set LCD values in OSD */ | ||
279 | IO_VID_ENC_VMOD = ( ( (IO_VID_ENC_VMOD & 0xFFFF8C00) | 0x14) | 0x2400 ); // disable NTSC/PAL encoder & set mode to RGB666 parallel 18 bit | ||
280 | IO_VID_ENC_VDCTL = ( ( (IO_VID_ENC_VDCTL & 0xFFFFCFE8) | 0x20) | 0x4000 ); | ||
281 | //TODO: finish this... | ||
282 | #endif | ||
283 | } | ||
284 | |||
285 | |||
286 | /*** Update functions ***/ | ||
287 | |||
288 | |||
289 | |||
290 | /* Update a fraction of the display. */ | ||
291 | void lcd_update_rect(int x, int y, int width, int height) | ||
292 | { | ||
293 | register fb_data *dst, *src; | ||
294 | |||
295 | if (!display_on || direct_fb_access) | ||
296 | return; | ||
297 | |||
298 | if (x + width > LCD_WIDTH) | ||
299 | width = LCD_WIDTH - x; /* Clip right */ | ||
300 | if (x < 0) | ||
301 | width += x, x = 0; /* Clip left */ | ||
302 | if (width <= 0) | ||
303 | return; /* nothing left to do */ | ||
304 | |||
305 | if (y + height > LCD_HEIGHT) | ||
306 | height = LCD_HEIGHT - y; /* Clip bottom */ | ||
307 | if (y < 0) | ||
308 | height += y, y = 0; /* Clip top */ | ||
309 | if (height <= 0) | ||
310 | return; /* nothing left to do */ | ||
311 | |||
312 | #if CONFIG_ORIENTATION == SCREEN_PORTAIT | ||
313 | dst = (fb_data *)FRAME + LCD_WIDTH*y + x; | ||
314 | src = &lcd_framebuffer[y][x]; | ||
315 | |||
316 | /* Copy part of the Rockbox framebuffer to the second framebuffer */ | ||
317 | if (width < LCD_WIDTH) | ||
318 | { | ||
319 | /* Not full width - do line-by-line */ | ||
320 | lcd_copy_buffer_rect(dst, src, width, height); | ||
321 | } | ||
322 | else | ||
323 | { | ||
324 | /* Full width - copy as one line */ | ||
325 | lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1); | ||
326 | } | ||
327 | #else | ||
328 | src = &lcd_framebuffer[y][x]; | ||
329 | |||
330 | register int xc, yc; | ||
331 | register fb_data *start=FRAME + LCD_HEIGHT*(LCD_WIDTH-x-1) + y + 1; | ||
332 | |||
333 | for(yc=0;yc<height;yc++) | ||
334 | { | ||
335 | dst=start+yc; | ||
336 | for(xc=0; xc<width; xc++) | ||
337 | { | ||
338 | *dst=*src++; | ||
339 | dst-=LCD_HEIGHT; | ||
340 | } | ||
341 | src+=x; | ||
342 | } | ||
343 | #endif | ||
344 | } | ||
345 | |||
346 | /* Update the display. | ||
347 | This must be called after all other LCD functions that change the display. */ | ||
348 | void lcd_update(void) | ||
349 | { | ||
350 | if (!display_on || direct_fb_access) | ||
351 | return; | ||
352 | #if CONFIG_ORIENTATION == SCREEN_PORTAIT | ||
353 | lcd_copy_buffer_rect((fb_data *)FRAME, &lcd_framebuffer[0][0], | ||
354 | LCD_WIDTH*LCD_HEIGHT, 1); | ||
355 | #else | ||
356 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); | ||
357 | #endif | ||
358 | } | ||
359 | |||
360 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
361 | extern void lcd_write_yuv420_lines(fb_data *dst, | ||
362 | unsigned char chroma_buf[LCD_HEIGHT/2*3], | ||
363 | unsigned char const * const src[3], | ||
364 | int width, | ||
365 | int stride); | ||
366 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
367 | /* For the Gigabeat - show it rotated */ | ||
368 | /* So the LCD_WIDTH is now the height */ | ||
369 | void lcd_blit_yuv(unsigned char * const src[3], | ||
370 | int src_x, int src_y, int stride, | ||
371 | int x, int y, int width, int height) | ||
372 | { | ||
373 | /* Caches for chroma data so it only need be recalculated every other | ||
374 | line */ | ||
375 | unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 480 bytes */ | ||
376 | unsigned char const * yuv_src[3]; | ||
377 | off_t z; | ||
378 | |||
379 | if (!display_on || direct_fb_access) | ||
380 | return; | ||
381 | |||
382 | /* Sorry, but width and height must be >= 2 or else */ | ||
383 | width &= ~1; | ||
384 | height >>= 1; | ||
385 | |||
386 | fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + (LCD_WIDTH - y) - 1; | ||
387 | |||
388 | z = stride*src_y; | ||
389 | yuv_src[0] = src[0] + z + src_x; | ||
390 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
391 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
392 | |||
393 | do | ||
394 | { | ||
395 | lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width, | ||
396 | stride); | ||
397 | |||
398 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
399 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
400 | yuv_src[2] += stride >> 1; | ||
401 | dst -= 2; | ||
402 | } | ||
403 | while (--height > 0); | ||
404 | } | ||
405 | |||