1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2008 by Maurus Cuelenaere
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
30 #include "spi-target.h"
31 #include "lcd-target.h"
34 /* Power and display status */
35 static bool display_on
= false; /* Is the display turned on? */
36 static bool direct_fb_access
= false; /* Does the DM320 has direct access to the FB? */
38 /* Copies a rectangle from one framebuffer to another. Can be used in
39 single transfer mode with width = num pixels, and height = 1 which
40 allows a full-width rectangle to be copied more efficiently. */
41 extern void lcd_copy_buffer_rect(fb_data
*dst
, const fb_data
*src
,
42 int width
, int height
);
44 int lcd_default_contrast(void)
49 void lcd_set_contrast(int val
)
51 /* find S6F2002 controller datasheet first */
55 void lcd_set_invert_display(bool yesno
) {
60 void lcd_set_flip(bool yesno
) {
65 static void enable_venc(bool enable
)
70 IO_CLK_MOD1
&= ~(CLK_MOD1_VENC
| CLK_MOD1_OSD
); /* disable OSD clock and VENC clock */
73 IO_CLK_OSEL
&= ~CLK_OSEL_O2SEL(0xF); /* reset 'General purpose clock output (GIO26, GIO34)' and */
74 IO_CLK_OSEL
|= CLK_OSEL_O2SEL(4); /* set to 'PLLIN clock' */
76 IO_CLK_SEL1
|= (CLK_SEL1_OSD
| CLK_SEL1_VENC(7)); /* set to 'GP clock output 2 (GIO26, GIO34)' and turn on 'VENC clock' */
77 IO_CLK_MOD1
|= (CLK_MOD1_VENC
| CLK_MOD1_OSD
); /* enable OSD clock and VENC clock */
81 /* Disable video encoder */
82 IO_VID_ENC_VMOD
&= ~VENC_VMOD_VENC
;
83 /* Disable clock for power saving */
84 IO_CLK_MOD1
&= ~(CLK_MOD1_VENC
| CLK_MOD1_OSD
);
88 /* LTV250QV panel functions */
89 static void lcd_write_reg(unsigned char reg
, unsigned short val
)
91 unsigned char block
[3] = {LTV_OPC_INDEX
, 0, reg
| 0xFF};
92 spi_block_transfer(SPI_target_LTV250QV
, block
, sizeof(block
), NULL
, 0);
93 block
[0] = LTV_OPC_DATA
;
95 block
[2] = val
& 0xFF;
96 spi_block_transfer(SPI_target_LTV250QV
, block
, sizeof(block
), NULL
, 0);
99 static void sleep_ms(unsigned int ms
)
104 static void lcd_display_on(bool reset
)
106 /* Enable main power */
107 IO_GIO_BITSET2
|= (1 << 3);
109 /* power on sequence as per the ZVM firmware */
111 IO_GIO_BITSET1
= (1 << 13);
113 IO_GIO_BITSET2
= (1 << 5);
114 IO_GIO_BITSET2
= (1 << 8);
117 /*Init SPI here... */
120 IO_GIO_BITSET2
= (1 << 0);
122 IO_GIO_BITSET2
= (1 << 7);
124 IO_GIO_BITSET2
= (1 << 4);
126 IO_GIO_BITCLR2
= (1 << 8);
127 /*TODO: figure out what OF does after this... */
128 IO_GIO_BITSET2
= (1 << 8);
131 lcd_write_reg(LTV_IFCTL
, LTV_NL(29));
132 lcd_write_reg(LTV_DATACTL
, 0);
133 lcd_write_reg(LTV_ENTRY_MODE
,0);
134 lcd_write_reg(LTV_GATECTL1
, 0);
135 lcd_write_reg(LTV_GATECTL2
, (LTV_NW_INV_1LINE
| LTV_FHN
| LTV_FTI(2) | LTV_FWI(3)));
136 lcd_write_reg(LTV_VBP
, 0);
137 lcd_write_reg(LTV_HBP
, 0);
138 lcd_write_reg(LTV_SOTCTL
, 0);
139 lcd_write_reg(LTV_PWRCTL1
, 0);
140 lcd_write_reg(LTV_PWRCTL2
, 0);
141 lcd_write_reg(LTV_GAMMA(0), 0);
142 lcd_write_reg(LTV_GAMMA(1), 0);
143 lcd_write_reg(LTV_GAMMA(2), 0);
144 lcd_write_reg(LTV_GAMMA(3), 0);
145 lcd_write_reg(LTV_GAMMA(4), 0);
146 lcd_write_reg(LTV_GAMMA(5), 0);
147 lcd_write_reg(LTV_GAMMA(6), 0);
148 lcd_write_reg(LTV_GAMMA(7), 0);
149 lcd_write_reg(LTV_GAMMA(8), 0);
150 lcd_write_reg(LTV_GAMMA(9), 0);
153 lcd_write_reg(LTV_PWRCTL1
, (LTV_VCOM_DISABLE
| LTV_DRIVE_CURRENT(5) | LTV_SUPPLY_CURRENT(5)));
154 lcd_write_reg(LTV_PWRCTL2
, 0);
157 lcd_write_reg(LTV_PWRCTL2
, LTV_VCOML_ENABLE
);
160 lcd_write_reg(LTV_IFCTL
, (LTV_NMD
| LTV_NL(29)));
161 lcd_write_reg(LTV_DATACTL
, (LTV_DS_SAME
| LTV_CHS_480
| LTV_DF_RGB
| LTV_RGB_BGR
));
162 lcd_write_reg(LTV_ENTRY_MODE
,(LTV_VSPL_ACTIVE_LOW
| LTV_HSPL_ACTIVE_LOW
| LTV_DPL_SAMPLE_RISING
| LTV_EPL_ACTIVE_LOW
| LTV_SS_RIGHT_TO_LEFT
));
163 lcd_write_reg(LTV_GATECTL1
, LTV_CLW(1));
164 lcd_write_reg(LTV_GATECTL2
, (LTV_NW_INV_1LINE
| LTV_DSC
| LTV_FTI(3) | LTV_FWI(3)));
165 lcd_write_reg(LTV_VBP
, 0x5);
166 lcd_write_reg(LTV_HBP
, 0x1B);
167 lcd_write_reg(LTV_SOTCTL
, LTV_SDT(2));
168 lcd_write_reg(LTV_GAMMA(0), 0x203);
169 lcd_write_reg(LTV_GAMMA(1), 0x302);
170 lcd_write_reg(LTV_GAMMA(2), 0xC08);
171 lcd_write_reg(LTV_GAMMA(3), 0xC08);
172 lcd_write_reg(LTV_GAMMA(4), 0x707);
173 lcd_write_reg(LTV_GAMMA(5), 0x707);
174 lcd_write_reg(LTV_GAMMA(6), 0x104);
175 lcd_write_reg(LTV_GAMMA(7), 0x306);
176 lcd_write_reg(LTV_GAMMA(8), 0);
177 lcd_write_reg(LTV_GAMMA(9), 0);
180 lcd_write_reg(LTV_PWRCTL1
, (LTV_VCOMOUT_ENABLE
| LTV_POWER_ON
| LTV_DRIVE_CURRENT(5) | LTV_SUPPLY_CURRENT(5)));
181 lcd_write_reg(LTV_PWRCTL2
, (LTV_VCOML_VOLTAGE(17) | LTV_VCOMH_VOLTAGE(26))); /* VCOML=0,0625V VCOMH=1,21875V */
187 /* Re-enable video encoder */
188 IO_VID_ENC_VMOD
|= VENC_VMOD_VENC
;
190 /* tell that we're on now */
194 #ifdef HAVE_LCD_ENABLE
195 static void lcd_display_off(void)
197 /* LQV shutdown sequence */
198 lcd_write_reg(LTV_PWRCTL1
, (LTV_VCOMOUT_ENABLE
| LTV_DRIVE_CURRENT(5) | LTV_SUPPLY_CURRENT(5)));
201 lcd_write_reg(LTV_PWRCTL1
, (LTV_DRIVE_CURRENT(5) | LTV_SUPPLY_CURRENT(5)));
202 lcd_write_reg(LTV_GATECTL2
, (LTV_NW_INV_1LINE
| LTV_FTI(3) | LTV_FWI(3)));
203 lcd_write_reg(LTV_PWRCTL2
, 0);
206 lcd_write_reg(LTV_PWRCTL1
, 0);
208 unsigned char temp
[1];
210 spi_block_transfer(SPI_target_LTV250QV
, temp
, sizeof(temp
), NULL
, 0);
212 IO_GIO_BITCLR2
= (1 << 4);
214 IO_GIO_BITCLR2
= (1 << 7);
216 IO_GIO_BITCLR2
= (1 << 0);
218 IO_GIO_BITCLR2
= (1 << 8);
219 IO_GIO_BITCLR2
= (1 << 5);
221 /* Disable main power */
222 IO_GIO_BITCLR2
|= (1 << 3);
229 void lcd_enable(bool on
)
231 /* Disabled until properly working */
233 if (on
== display_on
)
238 lcd_display_on(false); /* Turn on display */
239 lcd_update(); /* Resync display */
240 send_event(LCD_EVENT_ACTIVATION
, NULL
);
244 lcd_display_off(); /* Turn off display */
249 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
250 bool lcd_active(void)
256 void lcd_set_direct_fb(bool yes
)
259 direct_fb_access
= yes
;
261 addr
= ((unsigned int)&lcd_framebuffer
-CONFIG_SDRAM_START
) / 32;
263 addr
= ((unsigned int)FRAME
-CONFIG_SDRAM_START
) / 32;
264 IO_OSD_OSDWINADH
= addr
>> 16;
265 IO_OSD_OSDWIN0ADL
= addr
& 0xFFFF;
268 bool lcd_get_direct_fb(void)
270 return direct_fb_access
;
273 static bool _lcd_enabled(void)
275 /* Needed to detect if VENC/LCD already is initialized... */
276 if(IO_VID_ENC_VDCTL
& VENC_VDCTL_VCLKE
)
278 else if(!(IO_VID_ENC_VDCTL
& VENC_VDCTL_YCDC
))
280 else if(IO_CLK_MOD1
& CLK_MOD1_VENC
)
282 else if(IO_CLK_MOD1
& CLK_MOD1_OSD
)
288 void lcd_init_device(void)
292 lcd_display_on(true);
296 /* Set LCD values in Video Encoder */
297 IO_VID_ENC_VMOD
&= 0x8800; /* Clear all values */
298 IO_VID_ENC_VMOD
|= (VENC_VMOD_DACPD
| VENC_VMOD_VMD
| VENC_VMOD_ITLC
| VENC_VMOD_VDMD(2)); /* set mode to RGB666 parallel 16 bit */
299 IO_VID_ENC_VDCTL
&= 0x8FE8; /* Clear all values */
300 IO_VID_ENC_VDCTL
|= (VENC_VDCTL_VCLKP
| VENC_VDCTL_DOMD(2)),
301 IO_VID_ENC_VDPRO
= VENC_VDPRO_PFLTR
;
302 IO_VID_ENC_SYNCTL
&= 0xE000; /* Clear all values */
303 IO_VID_ENC_SYNCTL
|= (VENC_SYNCTL_VPL
| VENC_SYNCTL_HPL
);
304 IO_VID_ENC_HSDLY
= 0;
305 IO_VID_ENC_HSPLS
= 0x12;
306 IO_VID_ENC_HSTART
= 0x1B;
307 IO_VID_ENC_HVALID
= 0x140;
308 IO_VID_ENC_HINT
= 0x168;
309 IO_VID_ENC_VSDLY
= 0;
310 IO_VID_ENC_VSPLS
= 3;
311 IO_VID_ENC_VSTART
= 5;
312 IO_VID_ENC_VVALID
= 0xF0;
313 IO_VID_ENC_VINT
= 0x118;
314 IO_VID_ENC_RGBCTL
&= 0x088; /* Clear all values */
315 IO_VID_ENC_RGBCTL
|= VENC_RGBCTL_DFLTR
;
316 IO_VID_ENC_RGBCLP
= VENC_RGBCLP_UCLIP(0xFF);
317 IO_VID_ENC_LCDOUT
&= 0xFE00; /* Clear all values */
318 IO_VID_ENC_LCDOUT
|= (VENC_LCDOUT_OEE
| VENC_LCDOUT_FIDS
);
319 IO_VID_ENC_DCLKCTL
&= 0xC0C0; /* Clear all values */
320 IO_VID_ENC_DCLKCTL
|= VENC_DCLKCTL_DCKEC
;
321 IO_VID_ENC_DCLKPTN0
= 1;
322 DM320_REG(0x0864) = 0; /* ???? */
327 /* Based on lcd-mr500.c from Catalin Patulea */
328 /* Clear the Frame */
329 memset16(FRAME
, 0x0000, LCD_WIDTH
*LCD_HEIGHT
);
331 IO_OSD_MODE
= 0x00ff;
332 IO_OSD_VIDWINMD
= 0x0002;
333 IO_OSD_OSDWINMD0
= 0x2001;
334 IO_OSD_OSDWINMD1
= 0x0002;
335 IO_OSD_ATRMD
= 0x0000;
336 IO_OSD_RECTCUR
= 0x0000;
339 IO_OSD_OSDWIN0OFST
= (LCD_WIDTH
*16) / 256;
340 addr
= ((unsigned int)FRAME
-CONFIG_SDRAM_START
) / 32;
341 IO_OSD_OSDWINADH
= addr
>> 16;
342 IO_OSD_OSDWIN0ADL
= addr
& 0xFFFF;
352 IO_OSD_OSDWIN0XP
= 0;
353 IO_OSD_OSDWIN0YP
= 0;
354 IO_OSD_OSDWIN0XL
= LCD_WIDTH
;
355 IO_OSD_OSDWIN0YL
= LCD_HEIGHT
;
357 IO_VID_ENC_VDCTL
|= VENC_VDCTL_VCLKE
; /* Enable VCLK */
358 IO_VID_ENC_VMOD
|= VENC_VMOD_VENC
; /* Enable video encoder */
359 IO_VID_ENC_SYNCTL
|= VENC_SYNCTL_SYE
; /* Enable sync output */
360 IO_VID_ENC_VDCTL
&= ~VENC_VDCTL_DOMD(3); /* Normal digital data output */
364 /*** Update functions ***/
366 /* Update a fraction of the display. */
367 void lcd_update_rect(int x
, int y
, int width
, int height
)
369 register fb_data
*dst
, *src
;
371 if (!display_on
|| direct_fb_access
)
374 if (x
+ width
> LCD_WIDTH
)
375 width
= LCD_WIDTH
- x
; /* Clip right */
377 width
+= x
, x
= 0; /* Clip left */
379 return; /* nothing left to do */
381 if (y
+ height
> LCD_HEIGHT
)
382 height
= LCD_HEIGHT
- y
; /* Clip bottom */
384 height
+= y
, y
= 0; /* Clip top */
386 return; /* nothing left to do */
388 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
389 dst
= (fb_data
*)FRAME
+ LCD_WIDTH
*y
+ x
;
390 src
= &lcd_framebuffer
[y
][x
];
392 /* Copy part of the Rockbox framebuffer to the second framebuffer */
393 if (width
< LCD_WIDTH
)
395 /* Not full width - do line-by-line */
396 lcd_copy_buffer_rect(dst
, src
, width
, height
);
400 /* Full width - copy as one line */
401 lcd_copy_buffer_rect(dst
, src
, LCD_WIDTH
*height
, 1);
404 src
= &lcd_framebuffer
[y
][x
];
407 register fb_data
*start
=FRAME
+ LCD_HEIGHT
*(LCD_WIDTH
-x
-1) + y
+ 1;
409 for(yc
=0;yc
<height
;yc
++)
412 for(xc
=0; xc
<width
; xc
++)
422 /* Update the display.
423 This must be called after all other LCD functions that change the display. */
424 void lcd_update(void)
426 if (!display_on
|| direct_fb_access
)
428 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
429 lcd_copy_buffer_rect((fb_data
*)FRAME
, &lcd_framebuffer
[0][0],
430 LCD_WIDTH
*LCD_HEIGHT
, 1);
432 lcd_update_rect(0, 0, LCD_WIDTH
, LCD_HEIGHT
);
436 /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
437 extern void lcd_write_yuv420_lines(fb_data
*dst
,
438 unsigned char chroma_buf
[LCD_HEIGHT
/2*3],
439 unsigned char const * const src
[3],
442 /* Performance function to blit a YUV bitmap directly to the LCD */
443 /* For the Gigabeat - show it rotated */
444 /* So the LCD_WIDTH is now the height */
445 void lcd_blit_yuv(unsigned char * const src
[3],
446 int src_x
, int src_y
, int stride
,
447 int x
, int y
, int width
, int height
)
449 /* Caches for chroma data so it only need be recalculated every other
451 unsigned char chroma_buf
[LCD_HEIGHT
/2*3]; /* 480 bytes */
452 unsigned char const * yuv_src
[3];
455 if (!display_on
|| direct_fb_access
)
458 /* Sorry, but width and height must be >= 2 or else */
462 fb_data
*dst
= (fb_data
*)FRAME
+ x
* LCD_WIDTH
+ (LCD_WIDTH
- y
) - 1;
465 yuv_src
[0] = src
[0] + z
+ src_x
;
466 yuv_src
[1] = src
[1] + (z
>> 2) + (src_x
>> 1);
467 yuv_src
[2] = src
[2] + (yuv_src
[1] - src
[1]);
471 lcd_write_yuv420_lines(dst
, chroma_buf
, yuv_src
, width
,
474 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
475 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
476 yuv_src
[2] += stride
>> 1;
479 while (--height
> 0);