diff options
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c | 172 |
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 | ||
158 | static 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. */ |
160 | void lcd_update(void) ICODE_ATTR; | 168 | void 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 */ |
259 | void lcd_blit_yuv(unsigned char * const src[3], | 288 | void 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 | } |