1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2009 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 ****************************************************************************/
27 /* register defines for Philips LCD 220x176x16 - model: LPH9165-2 */
28 #define LCD_REG_UNKNOWN_00 0x00
29 #define LCD_REG_UNKNOWN_01 0x01
30 #define LCD_REG_UNKNOWN_05 0x05
31 #define LCD_REG_WRITE_DATA_2_GRAM 0x06
32 #define LCD_REG_HORIZ_ADDR_START 0x08
33 #define LCD_REG_HORIZ_ADDR_END 0x09
34 #define LCD_REG_VERT_ADDR_START 0x0a
35 #define LCD_REG_VERT_ADDR_END 0x0b
38 static unsigned lcd_yuv_options SHAREDBSS_ATTR
= 0;
40 /* Used for flip offset correction */
44 static inline void lcd_wait_write(void)
46 while (LCD2_PORT
& LCD2_BUSY_MASK
);
50 static void lcd_send_data(unsigned data
)
53 LCD2_PORT
= LCD2_DATA_MASK
| (data
& 0xff);
56 /* send LCD command */
57 static void lcd_send_reg(unsigned reg
)
60 LCD2_PORT
= LCD2_CMD_MASK
| (reg
& 0xff);
64 void lcd_init_device(void)
66 lcd_send_reg(LCD_REG_UNKNOWN_00
);
68 lcd_send_reg(LCD_REG_UNKNOWN_01
);
70 lcd_send_reg(LCD_REG_UNKNOWN_05
);
76 /*** hardware configuration ***/
77 int lcd_default_contrast(void)
79 return DEFAULT_CONTRAST_SETTING
;
82 void lcd_set_contrast(int val
)
87 void lcd_set_invert_display(bool yesno
)
89 int invert
= (yesno
) ? 0x40 : 0x00;
90 lcd_send_reg(LCD_REG_UNKNOWN_00
);
91 lcd_send_data(invert
);
94 /* turn the display upside down (call lcd_update() afterwards) */
95 void lcd_set_flip(bool yesno
)
97 int flip
= (yesno
) ? 0x88 : 0x48;
98 x_offset
= (yesno
) ? 4 : 16;
99 lcd_send_reg(LCD_REG_UNKNOWN_01
);
103 void lcd_yuv_set_options(unsigned options
)
105 lcd_yuv_options
= options
;
111 /* YUV- > RGB565 conversion
112 * |R| |1.000000 -0.000001 1.402000| |Y'|
113 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
114 * |B| |1.000000 1.772000 0.000000| |Pr|
115 * Scaled, normalized, rounded and tweaked to yield RGB 565:
116 * |R| |74 0 101| |Y' - 16| >> 9
117 * |G| = |74 -24 -51| |Cb - 128| >> 8
118 * |B| |74 128 0| |Cr - 128| >> 9
121 extern void lcd_yuv_write_inner_loop(unsigned char const * const ysrc
,
122 unsigned char const * const usrc
,
123 unsigned char const * const vsrc
,
126 /* Performance function to blit a YUV bitmap directly to the LCD */
127 void lcd_blit_yuv(unsigned char * const src
[3],
128 int src_x
, int src_y
, int stride
,
129 int x
, int y
, int width
, int height
)
133 width
= (width
+ 1) & ~1;
135 lcd_send_reg(LCD_REG_HORIZ_ADDR_START
);
138 lcd_send_reg(LCD_REG_HORIZ_ADDR_END
);
139 lcd_send_data(y
+ height
- 1);
141 lcd_send_reg(LCD_REG_VERT_ADDR_START
);
142 lcd_send_data(x
+ x_offset
);
144 lcd_send_reg(LCD_REG_VERT_ADDR_END
);
145 lcd_send_data(x
+ width
- 1 + x_offset
);
147 lcd_send_reg(LCD_REG_WRITE_DATA_2_GRAM
);
149 const int stride_div_csub_x
= stride
/CSUB_X
;
154 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
155 const unsigned char *ysrc
= src
[0] + stride
* src_y
+ src_x
;
157 const int uvoffset
= stride_div_csub_x
* (src_y
/CSUB_Y
) +
160 const unsigned char *usrc
= src
[1] + uvoffset
;
161 const unsigned char *vsrc
= src
[2] + uvoffset
;
167 while (!(LCD2_BLOCK_CTRL
& LCD2_BLOCK_READY
));
168 LCD2_BLOCK_CONFIG
= 0;
170 if (height
== 0) break;
172 pixels_to_write
= (width
* height
) * 2;
175 /* calculate how much we can do in one go */
176 if (pixels_to_write
> 0x10000)
178 h
= (0x10000/2) / width
;
179 pixels_to_write
= (width
* h
) * 2;
183 LCD2_BLOCK_CTRL
= 0x10000080;
184 LCD2_BLOCK_CONFIG
= 0xc0010000 | (pixels_to_write
- 1);
185 LCD2_BLOCK_CTRL
= 0x34000000;
188 lcd_yuv_write_inner_loop(ysrc
,usrc
,vsrc
,width
);
194 while (!(LCD2_BLOCK_CTRL
& LCD2_BLOCK_READY
));
195 LCD2_BLOCK_CONFIG
= 0;
198 /* Update the display.
199 This must be called after all other LCD functions that change the display. */
200 void lcd_update(void)
202 lcd_update_rect(0, 0, LCD_WIDTH
, LCD_HEIGHT
);
205 /* Update a fraction of the display. */
206 void lcd_update_rect(int x
, int y
, int width
, int height
)
209 int new_x
, new_width
;
211 /* Ensure x and width are both even - so we can read 32-bit aligned
212 data from lcd_framebuffer */
214 new_width
= width
&~1;
215 if (new_x
+new_width
< x
+width
) new_width
+= 2;
219 if (x
+ width
>= LCD_WIDTH
)
220 width
= LCD_WIDTH
- x
;
221 if (y
+ height
>= LCD_HEIGHT
)
222 height
= LCD_HEIGHT
- y
;
224 if ((width
<= 0) || (height
<= 0))
225 return; /* Nothing left to do. */
227 lcd_send_reg(LCD_REG_HORIZ_ADDR_START
);
230 lcd_send_reg(LCD_REG_HORIZ_ADDR_END
);
231 lcd_send_data(y
+ height
- 1);
233 lcd_send_reg(LCD_REG_VERT_ADDR_START
);
234 lcd_send_data(x
+ x_offset
);
236 lcd_send_reg(LCD_REG_VERT_ADDR_END
);
237 lcd_send_data(x
+ width
- 1 + x_offset
);
239 lcd_send_reg(LCD_REG_WRITE_DATA_2_GRAM
);
241 addr
= (unsigned long*)&lcd_framebuffer
[y
][x
];
246 int h
, pixels_to_write
;
248 pixels_to_write
= (width
* height
) * 2;
251 /* calculate how much we can do in one go */
252 if (pixels_to_write
> 0x10000)
254 h
= (0x10000/2) / width
;
255 pixels_to_write
= (width
* h
) * 2;
258 LCD2_BLOCK_CTRL
= 0x10000080;
259 LCD2_BLOCK_CONFIG
= 0xc0010000 | (pixels_to_write
- 1);
260 LCD2_BLOCK_CTRL
= 0x34000000;
263 for (r
= 0; r
< h
; r
++)
265 /* for each column */
266 for (c
= 0; c
< width
; c
+= 2)
268 while (!(LCD2_BLOCK_CTRL
& LCD2_BLOCK_TXOK
));
270 /* output 2 pixels */
271 LCD2_BLOCK_DATA
= *addr
++;
273 addr
+= (LCD_WIDTH
- width
)/2;
276 while (!(LCD2_BLOCK_CTRL
& LCD2_BLOCK_READY
));
277 LCD2_BLOCK_CONFIG
= 0;