M:Robe 500: Move all remote specific code into a common file for reuse on other playe...
[kugel-rb.git] / firmware / target / arm / tms320dm320 / mrobe-500 / lcd-mr500.c
blobec85821649c7fb91269cb37b204bfeb66a9931d6
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 /* This is a bit messy, the LCD transfers appear to happen in chunks of 32
213 * pixels. (based on OF)
215 #if LCD_NATIVE_WIDTH%32!=0
216 IO_OSD_VIDWIN0OFST=LCD_NATIVE_WIDTH / 32+1;
217 #else
218 IO_OSD_VIDWIN0OFST=LCD_NATIVE_WIDTH / 32;
219 #endif
221 IO_OSD_VIDWINADH=addr >> 16;
222 IO_OSD_VIDWIN0ADL=addr & 0xFFFF;
224 IO_OSD_VIDWIN0XP=0;
225 IO_OSD_VIDWIN0YP=0;
227 IO_OSD_VIDWIN0XL=LCD_NATIVE_WIDTH;
228 IO_OSD_VIDWIN0YL=LCD_NATIVE_HEIGHT;
230 /* Set pin 36 and 35 (LCD POWER and LCD RESOLUTION) to an output */
231 IO_GIO_DIR2&=!(3<<3);
233 #if LCD_NATIVE_HEIGHT > 320
234 /* Set LCD resolution to VGA */
235 IO_GIO_BITSET2=1<<3;
236 #else
237 /* Set LCD resolution to QVGA */
238 IO_GIO_BITCLR2=1<<3;
239 #endif
241 IO_OSD_OSDWINMD0|=0x01;
242 IO_VID_ENC_VMOD|=0x01;
245 /* Update a fraction of the display. */
246 void lcd_update_rect(int x, int y, int width, int height)
248 register fb_data *dst, *src;
250 if (!lcd_on)
251 return;
253 if ( (width | height) < 0)
254 return; /* nothing left to do */
256 if (x + width > LCD_WIDTH)
257 width = LCD_WIDTH - x; /* Clip right */
258 if (x < 0)
259 width += x, x = 0; /* Clip left */
261 if (y + height > LCD_HEIGHT)
262 height = LCD_HEIGHT - y; /* Clip bottom */
263 if (y < 0)
264 height += y, y = 0; /* Clip top */
267 src = &lcd_framebuffer[y][x];
269 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
270 dst = (fb_data *)FRAME + LCD_WIDTH*y + x;
272 /* Copy part of the Rockbox framebuffer to the second framebuffer */
273 if (width < LCD_WIDTH)
275 /* Not full width - do line-by-line */
276 lcd_copy_buffer_rect(dst, src, width, height);
278 else
280 /* Full width - copy as one line */
281 lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1);
283 #else
284 dst=FRAME + (LCD_NATIVE_WIDTH*(LCD_NATIVE_HEIGHT-1))
285 - LCD_NATIVE_WIDTH*x + y ;
287 while(height--)
289 register int c_width=width;
290 register fb_data *c_dst=dst;
292 while(c_width--)
294 *c_dst=*src++;
295 c_dst-=LCD_NATIVE_WIDTH;
298 src+=LCD_WIDTH-width;
299 dst++;
302 #endif
305 /* Update the display.
306 This must be called after all other LCD functions that change the display. */
307 void lcd_update(void)
309 if (!lcd_on)
310 return;
312 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
313 lcd_copy_buffer_rect((fb_data *)FRAME, &lcd_framebuffer[0][0],
314 LCD_WIDTH*LCD_HEIGHT, 1);
315 #else
316 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
317 #endif
320 #if defined(HAVE_LCD_MODES)
321 void lcd_set_mode(int mode)
323 if(mode==LCD_MODE_YUV)
325 /* Turn off the RGB buffer and enable the YUV buffer */
326 IO_OSD_OSDWINMD0 &=~(0x01);
327 IO_OSD_VIDWINMD |=0x01;
328 memset16(FRAME, 0x0080, LCD_NATIVE_HEIGHT*(LCD_NATIVE_WIDTH+LCD_FUDGE));
330 else if(mode==LCD_MODE_RGB565)
332 /* Turn on the RGB window, set it to 16 bit and turn YUV window off */
333 IO_OSD_VIDWINMD &=~(0x01);
334 IO_OSD_OSDWIN0OFST=LCD_NATIVE_WIDTH / 16;
335 IO_OSD_OSDWINMD0 |=(1<<13)|0x01;
336 lcd_clear_display();
338 else if(mode==LCD_MODE_PAL256)
340 #if LCD_NATIVE_WIDTH%32!=0
341 IO_OSD_OSDWIN0OFST=LCD_NATIVE_WIDTH / 32+1;
342 #else
343 IO_OSD_OSDWIN0OFST=LCD_NATIVE_WIDTH / 32;
344 #endif
346 IO_OSD_VIDWINMD &=~(0x01);
347 IO_OSD_OSDWINMD0 &=~(1<<13);
348 IO_OSD_OSDWINMD0 |=0x01;
351 #endif
353 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
354 void lcd_blit_pal256(unsigned char *src, int src_x, int src_y, int x, int y,
355 int width, int height)
357 #if CONFIG_ORIENTATION == SCREEN_PORTRAIT
358 char *dst=(char *)FRAME+x+y*(LCD_NATIVE_WIDTH+LCD_FUDGE);
360 src=src+src_x+src_y*LCD_NATIVE_WIDTH;
361 while(height--);
363 memcpy ( dst, src, width);
365 dst=dst+width+(LCD_NATIVE_WIDTH-x-width)+LCD_FUDGE;
366 src+=width;
369 #else
370 char *dst=(char *)FRAME
371 + (LCD_NATIVE_WIDTH+LCD_FUDGE)*(LCD_NATIVE_HEIGHT-1)
372 - (LCD_NATIVE_WIDTH+LCD_FUDGE)*x + y;
374 src=src+src_x+src_y*LCD_WIDTH;
375 while(height--)
377 register char *c_dst=dst;
378 register int c_width=width;
380 while (c_width--)
382 *c_dst=*src++;
383 c_dst=c_dst-(LCD_NATIVE_WIDTH+LCD_FUDGE);
386 dst++;
387 src+=LCD_WIDTH-width;
389 #endif
392 void lcd_pal256_update_pal(fb_data *palette)
394 unsigned char i;
395 for(i=0; i< 255; i++)
397 int y, cb, cr;
398 unsigned char r=RGB_UNPACK_RED_LCD(palette[i])<<3;
399 unsigned char g=RGB_UNPACK_GREEN_LCD(palette[i])<<2;
400 unsigned char b=RGB_UNPACK_BLUE_LCD(palette[i])<<3;
402 y = ((77 * r + 150 * g + 29 * b) >> 8); cb = ((-43 * r - 85 * g + 128 * b) >> 8) + 128;
403 cr = ((128 * r - 107 * g - 21 * b) >> 8) + 128;
405 while(IO_OSD_MISCCTL&0x08)
408 /* Write in y and cb */
409 IO_OSD_CLUTRAMYCB= ((unsigned char)y << 8) | (unsigned char)cb;
411 /* Write in the index and cr */
412 IO_OSD_CLUTRAMCR=((unsigned char)cr << 8) | i;
415 #endif
417 void lcd_blit_yuv(unsigned char * const src[3],
418 int src_x, int src_y, int stride,
419 int x, int y, int width,
420 int height) __attribute__ ((section(".icode")));
422 /* Performance function to blit a YUV bitmap directly to the LCD */
423 /* Show it rotated so the LCD_WIDTH is now the height */
424 void lcd_blit_yuv(unsigned char * const src[3],
425 int src_x, int src_y, int stride,
426 int x, int y, int width, int height)
428 /* Caches for chroma data so it only need be recaculated every other
429 line */
430 unsigned char const * yuv_src[3];
431 off_t z;
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 = FRAME + ((LCD_NATIVE_WIDTH+LCD_FUDGE)*(LCD_NATIVE_HEIGHT-1))
459 - (LCD_NATIVE_WIDTH+LCD_FUDGE)*x + y ;
461 z = stride*src_y;
462 yuv_src[0] = src[0] + z + src_x;
463 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
464 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
469 register fb_data *c_dst=dst;
470 register int c_width=width;
471 unsigned char const * c_yuv_src[3];
472 c_yuv_src[0] = yuv_src[0];
473 c_yuv_src[1] = yuv_src[1];
474 c_yuv_src[2] = yuv_src[2];
478 /* This needs to be done in a block of 4 pixels */
479 *c_dst=*c_yuv_src[0]<<8 | *c_yuv_src[1];
480 *(c_dst+1)=*(c_yuv_src[0]+stride)<<8 | *c_yuv_src[2];
481 c_dst-=(LCD_NATIVE_WIDTH+LCD_FUDGE);
482 c_yuv_src[0]++;
483 *c_dst=*c_yuv_src[0]<<8 | *c_yuv_src[1];
484 *(c_dst+1)=*(c_yuv_src[0]+stride)<<8 | *c_yuv_src[2];
485 c_dst-=(LCD_NATIVE_WIDTH+LCD_FUDGE);
486 c_yuv_src[0]++;
488 c_yuv_src[1]++;
489 c_yuv_src[2]++;
491 c_width -= 2;
493 while (c_width > 0);
495 yuv_src[0] += stride << 1; /* Skip down two luma lines */
496 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
497 yuv_src[2] += stride >> 1;
498 dst+=2;
500 while (--height > 0);
504 void lcd_set_contrast(int val) {
505 (void) val;
506 // TODO:
509 void lcd_set_invert_display(bool yesno) {
510 (void) yesno;
511 // TODO:
514 void lcd_set_flip(bool yesno) {
515 (void) yesno;
516 // TODO: