M:Robe 500: More LCD initialization, QVGA (vs. VGA) is now enabled by default for...
[kugel-rb.git] / firmware / target / arm / tms320dm320 / mrobe-500 / lcd-mr500.c
blob1334eeaf8d22a2268ee18585b24aa075761235cc
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
25 #include "config.h"
26 #include "cpu.h"
27 #include "string.h"
28 #include "lcd.h"
29 #include "kernel.h"
30 #include "memory.h"
31 #include "system-target.h"
32 #include "lcd.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;
44 #endif
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)
53 bool lcd_active(void)
55 return lcd_on;
57 #endif
59 #if defined(HAVE_LCD_SLEEP)
60 void lcd_sleep()
62 if (lcd_powered)
64 /* "not powered" implies "disabled" */
65 if (lcd_on)
66 lcd_enable(false);
68 /* Disabling these saves another ~15mA */
69 IO_OSD_OSDWINMD0&=~(0x01);
70 IO_VID_ENC_VMOD&=~(0x01);
72 sleep(HZ/5);
74 /* Disabling the LCD saves ~50mA */
75 IO_GIO_BITCLR2=1<<4;
76 lcd_powered=false;
79 #endif
81 #if defined(HAVE_LCD_ENABLE)
82 void lcd_enable(bool state)
84 if (state == lcd_on)
85 return;
87 if(state)
89 /* "enabled" implies "powered" */
90 if (!lcd_powered)
92 lcd_powered=true;
94 IO_OSD_OSDWINMD0|=0x01;
95 IO_VID_ENC_VMOD|=0x01;
97 sleep(2);
98 IO_GIO_BITSET2=1<<4;
99 /* Wait long enough for a frame to be written - yes, it
100 * takes awhile. */
101 sleep(HZ/5);
104 lcd_on = true;
105 lcd_update();
106 lcd_activation_call_hook();
108 else
110 lcd_on = false;
113 #endif
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)
125 unsigned int addr;
127 /* Clear the Frame */
128 memset16(FRAME, 0x0000, LCD_WIDTH*LCD_HEIGHT);
130 lcd_sleep();
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;
148 IO_VID_ENC_VSTART=3;
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 */
168 IO_OSD_MODE=0x00ff;
170 IO_OSD_ATRMD=0x0000;
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;
188 IO_OSD_OSDWIN0XP=0;
189 IO_OSD_OSDWIN0YP=0;
191 /* read from OF */
192 IO_OSD_OSDWIN0XL=LCD_NATIVE_WIDTH;
193 IO_OSD_OSDWIN0YL=LCD_NATIVE_HEIGHT;
195 /* Unused */
196 IO_OSD_OSDWINMD1=0x10C0;
198 #if LCD_NATIVE_WIDTH%32!=0
199 IO_OSD_OSDWIN1OFST=LCD_NATIVE_WIDTH / 32+1;
200 #else
201 IO_OSD_OSDWIN1OFST=LCD_NATIVE_WIDTH / 32;
202 #endif
204 IO_OSD_OSDWIN1ADL=addr & 0xFFFF;
206 IO_OSD_OSDWIN1XP=0;
207 IO_OSD_OSDWIN1YP=0;
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;
219 #else
220 IO_OSD_VIDWIN0OFST=LCD_NATIVE_WIDTH / 32;
221 #endif
223 IO_OSD_VIDWINADH=addr >> 16;
224 IO_OSD_VIDWIN0ADL=addr & 0xFFFF;
226 IO_OSD_VIDWIN0XP=0;
227 IO_OSD_VIDWIN0YP=0;
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 */
237 IO_GIO_BITSET2=1<<3;
238 #else
239 /* Set LCD resolution to QVGA */
240 IO_GIO_BITCLR2=1<<3;
241 #endif
243 IO_OSD_OSDWINMD0|=0x01;
244 IO_VID_ENC_VMOD|=0x01;
246 lcd_enable(true);
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;
254 if (!lcd_on)
255 return;
257 if (x + width > LCD_WIDTH)
258 width = LCD_WIDTH - x; /* Clip right */
259 if (x < 0)
260 width += x, x = 0; /* Clip left */
261 if (width <= 0)
262 return; /* nothing left to do */
264 if (y + height > LCD_HEIGHT)
265 height = LCD_HEIGHT - y; /* Clip bottom */
266 if (y < 0)
267 height += y, y = 0; /* Clip top */
268 if (height <= 0)
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);
282 else
284 /* Full width - copy as one line */
285 lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1);
287 #else
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;
297 *c_dst=*src++;
298 c_dst-=LCD_NATIVE_WIDTH;
300 while(--c_width);
301 src+=LCD_WIDTH-width-x;
302 dst++;
304 while(--height);
305 #endif
308 /* Update the display.
309 This must be called after all other LCD functions that change the display. */
310 void lcd_update(void)
312 if (!lcd_on)
313 return;
315 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
316 lcd_copy_buffer_rect((fb_data *)FRAME, &lcd_framebuffer[0][0],
317 LCD_WIDTH*LCD_HEIGHT, 1);
318 #else
319 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
320 #endif
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;
339 lcd_clear_display();
341 else if(mode==LCD_MODE_PAL256)
343 #if LCD_NATIVE_WIDTH%32!=0
344 IO_OSD_OSDWIN0OFST=LCD_NATIVE_WIDTH / 32+1;
345 #else
346 IO_OSD_OSDWIN0OFST=LCD_NATIVE_WIDTH / 32;
347 #endif
349 IO_OSD_VIDWINMD &=~(0x01);
350 IO_OSD_OSDWINMD0 &=~(1<<13);
351 IO_OSD_OSDWINMD0 |=0x01;
354 #endif
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;
370 src+=width;
372 while(--height);
373 #else
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;
385 *c_dst=*src++;
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);
388 } while (--c_width);
389 dst++;
390 src=src+(LCD_WIDTH-width-x);
392 while(--height);
393 #endif
396 void lcd_pal256_update_pal(fb_data *palette)
398 unsigned char i;
399 for(i=0; i< 255; i++)
401 int y, cb, cr;
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;
419 #endif
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
433 line */
434 unsigned char const * yuv_src[3];
435 off_t z;
437 if (!lcd_on)
438 return;
440 /* y has to be at multiple of 2 or else it will mess up the HW
441 * (interleaving)
443 y &= ~1;
445 if(y<0 || y>LCD_NATIVE_HEIGHT || x<0 || x>LCD_NATIVE_WIDTH
446 || height<0 || width <0)
448 return;
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 */
461 width &= ~1;
462 height>>=1;
464 fb_data * dst = FRAME + ((LCD_NATIVE_WIDTH+LCD_FUDGE)*(LCD_NATIVE_HEIGHT-1))
465 - (LCD_NATIVE_WIDTH+LCD_FUDGE)*x + y ;
467 z = stride*src_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);
488 c_yuv_src[0]++;
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);
492 c_yuv_src[0]++;
494 c_yuv_src[1]++;
495 c_yuv_src[2]++;
497 c_width -= 2;
499 while (c_width > 0);
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;
504 dst+=2;
506 while (--height > 0);
510 void lcd_set_contrast(int val) {
511 (void) val;
512 // TODO:
515 void lcd_set_invert_display(bool yesno) {
516 (void) yesno;
517 // TODO:
520 void lcd_set_flip(bool yesno) {
521 (void) yesno;
522 // TODO: