summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c172
1 files changed, 150 insertions, 22 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
index 6ce9707732..07a92a970d 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
+++ b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
@@ -155,6 +155,14 @@ void lcd_init_device(void)
155 155
156/*** Update functions ***/ 156/*** Update functions ***/
157 157
158static inline void lcd_write_pixel(fb_data pixel)
159{
160 while (LCD_STATUS & 0x10);
161 LCD_WDATA = (pixel & 0xff00) >> 8;
162 while (LCD_STATUS & 0x10);
163 LCD_WDATA = pixel & 0xff;
164}
165
158/* Update the display. 166/* Update the display.
159 This must be called after all other LCD functions that change the display. */ 167 This must be called after all other LCD functions that change the display. */
160void lcd_update(void) ICODE_ATTR; 168void lcd_update(void) ICODE_ATTR;
@@ -162,7 +170,6 @@ void lcd_update(void)
162{ 170{
163 int x,y; 171 int x,y;
164 fb_data* p = &lcd_framebuffer[0][0]; 172 fb_data* p = &lcd_framebuffer[0][0];
165 fb_data pixel;
166 173
167 if (lcd_type==0) { 174 if (lcd_type==0) {
168 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, 0); 175 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, 0);
@@ -191,12 +198,7 @@ void lcd_update(void)
191 /* Copy display bitmap to hardware */ 198 /* Copy display bitmap to hardware */
192 for (y = 0; y < LCD_HEIGHT; y++) { 199 for (y = 0; y < LCD_HEIGHT; y++) {
193 for (x = 0; x < LCD_WIDTH; x++) { 200 for (x = 0; x < LCD_WIDTH; x++) {
194 pixel = *(p++); 201 lcd_write_pixel(*(p++));
195
196 while (LCD_STATUS & 0x10);
197 LCD_WDATA = (pixel & 0xff00) >> 8;
198 while (LCD_STATUS & 0x10);
199 LCD_WDATA = pixel & 0xff;
200 } 202 }
201 } 203 }
202} 204}
@@ -208,7 +210,6 @@ void lcd_update_rect(int x, int y, int width, int height)
208 int xx,yy; 210 int xx,yy;
209 int y0, x0, y1, x1; 211 int y0, x0, y1, x1;
210 fb_data* p; 212 fb_data* p;
211 fb_data pixel;
212 213
213 x0 = x; /* start horiz */ 214 x0 = x; /* start horiz */
214 y0 = y; /* start vert */ 215 y0 = y; /* start vert */
@@ -244,28 +245,155 @@ void lcd_update_rect(int x, int y, int width, int height)
244 yy = height; 245 yy = height;
245 for (yy = y0; yy <= y1; yy++) { 246 for (yy = y0; yy <= y1; yy++) {
246 for (xx = x0; xx <= x1; xx++) { 247 for (xx = x0; xx <= x1; xx++) {
247 pixel = *(p++); 248 lcd_write_pixel(*(p++));
248
249 while (LCD_STATUS & 0x10);
250 LCD_WDATA = (pixel & 0xff00) >> 8;
251 while (LCD_STATUS & 0x10);
252 LCD_WDATA = pixel & 0xff;
253 } 249 }
254 p += LCD_WIDTH - width; 250 p += LCD_WIDTH - width;
255 } 251 }
256} 252}
257 253
254/*** update functions ***/
255
256#define CSUB_X 2
257#define CSUB_Y 2
258
259/* YUV- > RGB565 conversion
260 * |R| |1.000000 -0.000001 1.402000| |Y'|
261 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
262 * |B| |1.000000 1.772000 0.000000| |Pr|
263 * Scaled, normalized, rounded and tweaked to yield RGB 565:
264 * |R| |74 0 101| |Y' - 16| >> 9
265 * |G| = |74 -24 -51| |Cb - 128| >> 8
266 * |B| |74 128 0| |Cr - 128| >> 9
267*/
268
269#define RGBYFAC 74 /* 1.0 */
270#define RVFAC 101 /* 1.402 */
271#define GVFAC (-51) /* -0.714136 */
272#define GUFAC (-24) /* -0.334136 */
273#define BUFAC 128 /* 1.772 */
274
275/* ROUNDOFFS contain constant for correct round-offs as well as
276 constant parts of the conversion matrix (e.g. (Y'-16)*RGBYFAC
277 -> constant part = -16*RGBYFAC). Through extraction of these
278 constant parts we save at leat 4 substractions in the conversion
279 loop */
280#define ROUNDOFFSR (256 - 16*RGBYFAC - 128*RVFAC)
281#define ROUNDOFFSG (128 - 16*RGBYFAC - 128*GVFAC - 128*GUFAC)
282#define ROUNDOFFSB (256 - 16*RGBYFAC - 128*BUFAC)
283
284#define MAX_5BIT 0x1f
285#define MAX_6BIT 0x3f
286
258/* Performance function to blit a YUV bitmap directly to the LCD */ 287/* Performance function to blit a YUV bitmap directly to the LCD */
259void lcd_blit_yuv(unsigned char * const src[3], 288void lcd_blit_yuv(unsigned char * const src[3],
260 int src_x, int src_y, int stride, 289 int src_x, int src_y, int stride,
261 int x, int y, int width, int height) 290 int x, int y, int width, int height)
262{ 291{
263 (void)src; 292 int h;
264 (void)src_x; 293 int y0, x0, y1, x1;
265 (void)src_y; 294
266 (void)stride; 295 width = (width + 1) & ~1;
267 (void)x; 296
268 (void)y; 297 x0 = x; /* start horiz */
269 (void)width; 298 y0 = y; /* start vert */
270 (void)height; 299 x1 = (x + width) - 1; /* max horiz */
300 y1 = (y + height) - 1; /* max vert */
301
302 if (lcd_type==0) {
303 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0);
304 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1);
305 s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0);
306 s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1);
307
308 s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0);
309 s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0);
310
311 s5l_lcd_write_cmd(0);
312 s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM);
313 } else {
314 s5l_lcd_write_cmd(R_COLUMN_ADDR_SET);
315 s5l_lcd_write_data(x0); /* Start column */
316 s5l_lcd_write_data(x1); /* End column */
317
318 s5l_lcd_write_cmd(R_ROW_ADDR_SET);
319 s5l_lcd_write_data(y0); /* Start row */
320 s5l_lcd_write_data(y1); /* End row */
321
322 s5l_lcd_write_cmd(R_MEMORY_WRITE);
323 }
324
325 const int stride_div_csub_x = stride/CSUB_X;
326
327 h = height;
328 while (h > 0) {
329 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
330 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
331
332 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
333 (src_x/CSUB_X);
334
335 const unsigned char *usrc = src[1] + uvoffset;
336 const unsigned char *vsrc = src[2] + uvoffset;
337 const unsigned char *row_end = ysrc + width;
338
339 int yp, up, vp;
340 int red1, green1, blue1;
341 int red2, green2, blue2;
342
343 int rc, gc, bc;
344
345 do
346 {
347 up = *usrc++;
348 vp = *vsrc++;
349 rc = RVFAC * vp + ROUNDOFFSR;
350 gc = GVFAC * vp + GUFAC * up + ROUNDOFFSG;
351 bc = BUFAC * up + ROUNDOFFSB;
352
353 /* Pixel 1 -> RGB565 */
354 yp = *ysrc++ * RGBYFAC;
355 red1 = (yp + rc) >> 9;
356 green1 = (yp + gc) >> 8;
357 blue1 = (yp + bc) >> 9;
358
359 /* Pixel 2 -> RGB565 */
360 yp = *ysrc++ * RGBYFAC;
361 red2 = (yp + rc) >> 9;
362 green2 = (yp + gc) >> 8;
363 blue2 = (yp + bc) >> 9;
364
365 /* Since out of bounds errors are relatively rare, we check two
366 pixels at once to see if any components are out of bounds, and
367 then fix whichever is broken. This works due to high values and
368 negative values both being !=0 when bitmasking them.
369 We first check for red and blue components (5bit range). */
370 if ((red1 | blue1 | red2 | blue2) & ~MAX_5BIT)
371 {
372 if (red1 & ~MAX_5BIT)
373 red1 = (red1 >> 31) ? 0 : MAX_5BIT;
374 if (blue1 & ~MAX_5BIT)
375 blue1 = (blue1 >> 31) ? 0 : MAX_5BIT;
376 if (red2 & ~MAX_5BIT)
377 red2 = (red2 >> 31) ? 0 : MAX_5BIT;
378 if (blue2 & ~MAX_5BIT)
379 blue2 = (blue2 >> 31) ? 0 : MAX_5BIT;
380 }
381 /* We second check for green component (6bit range) */
382 if ((green1 | green2) & ~MAX_6BIT)
383 {
384 if (green1 & ~MAX_6BIT)
385 green1 = (green1 >> 31) ? 0 : MAX_6BIT;
386 if (green2 & ~MAX_6BIT)
387 green2 = (green2 >> 31) ? 0 : MAX_6BIT;
388 }
389
390 /* output 2 pixels */
391 lcd_write_pixel((red1 << 11) | (green1 << 5) | blue1);
392 lcd_write_pixel((red2 << 11) | (green2 << 5) | blue2);
393 }
394 while (ysrc < row_end);
395
396 src_y++;
397 h--;
398 }
271} 399}