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;
41 static inline void lcd_wait_write(void)
43 while (LCD2_PORT
& LCD2_BUSY_MASK
);
47 static void lcd_send_data(unsigned data
)
50 LCD2_PORT
= LCD2_DATA_MASK
| (data
& 0xff);
53 /* send LCD command */
54 static void lcd_send_reg(unsigned reg
)
57 LCD2_PORT
= LCD2_CMD_MASK
| (reg
& 0xff);
61 void lcd_init_device(void)
63 lcd_send_reg(LCD_REG_UNKNOWN_00
);
65 lcd_send_reg(LCD_REG_UNKNOWN_01
);
67 lcd_send_reg(LCD_REG_UNKNOWN_05
);
71 /*** hardware configuration ***/
72 int lcd_default_contrast(void)
74 return DEFAULT_CONTRAST_SETTING
;
77 void lcd_set_contrast(int val
)
82 void lcd_set_invert_display(bool yesno
)
84 int invert
= (yesno
) ? 0x40 : 0x00;
85 lcd_send_reg(LCD_REG_UNKNOWN_00
);
86 lcd_send_data(invert
);
89 /* turn the display upside down (call lcd_update() afterwards) */
90 void lcd_set_flip(bool yesno
)
95 void lcd_yuv_set_options(unsigned options
)
97 lcd_yuv_options
= options
;
103 /* YUV- > RGB565 conversion
104 * |R| |1.000000 -0.000001 1.402000| |Y'|
105 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
106 * |B| |1.000000 1.772000 0.000000| |Pr|
107 * Scaled, normalized, rounded and tweaked to yield RGB 565:
108 * |R| |74 0 101| |Y' - 16| >> 9
109 * |G| = |74 -24 -51| |Cb - 128| >> 8
110 * |B| |74 128 0| |Cr - 128| >> 9
113 extern void lcd_yuv_write_inner_loop(unsigned char const * const ysrc
,
114 unsigned char const * const usrc
,
115 unsigned char const * const vsrc
,
118 /* Performance function to blit a YUV bitmap directly to the LCD */
119 void lcd_blit_yuv(unsigned char * const src
[3],
120 int src_x
, int src_y
, int stride
,
121 int x
, int y
, int width
, int height
)
125 width
= (width
+ 1) & ~1;
127 lcd_send_reg(LCD_REG_HORIZ_ADDR_START
);
130 lcd_send_reg(LCD_REG_HORIZ_ADDR_END
);
131 lcd_send_data(y
+ height
- 1);
133 lcd_send_reg(LCD_REG_VERT_ADDR_START
);
134 lcd_send_data(x
+ 16);
136 lcd_send_reg(LCD_REG_VERT_ADDR_END
);
137 lcd_send_data(x
+ width
- 1 + 16);
139 lcd_send_reg(LCD_REG_WRITE_DATA_2_GRAM
);
141 const int stride_div_csub_x
= stride
/CSUB_X
;
146 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
147 const unsigned char *ysrc
= src
[0] + stride
* src_y
+ src_x
;
149 const int uvoffset
= stride_div_csub_x
* (src_y
/CSUB_Y
) +
152 const unsigned char *usrc
= src
[1] + uvoffset
;
153 const unsigned char *vsrc
= src
[2] + uvoffset
;
159 while (!(LCD2_BLOCK_CTRL
& LCD2_BLOCK_READY
));
160 LCD2_BLOCK_CONFIG
= 0;
162 if (height
== 0) break;
164 pixels_to_write
= (width
* height
) * 2;
167 /* calculate how much we can do in one go */
168 if (pixels_to_write
> 0x10000)
170 h
= (0x10000/2) / width
;
171 pixels_to_write
= (width
* h
) * 2;
175 LCD2_BLOCK_CTRL
= 0x10000080;
176 LCD2_BLOCK_CONFIG
= 0xc0010000 | (pixels_to_write
- 1);
177 LCD2_BLOCK_CTRL
= 0x34000000;
180 lcd_yuv_write_inner_loop(ysrc
,usrc
,vsrc
,width
);
186 while (!(LCD2_BLOCK_CTRL
& LCD2_BLOCK_READY
));
187 LCD2_BLOCK_CONFIG
= 0;
190 /* Update the display.
191 This must be called after all other LCD functions that change the display. */
192 void lcd_update(void)
194 lcd_update_rect(0, 0, LCD_WIDTH
, LCD_HEIGHT
);
197 /* Update a fraction of the display. */
198 void lcd_update_rect(int x
, int y
, int width
, int height
)
201 int new_x
, new_width
;
203 /* Ensure x and width are both even - so we can read 32-bit aligned
204 data from lcd_framebuffer */
206 new_width
= width
&~1;
207 if (new_x
+new_width
< x
+width
) new_width
+= 2;
211 if (x
+ width
>= LCD_WIDTH
)
212 width
= LCD_WIDTH
- x
;
213 if (y
+ height
>= LCD_HEIGHT
)
214 height
= LCD_HEIGHT
- y
;
216 if ((width
<= 0) || (height
<= 0))
217 return; /* Nothing left to do. */
219 lcd_send_reg(LCD_REG_HORIZ_ADDR_START
);
222 lcd_send_reg(LCD_REG_HORIZ_ADDR_END
);
223 lcd_send_data(y
+ height
- 1);
225 lcd_send_reg(LCD_REG_VERT_ADDR_START
);
226 lcd_send_data(x
+ 16);
228 lcd_send_reg(LCD_REG_VERT_ADDR_END
);
229 lcd_send_data(x
+ width
- 1 + 16);
231 lcd_send_reg(LCD_REG_WRITE_DATA_2_GRAM
);
233 addr
= (unsigned long*)&lcd_framebuffer
[y
][x
];
238 int h
, pixels_to_write
;
240 pixels_to_write
= (width
* height
) * 2;
243 /* calculate how much we can do in one go */
244 if (pixels_to_write
> 0x10000)
246 h
= (0x10000/2) / width
;
247 pixels_to_write
= (width
* h
) * 2;
250 LCD2_BLOCK_CTRL
= 0x10000080;
251 LCD2_BLOCK_CONFIG
= 0xc0010000 | (pixels_to_write
- 1);
252 LCD2_BLOCK_CTRL
= 0x34000000;
255 for (r
= 0; r
< h
; r
++)
257 /* for each column */
258 for (c
= 0; c
< width
; c
+= 2)
260 while (!(LCD2_BLOCK_CTRL
& LCD2_BLOCK_TXOK
));
262 /* output 2 pixels */
263 LCD2_BLOCK_DATA
= *addr
++;
265 addr
+= (LCD_WIDTH
- width
)/2;
268 while (!(LCD2_BLOCK_CTRL
& LCD2_BLOCK_READY
));
269 LCD2_BLOCK_CONFIG
= 0;