summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S306
-rw-r--r--firmware/target/arm/sandisk/sansa-c200/lcd-c200.c54
2 files changed, 349 insertions, 11 deletions
diff --git a/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S b/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S
index 9b0cd75bae..aaeb8439b6 100644
--- a/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S
+++ b/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S
@@ -241,3 +241,309 @@ lcd_write_yuv420_lines:
241 .ltorg @ dump constant pool 241 .ltorg @ dump constant pool
242 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines 242 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
243 243
244/****************************************************************************
245 * void lcd_write_yuv_420_lines_odither(unsigned char const * const src[3],
246 * int width,
247 * int stride,
248 * int x_screen,
249 * int y_screen);
250 *
251 * |R| |1.000000 -0.000001 1.402000| |Y'|
252 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
253 * |B| |1.000000 1.772000 0.000000| |Pr|
254 * Red scaled at twice g & b but at same precision to place it in correct
255 * bit position after multiply and leave instruction count lower.
256 * |R| |258 0 408| |Y' - 16|
257 * |G| = |149 -49 -104| |Cb - 128|
258 * |B| |149 258 0| |Cr - 128|
259 *
260 * Write four RGB565 pixels in the following order on each loop:
261 * 1 3 + > down
262 * 2 4 \/ left
263 *
264 * Kernel pattern (raw|rotated|use order):
265 * 5 3 4 2 2 6 3 7 row0 row2 > down
266 * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left
267 * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/
268 * 0 6 1 7 5 1 4 0
269 */
270 .section .icode, "ax", %progbits
271 .align 2
272 .global lcd_write_yuv420_lines_odither
273 .type lcd_write_yuv420_lines_odither, %function
274lcd_write_yuv420_lines_odither:
275 @ r0 = yuv_src
276 @ r1 = width
277 @ r2 = stride
278 @ r3 = x_screen
279 @ [sp] = y_screen
280 stmfd sp!, { r4-r12, lr } @ save non-scratch
281 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
282 @ r5 = yuv_src[1] = Cb_p
283 @ r6 = yuv_src[2] = Cr_p
284 @
285 sub r2, r2, #1 @
286 ldr r14, [sp, #40] @ Line up pattern and kernel quadrant
287 eor r14, r14, r3 @
288 and r14, r14, #0x2 @
289 mov r14, r14, lsl #6 @ 0x00 or 0x80
290 mov r3, #0x70000000 @
291 orr r3, r3, #0x3000 @ r3 = LCD1_BASE
29210: @ loop line @
293 @
294 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
295 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
296 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
297 @
298 eor r14, r14, #0x80 @ flip pattern quadrant
299 @
300 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
301 add r12, r7, r7, asl #2 @
302 add r12, r12, r12, asl #4 @
303 add r7, r12, r7, asl #6 @
304 @
305 sub r8, r8, #128 @ Cb -= 128
306 sub r9, r9, #128 @ Cr -= 128
307 @
308 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
309 add r10, r10, r8, asl #5 @
310 add r10, r10, r9, asl #3 @
311 add r10, r10, r9, asl #5 @
312 add r10, r10, r9, asl #6 @
313 @
314 mov r8, r8, asl #1 @ r8 = bu = Cb*258
315 add r8, r8, r8, asl #7 @
316 @
317 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
318 add r9, r9, r9, asl #4 @
319 mov r9, r9, asl #3 @
320 @
321 @ compute R, G, and B
322 add r0, r8, r7 @ r0 = b' = Y + bu
323 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
324 rsb r7, r10, r7 @ r7 = g' = Y + guv
325 @
326 @ r8 = bu, r9 = rv, r10 = guv
327 @
328 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
329 add r0, r12, r0, lsr #8 @
330 @
331 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
332 add r11, r12, r11, lsr #8 @
333 @
334 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
335 add r7, r12, r7, lsr #8 @
336 @
337 add r12, r14, #0x100 @
338 @
339 add r0, r0, r12 @ b = r0 + delta
340 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
341 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
342 @
343 orr r12, r0, r11, asr #1 @ check if clamping is needed...
344 orr r12, r12, r7 @ ...at all
345 movs r12, r12, asr #15 @
346 beq 15f @ no clamp @
347 movs r12, r0, asr #15 @ clamp b
348 mvnne r0, r12, lsr #15 @
349 andne r0, r0, #0x7c00 @ mask b only if clamped
350 movs r12, r11, asr #16 @ clamp r
351 mvnne r11, r12, lsr #16 @
352 movs r12, r7, asr #15 @ clamp g
353 mvnne r7, r12, lsr #15 @
35415: @ no clamp @
355 @
356 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
357 @
358
359 and r11, r11, #0xf800 @ pack pixel
360 mov r11, r11, lsr #8
361 and r7, r7, #0x7e00
362 orr r11, r11, r7, lsr #12
363 mov r7, r7, lsr#4
364 orr r0, r7, r0, lsr #10
3651: @ busy @
366 ldr r7, [r3] @ r7 = LCD1_BASE
367 tst r7, #LCD1_BUSY_MASK @ bridge busy?
368 bne 1b @
369 str r11, [r3, #0x10] @ send MSB
3701: @ busy @
371 ldr r7, [r3] @ r7 = LCD1_BASE
372 tst r7, #LCD1_BUSY_MASK @ bridge busy?
373 bne 1b @
374 str r0, [r3, #0x10] @ send LSB
375 @
376 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
377 add r12, r7, r7, asl #2 @
378 add r12, r12, r12, asl #4 @
379 add r7, r12, r7, asl #6 @
380 @ compute R, G, and B
381 add r0, r8, r7 @ r0 = b' = Y + bu
382 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
383 rsb r7, r10, r7 @ r7 = g' = Y + guv
384 @
385 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
386 add r0, r12, r0, lsr #8 @
387 @
388 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
389 add r11, r12, r11, lsr #8 @
390 @
391 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
392 add r7, r12, r7, lsr #8 @
393 @
394 add r12, r14, #0x200 @
395 @
396 add r0, r0, r12 @ b = r0 + delta
397 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
398 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
399 @
400 orr r12, r0, r11, asr #1 @ check if clamping is needed...
401 orr r12, r12, r7 @ ...at all
402 movs r12, r12, asr #15 @
403 beq 15f @ no clamp @
404 movs r12, r0, asr #15 @ clamp b
405 mvnne r0, r12, lsr #15 @
406 andne r0, r0, #0x7c00 @ mask b only if clamped
407 movs r12, r11, asr #16 @ clamp r
408 mvnne r11, r12, lsr #16 @
409 movs r12, r7, asr #15 @ clamp g
410 mvnne r7, r12, lsr #15 @
41115: @ no clamp @
412 @
413 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
414
415 and r11, r11, #0xf800 @ pack pixel
416 mov r11, r11, lsr #8
417 and r7, r7, #0x7e00
418 orr r11, r11, r7, lsr #12
419 mov r7, r7, lsr#4
420 orr r0, r7, r0, lsr #10
4211: @ busy @
422 ldr r7, [r3] @ r7 = LCD1_BASE
423 tst r7, #LCD1_BUSY_MASK @ bridge busy?
424 bne 1b @
425 str r11, [r3, #0x10] @ send MSB
4261: @ busy @
427 ldr r7, [r3] @ r7 = LCD1_BASE
428 tst r7, #LCD1_BUSY_MASK @ bridge busy?
429 bne 1b @
430 str r0, [r3, #0x10] @ send LSB
431
432 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
433 add r12, r7, r7, asl #2 @
434 add r12, r12, r12, asl #4 @
435 add r7, r12, r7, asl #6 @
436 @ compute R, G, and B
437 add r0, r8, r7 @ r0 = b' = Y + bu
438 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
439 rsb r7, r10, r7 @ r7 = g' = Y + guv
440 @
441 @ r8 = bu, r9 = rv, r10 = guv
442 @
443 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
444 add r0, r12, r0, lsr #8 @
445 @
446 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
447 add r11, r12, r11, lsr #8 @
448 @
449 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
450 add r7, r12, r7, lsr #8 @
451 @
452 add r12, r14, #0x300 @
453 @
454 add r0, r0, r12 @ b = r0 + delta
455 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
456 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
457 @
458 orr r12, r0, r11, asr #1 @ check if clamping is needed...
459 orr r12, r12, r7 @ ...at all
460 movs r12, r12, asr #15 @
461 beq 15f @ no clamp @
462 movs r12, r0, asr #15 @ clamp b
463 mvnne r0, r12, lsr #15 @
464 andne r0, r0, #0x7c00 @ mask b only if clamped
465 movs r12, r11, asr #16 @ clamp r
466 mvnne r11, r12, lsr #16 @
467 movs r12, r7, asr #15 @ clamp g
468 mvnne r7, r12, lsr #15 @
46915: @ no clamp @
470 @
471 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
472
473 and r11, r11, #0xf800 @ pack pixel
474 mov r11, r11, lsr #8
475 and r7, r7, #0x7e00
476 orr r11, r11, r7, lsr #12
477 mov r7, r7, lsr#4
478 orr r0, r7, r0, lsr #10
4791: @ busy @
480 ldr r7, [r3] @ r7 = LCD1_BASE
481 tst r7, #LCD1_BUSY_MASK @ bridge busy?
482 bne 1b @
483 str r11, [r3, #0x10] @ send MSB
4841: @ busy @
485 ldr r7, [r3] @ r7 = LCD1_BASE
486 tst r7, #LCD1_BUSY_MASK @ bridge busy?
487 bne 1b @
488 str r0, [r3, #0x10] @ send LSB
489
490 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
491 add r12, r7, r7, asl #2 @
492 add r12, r12, r12, asl #4 @
493 add r7, r12, r7, asl #6 @
494 @ compute R, G, and B
495 add r0, r8, r7 @ r0 = b' = Y + bu
496 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
497 rsb r7, r10, r7 @ r7 = g' = Y + guv
498 @
499 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
500 add r0, r12, r0, lsr #8 @
501 @
502 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
503 add r11, r12, r11, lsr #8 @
504 @
505 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
506 add r7, r12, r7, lsr #8 @
507 @
508 @ This element is zero - use r14 @
509 @
510 add r0, r0, r14 @ b = r0 + delta
511 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
512 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
513 @
514 orr r12, r0, r11, asr #1 @ check if clamping is needed...
515 orr r12, r12, r7 @ ...at all
516 movs r12, r12, asr #15 @
517 beq 15f @ no clamp @
518 movs r12, r0, asr #15 @ clamp b
519 mvnne r0, r12, lsr #15 @
520 andne r0, r0, #0x7c00 @ mask b only if clamped
521 movs r12, r11, asr #16 @ clamp r
522 mvnne r11, r12, lsr #16 @
523 movs r12, r7, asr #15 @ clamp g
524 mvnne r7, r12, lsr #15 @
52515: @ no clamp @
526
527 and r11, r11, #0xf800 @ pack pixel
528 mov r11, r11, lsr #8
529 and r7, r7, #0x7e00
530 orr r11, r11, r7, lsr #12
531 mov r7, r7, lsr#4
532 orr r0, r7, r0, lsr #10
5331: @ busy @
534 ldr r7, [r3] @ r7 = LCD1_BASE
535 tst r7, #LCD1_BUSY_MASK @ bridge busy?
536 bne 1b @
537 str r11, [r3, #0x10] @ send MSB
5381: @ busy @
539 ldr r7, [r3] @ r7 = LCD1_BASE
540 tst r7, #LCD1_BUSY_MASK @ bridge busy?
541 bne 1b @
542 str r0, [r3, #0x10] @ send LSB
543
544 subs r1, r1, #2 @ subtract block from width
545 bgt 10b @ loop line @
546 @
547 ldmfd sp!, { r4-r12, pc } @ restore registers and return
548 .ltorg @ dump constant pool
549 .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither
diff --git a/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c b/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c
index 5975ab159d..fa8581f286 100644
--- a/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c
+++ b/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c
@@ -22,6 +22,9 @@
22#include "kernel.h" 22#include "kernel.h"
23#include "system.h" 23#include "system.h"
24 24
25/* Display status */
26static unsigned lcd_yuv_options NOCACHEBSS_ATTR = 0;
27
25/* LCD command set for Samsung S6B33B2 */ 28/* LCD command set for Samsung S6B33B2 */
26 29
27#define R_OSCILLATION_MODE 0x02 30#define R_OSCILLATION_MODE 0x02
@@ -206,10 +209,20 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
206 (void)stride; 209 (void)stride;
207} 210}
208 211
212void lcd_yuv_set_options(unsigned options)
213{
214 lcd_yuv_options = options;
215}
216
209/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ 217/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
210extern void lcd_write_yuv420_lines(unsigned char const * const src[3], 218extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
211 int width, 219 int width,
212 int stride); 220 int stride);
221extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
222 int width,
223 int stride,
224 int x_screen, /* To align dither pattern */
225 int y_screen);
213/* Performance function to blit a YUV bitmap directly to the LCD */ 226/* Performance function to blit a YUV bitmap directly to the LCD */
214void lcd_yuv_blit(unsigned char * const src[3], 227void lcd_yuv_blit(unsigned char * const src[3],
215 int src_x, int src_y, int stride, 228 int src_x, int src_y, int stride,
@@ -236,19 +249,38 @@ void lcd_yuv_blit(unsigned char * const src[3],
236 lcd_send_command(x); 249 lcd_send_command(x);
237 lcd_send_command(x + width - 1); 250 lcd_send_command(x + width - 1);
238 251
239 do 252 if (lcd_yuv_options & LCD_YUV_DITHER)
240 { 253 {
241 lcd_send_command(R_Y_ADDR_AREA); 254 do
242 lcd_send_command(y); 255 {
243 lcd_send_command(y + 1); 256 lcd_send_command(R_Y_ADDR_AREA);
244 257 lcd_send_command(y);
245 lcd_write_yuv420_lines(yuv_src, width, stride); 258 lcd_send_command(y + 1);
246 yuv_src[0] += stride << 1; /* Skip down two luma lines */ 259
247 yuv_src[1] += stride >> 1; /* Skip down one chroma line */ 260 lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y);
248 yuv_src[2] += stride >> 1; 261 yuv_src[0] += stride << 1; /* Skip down two luma lines */
249 y += 2; 262 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
263 yuv_src[2] += stride >> 1;
264 y += 2;
265 }
266 while (--height > 0);
267 }
268 else
269 {
270 do
271 {
272 lcd_send_command(R_Y_ADDR_AREA);
273 lcd_send_command(y);
274 lcd_send_command(y + 1);
275
276 lcd_write_yuv420_lines(yuv_src, width, stride);
277 yuv_src[0] += stride << 1; /* Skip down two luma lines */
278 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
279 yuv_src[2] += stride >> 1;
280 y += 2;
281 }
282 while (--height > 0);
250 } 283 }
251 while (--height > 0);
252} 284}
253 285
254/* Update the display. 286/* Update the display.