1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 by Karl Kurbjun
12 * Some of this is based on the Cowon A2 Firmware release:
13 * http://www.cowonglobal.com/download/gnu/cowon_pmp_a2_src_1.59_GPL.tar.gz
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
31 #include "system-target.h"
33 #include "lcd-target.h"
35 /* Copies a rectangle from one framebuffer to another. Can be used in
36 single transfer mode with width = num pixels, and height = 1 which
37 allows a full-width rectangle to be copied more efficiently. */
38 extern void lcd_copy_buffer_rect(fb_data
*dst
, const fb_data
*src
,
39 int width
, int height
);
41 static bool lcd_on
= true;
42 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
43 static bool lcd_powered
= true;
47 ** These are imported from lcd-16bit.c
49 extern unsigned fg_pattern
;
50 extern unsigned bg_pattern
;
52 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
59 #if defined(HAVE_LCD_SLEEP)
64 /* "not powered" implies "disabled" */
68 /* Disabling these saves another ~15mA */
69 IO_OSD_OSDWINMD0
&=~(0x01);
70 IO_VID_ENC_VMOD
&=~(0x01);
74 /* Disabling the LCD saves ~50mA */
81 #if defined(HAVE_LCD_ENABLE)
82 void lcd_enable(bool state
)
89 /* "enabled" implies "powered" */
94 IO_OSD_OSDWINMD0
|=0x01;
95 IO_VID_ENC_VMOD
|=0x01;
99 /* Wait long enough for a frame to be written - yes, it
106 lcd_activation_call_hook();
115 /* Note this is expecting a screen size of 480x640 or 240x320, other screen
116 * sizes need to be considered for fudge factors
118 #define LCD_FUDGE LCD_NATIVE_WIDTH%32
120 /* LCD init - based on code from ingenient-bsp/bootloader/board/dm320/splash.c
121 * and code by Catalin Patulea from the M:Robe 500i linux port
123 void lcd_init_device(void)
127 /* Clear the Frame */
128 memset16(FRAME
, 0x0000, LCD_WIDTH
*LCD_HEIGHT
);
132 IO_OSD_OSDWINMD0
&=~(0x0001);
133 IO_OSD_VIDWINMD
&=~(0x0001);
135 /* Setup the LCD controller */
136 IO_VID_ENC_VMOD
=0x2014;
137 IO_VID_ENC_VDCTL
=0x2000;
138 IO_VID_ENC_VDPRO
=0x0000;
139 IO_VID_ENC_SYNCTL
=0x100E;
140 IO_VID_ENC_HSPLS
=1; /* HSYNC pulse width */
141 IO_VID_ENC_VSPLS
=1; /* VSYNC pulse width */
143 /* These calculations support 640x480 and 320x240 (based on OF) */
144 IO_VID_ENC_HINT
=LCD_NATIVE_WIDTH
+LCD_NATIVE_WIDTH
/3;
145 IO_VID_ENC_HSTART
=LCD_NATIVE_WIDTH
/6; /* Front porch */
146 IO_VID_ENC_HVALID
=LCD_NATIVE_WIDTH
; /* Data valid */
147 IO_VID_ENC_VINT
=LCD_NATIVE_HEIGHT
+7;
149 IO_VID_ENC_VVALID
=LCD_NATIVE_HEIGHT
;
151 IO_VID_ENC_HSDLY
=0x0000;
152 IO_VID_ENC_VSDLY
=0x0000;
153 IO_VID_ENC_YCCTL
=0x0000;
154 IO_VID_ENC_RGBCTL
=0x0000;
155 IO_VID_ENC_RGBCLP
=0xFF00;
156 IO_VID_ENC_LNECTL
=0x0000;
157 IO_VID_ENC_CULLLNE
=0x0000;
158 IO_VID_ENC_LCDOUT
=0x0000;
159 IO_VID_ENC_BRTS
=0x0000;
160 IO_VID_ENC_BRTW
=0x0000;
161 IO_VID_ENC_ACCTL
=0x0000;
162 IO_VID_ENC_PWMP
=0x0000;
163 IO_VID_ENC_PWMW
=0x0000;
165 IO_VID_ENC_DCLKPTN0
=0x0001;
167 /* Setup the display */
171 IO_OSD_RECTCUR
=0x0000;
173 IO_OSD_BASEPX
=IO_VID_ENC_HSTART
;
174 IO_OSD_BASEPY
=IO_VID_ENC_VSTART
;
176 addr
= ((int)FRAME
-CONFIG_SDRAM_START
) / 32;
178 /* Setup the OSD windows */
180 /* Used for 565 RGB */
181 IO_OSD_OSDWINMD0
=0x30C0;
183 IO_OSD_OSDWIN0OFST
=LCD_NATIVE_WIDTH
/ 16;
185 IO_OSD_OSDWINADH
=addr
>> 16;
186 IO_OSD_OSDWIN0ADL
=addr
& 0xFFFF;
192 IO_OSD_OSDWIN0XL
=LCD_NATIVE_WIDTH
;
193 IO_OSD_OSDWIN0YL
=LCD_NATIVE_HEIGHT
;
196 IO_OSD_OSDWINMD1
=0x10C0;
198 #if LCD_NATIVE_WIDTH%32!=0
199 IO_OSD_OSDWIN1OFST
=LCD_NATIVE_WIDTH
/ 32+1;
201 IO_OSD_OSDWIN1OFST
=LCD_NATIVE_WIDTH
/ 32;
204 IO_OSD_OSDWIN1ADL
=addr
& 0xFFFF;
209 IO_OSD_OSDWIN1XL
=LCD_NATIVE_WIDTH
;
210 IO_OSD_OSDWIN1YL
=LCD_NATIVE_HEIGHT
;
212 IO_OSD_VIDWINMD
=0x0002;
214 /* This is a bit messy, the LCD transfers appear to happen in chunks of 32
215 * pixels. (based on OF)
217 #if LCD_NATIVE_WIDTH%32!=0
218 IO_OSD_VIDWIN0OFST
=LCD_NATIVE_WIDTH
/ 32+1;
220 IO_OSD_VIDWIN0OFST
=LCD_NATIVE_WIDTH
/ 32;
223 IO_OSD_VIDWINADH
=addr
>> 16;
224 IO_OSD_VIDWIN0ADL
=addr
& 0xFFFF;
229 IO_OSD_VIDWIN0XL
=LCD_NATIVE_WIDTH
;
230 IO_OSD_VIDWIN0YL
=LCD_NATIVE_HEIGHT
;
232 /* Set pin 36 and 35 (LCD POWER and LCD RESOLUTION) to an output */
233 IO_GIO_DIR2
&=!(3<<3);
235 #if LCD_NATIVE_HEIGHT > 320
236 /* Set LCD resolution to VGA */
239 /* Set LCD resolution to QVGA */
243 IO_OSD_OSDWINMD0
|=0x01;
244 IO_VID_ENC_VMOD
|=0x01;
249 /* Update a fraction of the display. */
250 void lcd_update_rect(int x
, int y
, int width
, int height
)
252 register fb_data
*dst
, *src
;
257 if (x
+ width
> LCD_WIDTH
)
258 width
= LCD_WIDTH
- x
; /* Clip right */
260 width
+= x
, x
= 0; /* Clip left */
262 return; /* nothing left to do */
264 if (y
+ height
> LCD_HEIGHT
)
265 height
= LCD_HEIGHT
- y
; /* Clip bottom */
267 height
+= y
, y
= 0; /* Clip top */
269 return; /* nothing left to do */
271 src
= &lcd_framebuffer
[y
][x
];
273 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
274 dst
= (fb_data
*)FRAME
+ LCD_WIDTH
*y
+ x
;
276 /* Copy part of the Rockbox framebuffer to the second framebuffer */
277 if (width
< LCD_WIDTH
)
279 /* Not full width - do line-by-line */
280 lcd_copy_buffer_rect(dst
, src
, width
, height
);
284 /* Full width - copy as one line */
285 lcd_copy_buffer_rect(dst
, src
, LCD_WIDTH
*height
, 1);
288 dst
=FRAME
+ (LCD_NATIVE_WIDTH
*(LCD_NATIVE_HEIGHT
-1))
289 - LCD_NATIVE_WIDTH
*x
+ y
;
293 register int c_width
=width
;
294 register fb_data
*c_dst
=dst
;
298 c_dst
-=LCD_NATIVE_WIDTH
;
301 src
+=LCD_WIDTH
-width
-x
;
308 /* Update the display.
309 This must be called after all other LCD functions that change the display. */
310 void lcd_update(void)
315 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
316 lcd_copy_buffer_rect((fb_data
*)FRAME
, &lcd_framebuffer
[0][0],
317 LCD_WIDTH
*LCD_HEIGHT
, 1);
319 lcd_update_rect(0, 0, LCD_WIDTH
, LCD_HEIGHT
);
323 #if defined(HAVE_LCD_MODES)
324 void lcd_set_mode(int mode
)
326 if(mode
==LCD_MODE_YUV
)
328 /* Turn off the RGB buffer and enable the YUV buffer */
329 IO_OSD_OSDWINMD0
&=~(0x01);
330 IO_OSD_VIDWINMD
|=0x01;
331 memset16(FRAME
, 0x0080, LCD_NATIVE_HEIGHT
*(LCD_NATIVE_WIDTH
+LCD_FUDGE
));
333 else if(mode
==LCD_MODE_RGB565
)
335 /* Turn on the RGB window, set it to 16 bit and turn YUV window off */
336 IO_OSD_VIDWINMD
&=~(0x01);
337 IO_OSD_OSDWIN0OFST
=LCD_NATIVE_WIDTH
/ 16;
338 IO_OSD_OSDWINMD0
|=(1<<13)|0x01;
341 else if(mode
==LCD_MODE_PAL256
)
343 #if LCD_NATIVE_WIDTH%32!=0
344 IO_OSD_OSDWIN0OFST
=LCD_NATIVE_WIDTH
/ 32+1;
346 IO_OSD_OSDWIN0OFST
=LCD_NATIVE_WIDTH
/ 32;
349 IO_OSD_VIDWINMD
&=~(0x01);
350 IO_OSD_OSDWINMD0
&=~(1<<13);
351 IO_OSD_OSDWINMD0
|=0x01;
356 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
357 void lcd_blit_pal256(unsigned char *src
, int src_x
, int src_y
, int x
, int y
,
358 int width
, int height
)
360 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
361 char *dst
=(char *)FRAME
+x
+y
*(LCD_NATIVE_WIDTH
+LCD_FUDGE
);
363 src
=src
+src_x
+src_y
*LCD_NATIVE_WIDTH
;
366 memcpy ( dst
, src
, width
);
368 /* The LCD uses the top 1/4 of the screen when in palette mode */
369 dst
=dst
+width
+(LCD_NATIVE_WIDTH
-x
-width
)+LCD_FUDGE
;
374 char *dst
=(char *)FRAME
375 + (LCD_NATIVE_WIDTH
+LCD_FUDGE
)*(LCD_NATIVE_HEIGHT
-1)
376 - (LCD_NATIVE_WIDTH
+LCD_FUDGE
)*x
+ y
;
378 src
=src
+src_x
+src_y
*LCD_WIDTH
;
381 register char *c_dst
=dst
;
382 register int c_width
=width
;
386 /* The LCD uses the top 1/4 of the screen when in palette mode */
387 c_dst
=c_dst
-(LCD_NATIVE_WIDTH
+LCD_FUDGE
);
390 src
=src
+(LCD_WIDTH
-width
-x
);
396 void lcd_pal256_update_pal(fb_data
*palette
)
399 for(i
=0; i
< 255; i
++)
402 unsigned char r
=RGB_UNPACK_RED_LCD(palette
[i
])<<3;
403 unsigned char g
=RGB_UNPACK_GREEN_LCD(palette
[i
])<<2;
404 unsigned char b
=RGB_UNPACK_BLUE_LCD(palette
[i
])<<3;
406 y
= ((77 * r
+ 150 * g
+ 29 * b
) >> 8);
cb
= ((-43 * r
- 85 * g
+ 128 * b
) >> 8) + 128;
407 cr
= ((128 * r
- 107 * g
- 21 * b
) >> 8) + 128;
409 while(IO_OSD_MISCCTL
&0x08)
412 /* Write in y and cb */
413 IO_OSD_CLUTRAMYCB
= ((unsigned char)y
<< 8) | (unsigned char)cb
;
415 /* Write in the index and cr */
416 IO_OSD_CLUTRAMCR
=((unsigned char)cr
<< 8) | i
;
421 void lcd_blit_yuv(unsigned char * const src
[3],
422 int src_x
, int src_y
, int stride
,
423 int x
, int y
, int width
,
424 int height
) __attribute__ ((section(".icode")));
426 /* Performance function to blit a YUV bitmap directly to the LCD */
427 /* Show it rotated so the LCD_WIDTH is now the height */
428 void lcd_blit_yuv(unsigned char * const src
[3],
429 int src_x
, int src_y
, int stride
,
430 int x
, int y
, int width
, int height
)
432 /* Caches for chroma data so it only need be recaculated every other
434 unsigned char const * yuv_src
[3];
440 /* y has to be at multiple of 2 or else it will mess up the HW
445 if(y
<0 || y
>LCD_NATIVE_HEIGHT
|| x
<0 || x
>LCD_NATIVE_WIDTH
446 || height
<0 || width
<0)
451 if(y
+height
>LCD_NATIVE_WIDTH
)
453 height
=LCD_NATIVE_WIDTH
-y
;
455 if(x
+width
>LCD_NATIVE_HEIGHT
)
457 width
=LCD_NATIVE_HEIGHT
-x
;
460 /* Sorry, but width and height must be >= 2 or else */
464 fb_data
* dst
= FRAME
+ ((LCD_NATIVE_WIDTH
+LCD_FUDGE
)*(LCD_NATIVE_HEIGHT
-1))
465 - (LCD_NATIVE_WIDTH
+LCD_FUDGE
)*x
+ y
;
468 yuv_src
[0] = src
[0] + z
+ src_x
;
469 yuv_src
[1] = src
[1] + (z
>> 2) + (src_x
>> 1);
470 yuv_src
[2] = src
[2] + (yuv_src
[1] - src
[1]);
475 register fb_data
*c_dst
=dst
;
476 register int c_width
=width
;
477 unsigned char const * c_yuv_src
[3];
478 c_yuv_src
[0] = yuv_src
[0];
479 c_yuv_src
[1] = yuv_src
[1];
480 c_yuv_src
[2] = yuv_src
[2];
484 /* This needs to be done in a block of 4 pixels */
485 *c_dst
=*c_yuv_src
[0]<<8 | *c_yuv_src
[1];
486 *(c_dst
+1)=*(c_yuv_src
[0]+stride
)<<8 | *c_yuv_src
[2];
487 c_dst
-=(LCD_NATIVE_WIDTH
+LCD_FUDGE
);
489 *c_dst
=*c_yuv_src
[0]<<8 | *c_yuv_src
[1];
490 *(c_dst
+1)=*(c_yuv_src
[0]+stride
)<<8 | *c_yuv_src
[2];
491 c_dst
-=(LCD_NATIVE_WIDTH
+LCD_FUDGE
);
501 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
502 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
503 yuv_src
[2] += stride
>> 1;
506 while (--height
> 0);
510 void lcd_set_contrast(int val
) {
515 void lcd_set_invert_display(bool yesno
) {
520 void lcd_set_flip(bool yesno
) {