1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2008 by Mark Arigo
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 ****************************************************************************/
29 /* The LCD registers appear to match controllers from Leadis Technology,
30 either the LDS176 (132x132 4k) or the LDS186 (128x160 65k).
31 These defines are from the LDS176 (I couldn't find the LDS186 datasheet. */
81 static unsigned lcd_yuv_options SHAREDBSS_ATTR
= 0;
82 static unsigned mad_ctrl
= 0;
85 static inline void lcd_wait_write(void)
88 while (LCD2_PORT
& LCD2_BUSY_MASK
)
93 LCD2_PORT
&= ~LCD2_BUSY_MASK
;
98 static void lcd_send_data(unsigned data
)
101 LCD2_PORT
= LCD2_DATA_MASK
| (data
& 0xff);
104 /* send LCD command */
105 static void lcd_send_cmd(unsigned cmd
)
108 LCD2_PORT
= LCD2_CMD_MASK
| (cmd
& 0xff);
112 static inline void lcd_send_pixel(unsigned pixel
)
114 lcd_send_data(pixel
>> 8);
115 lcd_send_data(pixel
);
118 void lcd_init_device(void)
121 /* this sequence from the OF bootloader */
124 outl(inl(0x70000014) & ~0xf000000, 0x70000014);
125 outl(inl(0x70000014) | 0xa000000, 0x70000014);
128 MLCD_SCLK_DIV
&= ~0x800;
129 CLCD_CLOCK_SRC
|= 0xc0000000;
131 outl(inl(0x7000002c) | ((1<<4)<<24), 0x7000002c);
132 DEV_INIT2
&= ~((1<<4)<<24);
135 DEV_INIT2
|= ((1<<4)<<24);
136 outl(0x220, 0x70008a00);
137 outl(0x1f00, 0x70008a04);
138 LCD2_BLOCK_CTRL
= 0x10008080;
139 LCD2_BLOCK_CONFIG
= 0xF00000;
143 GPIOJ_OUTPUT_VAL
|= 0x4;
144 GPIOJ_OUTPUT_EN
|= 0x4;
146 lcd_send_cmd(SWRESET
);
149 lcd_send_cmd(WRCNTR
);
152 lcd_send_cmd(SLPOUT
);
155 lcd_send_cmd(INVOFF
);
156 lcd_send_cmd(IDMOFF
);
159 lcd_send_cmd(FRMSEL
);
165 lcd_send_cmd(FRM8SEL
);
171 lcd_send_cmd(TMPRNG
);
176 lcd_send_cmd(TMPHIS
);
179 lcd_send_cmd(DISCTR
);
183 lcd_send_cmd(MADCTR
);
187 lcd_send_cmd(COLMOD
);
190 lcd_send_cmd(RGBSET
);
240 lcd_send_cmd(DISPON
);
244 /*** hardware configuration ***/
245 int lcd_default_contrast(void)
247 return DEFAULT_CONTRAST_SETTING
;
250 void lcd_set_contrast(int val
)
252 lcd_send_cmd(WRCNTR
);
256 void lcd_set_invert_display(bool yesno
)
261 lcd_send_cmd(INVOFF
);
264 /* turn the display upside down (call lcd_update() afterwards) */
265 void lcd_set_flip(bool yesno
)
268 mad_ctrl
|= ((1<<7) | (1<<6)); /* flip */
270 mad_ctrl
&= ~((1<<7) | (1<<6)); /* normal */
272 lcd_send_cmd(MADCTR
);
273 lcd_send_data(mad_ctrl
);
276 void lcd_yuv_set_options(unsigned options
)
278 lcd_yuv_options
= options
;
281 /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
282 extern void lcd_write_yuv420_lines(unsigned char const * const src
[3],
283 int width
, int stride
);
285 extern void lcd_write_yuv420_lines_odither(unsigned char const * const src
[3],
286 int width
, int stride
,
287 int x_screen
, int y_screen
);
289 /* Performance function to blit a YUV bitmap directly to the LCD */
290 void lcd_blit_yuv(unsigned char * const src
[3],
291 int src_x
, int src_y
, int stride
,
292 int x
, int y
, int width
, int height
)
294 unsigned char const * yuv_src
[3];
297 /* Sorry, but width and height must be >= 2 or else */
302 yuv_src
[0] = src
[0] + z
+ src_x
;
303 yuv_src
[1] = src
[1] + (z
>> 2) + (src_x
>> 1);
304 yuv_src
[2] = src
[2] + (yuv_src
[1] - src
[1]);
306 /* Set vertical address mode */
307 lcd_send_cmd(MADCTR
);
308 lcd_send_data(mad_ctrl
| (1<<5));
312 lcd_send_data(x
+ width
- 1);
314 if (lcd_yuv_options
& LCD_YUV_DITHER
)
320 lcd_send_data(y
+ 1);
324 lcd_write_yuv420_lines_odither(yuv_src
, width
, stride
, x
, y
);
325 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
326 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
327 yuv_src
[2] += stride
>> 1;
330 while (--height
> 0);
338 lcd_send_data(y
+ 1);
342 lcd_write_yuv420_lines(yuv_src
, width
, stride
);
343 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
344 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
345 yuv_src
[2] += stride
>> 1;
348 while (--height
> 0);
351 /* Restore the address mode */
352 lcd_send_cmd(MADCTR
);
353 lcd_send_data(mad_ctrl
);
356 /* Update the display.
357 This must be called after all other LCD functions that change the display. */
358 void lcd_update(void)
360 lcd_update_rect(0, 0, LCD_WIDTH
, LCD_HEIGHT
);
363 /* Update a fraction of the display. */
364 void lcd_update_rect(int x
, int y
, int width
, int height
)
368 if (x
+ width
>= LCD_WIDTH
)
369 width
= LCD_WIDTH
- x
;
370 if (y
+ height
>= LCD_HEIGHT
)
371 height
= LCD_HEIGHT
- y
;
373 if ((width
<= 0) || (height
<= 0))
374 return; /* Nothing left to do. */
376 addr
= &lcd_framebuffer
[y
][x
];
380 lcd_send_data(x
+ width
- 1);
384 lcd_send_data(y
+ height
- 1);
390 lcd_send_pixel(*addr
++);
392 addr
+= LCD_WIDTH
- width
;
393 } while (--height
> 0);