Add second buffer for YUV blitting, progressbar and FPS display in mpegplayer work...
[kugel-rb.git] / firmware / target / arm / tms320dm320 / mrobe-500 / lcd-mr500.c
blobe26a88704d214050268f4bceacde6add4c6951d4
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 IO_OSD_OSDWINMD0&=~(0x0001);
131 IO_OSD_VIDWINMD&=~(0x0001);
133 /* Setup the LCD controller */
134 IO_VID_ENC_VMOD=0x2014;
135 IO_VID_ENC_VDCTL=0x2000;
136 IO_VID_ENC_VDPRO=0x0000;
137 IO_VID_ENC_SYNCTL=0x100E;
138 IO_VID_ENC_HSPLS=1; /* HSYNC pulse width */
139 IO_VID_ENC_VSPLS=1; /* VSYNC pulse width */
141 /* These calculations support 640x480 and 320x240 (based on OF) */
142 IO_VID_ENC_HINT=LCD_NATIVE_WIDTH+LCD_NATIVE_WIDTH/3;
143 IO_VID_ENC_HSTART=LCD_NATIVE_WIDTH/6; /* Front porch */
144 IO_VID_ENC_HVALID=LCD_NATIVE_WIDTH; /* Data valid */
145 IO_VID_ENC_VINT=LCD_NATIVE_HEIGHT+7;
146 IO_VID_ENC_VSTART=3;
147 IO_VID_ENC_VVALID=LCD_NATIVE_HEIGHT;
149 IO_VID_ENC_HSDLY=0x0000;
150 IO_VID_ENC_VSDLY=0x0000;
151 IO_VID_ENC_YCCTL=0x0000;
152 IO_VID_ENC_RGBCTL=0x0000;
153 IO_VID_ENC_RGBCLP=0xFF00;
154 IO_VID_ENC_LNECTL=0x0000;
155 IO_VID_ENC_CULLLNE=0x0000;
156 IO_VID_ENC_LCDOUT=0x0000;
157 IO_VID_ENC_BRTS=0x0000;
158 IO_VID_ENC_BRTW=0x0000;
159 IO_VID_ENC_ACCTL=0x0000;
160 IO_VID_ENC_PWMP=0x0000;
161 IO_VID_ENC_PWMW=0x0000;
163 IO_VID_ENC_DCLKPTN0=0x0001;
165 /* Setup the display */
166 IO_OSD_MODE=0x00ff;
168 IO_OSD_ATRMD=0x0000;
169 IO_OSD_RECTCUR=0x0000;
171 IO_OSD_BASEPX=IO_VID_ENC_HSTART;
172 IO_OSD_BASEPY=IO_VID_ENC_VSTART;
174 addr = ((int)FRAME-CONFIG_SDRAM_START) / 32;
176 /* Setup the OSD windows */
178 /* Used for 565 RGB */
179 IO_OSD_OSDWINMD0=0x30C0;
181 IO_OSD_OSDWIN0OFST=LCD_NATIVE_WIDTH / 16;
183 IO_OSD_OSDWINADH=addr >> 16;
184 IO_OSD_OSDWIN0ADL=addr & 0xFFFF;
186 IO_OSD_OSDWIN0XP=0;
187 IO_OSD_OSDWIN0YP=0;
189 /* read from OF */
190 IO_OSD_OSDWIN0XL=LCD_NATIVE_WIDTH;
191 IO_OSD_OSDWIN0YL=LCD_NATIVE_HEIGHT;
193 /* Unused */
194 IO_OSD_OSDWINMD1=0x10C0;
196 #if LCD_NATIVE_WIDTH%32!=0
197 IO_OSD_OSDWIN1OFST=LCD_NATIVE_WIDTH / 32+1;
198 #else
199 IO_OSD_OSDWIN1OFST=LCD_NATIVE_WIDTH / 32;
200 #endif
202 IO_OSD_OSDWIN1ADL=addr & 0xFFFF;
204 IO_OSD_OSDWIN1XP=0;
205 IO_OSD_OSDWIN1YP=0;
207 IO_OSD_OSDWIN1XL=LCD_NATIVE_WIDTH;
208 IO_OSD_OSDWIN1YL=LCD_NATIVE_HEIGHT;
210 IO_OSD_VIDWINMD=0x0002;
212 addr = ((int)FRAME2-CONFIG_SDRAM_START) / 32;
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;
247 #if defined(HAVE_LCD_MODES)
248 void lcd_set_mode(int mode)
250 if(mode==LCD_MODE_YUV)
252 /* Turn off the RGB buffer and enable the YUV buffer */
253 IO_OSD_OSDWINMD0 |=0x04;
254 IO_OSD_VIDWINMD |=0x01;
255 memset16(FRAME2, 0x0080, LCD_NATIVE_HEIGHT*(LCD_NATIVE_WIDTH+LCD_FUDGE));
257 else if(mode==LCD_MODE_RGB565)
259 /* Turn on the RGB window, set it to 16 bit and turn YUV window off */
260 IO_OSD_VIDWINMD &=~(0x01);
261 IO_OSD_OSDWIN0OFST=LCD_NATIVE_WIDTH / 16;
262 IO_OSD_OSDWINMD0 |=(1<<13);
263 IO_OSD_OSDWINMD0 &=~0x04;
264 lcd_clear_display();
266 else if(mode==LCD_MODE_PAL256)
268 #if LCD_NATIVE_WIDTH%32!=0
269 IO_OSD_OSDWIN0OFST=LCD_NATIVE_WIDTH / 32+1;
270 #else
271 IO_OSD_OSDWIN0OFST=LCD_NATIVE_WIDTH / 32;
272 #endif
274 IO_OSD_VIDWINMD &=~(0x01);
275 IO_OSD_OSDWINMD0 &=~(1<<13);
276 IO_OSD_OSDWINMD0 |=0x01;
279 #endif
281 /* Update a fraction of the display. */
282 void lcd_update_rect(int x, int y, int width, int height)
284 register fb_data *dst, *src;
286 if (!lcd_on)
287 return;
289 if ( (width | height) < 0)
290 return; /* nothing left to do */
292 if (x + width > LCD_WIDTH)
293 width = LCD_WIDTH - x; /* Clip right */
294 if (x < 0)
295 width += x, x = 0; /* Clip left */
297 if (y + height > LCD_HEIGHT)
298 height = LCD_HEIGHT - y; /* Clip bottom */
299 if (y < 0)
300 height += y, y = 0; /* Clip top */
303 src = &lcd_framebuffer[y][x];
305 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
306 dst = (fb_data *)FRAME + LCD_WIDTH*y + x;
308 /* Copy part of the Rockbox framebuffer to the second framebuffer */
309 if (width < LCD_WIDTH)
311 /* Not full width - do line-by-line */
312 lcd_copy_buffer_rect(dst, src, width, height);
314 else
316 /* Full width - copy as one line */
317 lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1);
319 #else
320 dst=FRAME + (LCD_NATIVE_WIDTH*(LCD_NATIVE_HEIGHT-1))
321 - LCD_NATIVE_WIDTH*x + y ;
323 while(height--)
325 register int c_width=width;
326 register fb_data *c_dst=dst;
328 while(c_width--)
330 *c_dst=*src++;
331 c_dst-=LCD_NATIVE_WIDTH;
334 src+=LCD_WIDTH-width;
335 dst++;
338 #endif
341 /* Update the display.
342 This must be called after all other LCD functions that change the display. */
343 void lcd_update(void)
345 if (!lcd_on)
346 return;
348 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
349 lcd_copy_buffer_rect((fb_data *)FRAME, &lcd_framebuffer[0][0],
350 LCD_WIDTH*LCD_HEIGHT, 1);
351 #else
352 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
353 #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;
364 while(height--);
366 memcpy ( dst, src, width);
368 dst=dst+(LCD_NATIVE_WIDTH-x+LCD_FUDGE);
369 src+=width;
372 #else
373 char *dst=(char *)FRAME
374 + (LCD_NATIVE_WIDTH+LCD_FUDGE)*(LCD_NATIVE_HEIGHT-1)
375 - (LCD_NATIVE_WIDTH+LCD_FUDGE)*x + y;
377 src=src+src_x+src_y*LCD_WIDTH;
378 while(height--)
380 register char *c_dst=dst;
381 register int c_width=width;
383 while (c_width--)
385 *c_dst=*src++;
386 c_dst=c_dst-(LCD_NATIVE_WIDTH+LCD_FUDGE);
389 dst++;
390 src+=LCD_WIDTH-width;
392 #endif
395 void lcd_pal256_update_pal(fb_data *palette)
397 unsigned char i;
398 for(i=0; i< 255; i++)
400 int y, cb, cr;
401 unsigned char r=RGB_UNPACK_RED_LCD(palette[i])<<3;
402 unsigned char g=RGB_UNPACK_GREEN_LCD(palette[i])<<2;
403 unsigned char b=RGB_UNPACK_BLUE_LCD(palette[i])<<3;
405 y = ((77 * r + 150 * g + 29 * b) >> 8); cb = ((-43 * r - 85 * g + 128 * b) >> 8) + 128;
406 cr = ((128 * r - 107 * g - 21 * b) >> 8) + 128;
408 while(IO_OSD_MISCCTL&0x08)
411 /* Write in y and cb */
412 IO_OSD_CLUTRAMYCB= ((unsigned char)y << 8) | (unsigned char)cb;
414 /* Write in the index and cr */
415 IO_OSD_CLUTRAMCR=((unsigned char)cr << 8) | i;
418 #endif
420 void lcd_blit_yuv(unsigned char * const src[3],
421 int src_x, int src_y, int stride,
422 int x, int y, int width,
423 int height) __attribute__ ((section(".icode")));
425 /* Performance function to blit a YUV bitmap directly to the LCD */
426 /* Show it rotated so the LCD_WIDTH is now the height */
427 void lcd_blit_yuv(unsigned char * const src[3],
428 int src_x, int src_y, int stride,
429 int x, int y, int width, int height)
431 register unsigned char const * yuv_src[3];
433 if (!lcd_on)
434 return;
436 /* y has to be at multiple of 2 or else it will mess up the HW
437 * (interleaving)
439 y &= ~1;
441 if( ((y | x | height | width ) < 0)
442 || y>LCD_NATIVE_HEIGHT || x>LCD_NATIVE_WIDTH )
443 return;
445 if(y+height>LCD_NATIVE_WIDTH)
447 height=LCD_NATIVE_WIDTH-y;
449 if(x+width>LCD_NATIVE_HEIGHT)
451 width=LCD_NATIVE_HEIGHT-x;
454 /* Sorry, but width and height must be >= 2 or else */
455 width &= ~1;
456 height>>=1;
458 fb_data * dst = FRAME2
459 + ((LCD_NATIVE_WIDTH+LCD_FUDGE)*(LCD_NATIVE_HEIGHT-1))
460 - (LCD_NATIVE_WIDTH+LCD_FUDGE)*x + y ;
462 /* Scope z */
464 off_t z;
465 z = stride*src_y;
466 yuv_src[0] = src[0] + z + src_x;
467 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
468 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
471 register int cbcr_remain=(stride>>1)-(width>>1);
472 register int y_remain=(stride<<1)-width;
475 register fb_data *c_dst=dst;
476 register int c_width=width;
480 /* This needs to be done in a block of 4 pixels */
482 *c_dst=*yuv_src[0]<<8 | *yuv_src[1];
483 *(c_dst+1)=*(yuv_src[0]+stride)<<8 | *yuv_src[2];
484 c_dst-=(LCD_NATIVE_WIDTH+LCD_FUDGE);
486 yuv_src[0]++;
488 *c_dst=*yuv_src[0]<<8 | *yuv_src[1];
489 *(c_dst+1)=*(yuv_src[0]+stride)<<8 | *yuv_src[2];
490 c_dst-=(LCD_NATIVE_WIDTH+LCD_FUDGE);
492 yuv_src[0]++;
494 yuv_src[1]++;
495 yuv_src[2]++;
497 c_width -= 2;
499 while (c_width > 0);
501 yuv_src[0] += y_remain; /* Skip down two luma lines-width */
502 yuv_src[1] += cbcr_remain; /* Skip down one chroma line-width/2 */
503 yuv_src[2] += cbcr_remain;
504 dst+=2;
506 while (--height > 0);
509 void lcd_set_contrast(int val) {
510 (void) val;
511 // TODO:
514 void lcd_set_invert_display(bool yesno) {
515 (void) yesno;
516 // TODO:
519 void lcd_set_flip(bool yesno) {
520 (void) yesno;
521 // TODO: