diff options
Diffstat (limited to 'firmware/target/arm/sandisk')
-rw-r--r-- | firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S | 306 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-c200/lcd-c200.c | 54 |
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 | ||
274 | lcd_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 | ||
292 | 10: @ 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 @ | ||
354 | 15: @ 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 | ||
365 | 1: @ 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 | ||
370 | 1: @ 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 @ | ||
411 | 15: @ 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 | ||
421 | 1: @ 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 | ||
426 | 1: @ 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 @ | ||
469 | 15: @ 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 | ||
479 | 1: @ 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 | ||
484 | 1: @ 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 @ | ||
525 | 15: @ 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 | ||
533 | 1: @ 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 | ||
538 | 1: @ 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 */ | ||
26 | static 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 | ||
212 | void 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. */ |
210 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | 218 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], |
211 | int width, | 219 | int width, |
212 | int stride); | 220 | int stride); |
221 | extern 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 */ |
214 | void lcd_yuv_blit(unsigned char * const src[3], | 227 | void 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. |