| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2006 by Jens Arnold |
| * |
| * All files in this archive are subject to the GNU General Public License. |
| * See the file COPYING in the source tree root for full license agreement. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| #include "config.h" |
| #include "cpu.h" |
| |
| .section .icode, "ax", @progbits |
| |
| /* lcd_write_yuv420_lines(), based on lcd-as-x5.S |
| * |
| * See http://en.wikipedia.org/wiki/YCbCr |
| * ITU-R BT.601 (formerly CCIR 601): |
| * |Y'| | 0.299000 0.587000 0.114000| |R| |
| * |Pb| = |-0.168736 -0.331264 0.500000| |G| or 0.564334*(B - Y') |
| * |Pr| | 0.500000 -0.418688 0.081312| |B| or 0.713267*(R - Y') |
| * Scaled, normalized and rounded: |
| * |Y'| | 65 129 25| |R| + 16 : 16->235 |
| * |Cb| = |-38 -74 112| |G| + 128 : 16->240 |
| * |Cr| |112 -94 -18| |B| + 128 : 16->240 |
| * |
| * The inverse: |
| * |R| |1.000000 0.000000 1.402000| |Y'| |
| * |G| = |1.000000 -0.334136 -0.714136| |Pb| |
| * |B| |1.000000 1.772000 0.000000| |Pr| |
| * Scaled, normalized, rounded and tweaked to yield RGB666, as converting |
| * directly to RGB565 gives too much roundoff error: |
| * |R| |74 0 101| |Y' - 16| / 256 |
| * |G| = |74 -24 -51| |Cb - 128| / 256 |
| * |B| |74 128 0| |Cr - 128| / 256 |
| */ |
| |
| .align 2 |
| .global lcd_write_yuv420_lines |
| .type lcd_write_yuv420_lines, @function |
| |
| lcd_write_yuv420_lines: |
| lea.l (-36, %sp), %sp /* free up some registers */ |
| movem.l %d2-%d6/%a2-%a5, (%sp) |
| |
| lea.l 0xf0000002, %a0 /* LCD data port */ |
| movem.l (36+4, %sp), %a1-%a5 /* Y data, Cb data, guv storage, Cr data, width */ |
| lea.l (%a1, %a5), %a5 /* end address */ |
| |
| .yuv_line_loop1: |
| /* chroma for first & second pixel */ |
| clr.l %d1 /* load bu component */ |
| move.b (%a2), %d1 |
| clr.l %d3 /* load rv component */ |
| move.b (%a4), %d3 |
| moveq.l #-128, %d0 |
| add.l %d0, %d1 |
| add.l %d0, %d3 |
| |
| move.l %d1, %d2 /* %d2 = cb component for guv */ |
| asr.l #1, %d1 /* %d1 = 128 * (Cb - 128) / 256 */ |
| move.b %d1, (%a2)+ /* save bu for next line */ |
| moveq.l #-24, %d0 |
| muls.w %d0, %d2 /* %d2 = -24 * (Cb - 128)*/ |
| moveq.l #-51, %d0 |
| muls.w %d3, %d0 |
| add.l %d0, %d2 /* %d2 = -24 * (Cb - 128) - 51 * (Cr - 128) */ |
| asr.l #8, %d2 |
| move.b %d2, (%a3)+ /* save guv for next line */ |
| moveq.l #101, %d0 |
| muls.w %d0, %d3 /* %d3 = 101 * (Cr - 128) */ |
| asr.l #8, %d3 |
| move.b %d3, (%a4)+ /* save rv for next line */ |
| |
| /* luma for first pixel */ |
| clr.l %d4 /* load y component */ |
| move.b (%a1)+, %d4 |
| moveq.l #74, %d0 |
| muls.w %d0, %d4 /* %d4 = 36 * Y */ |
| asr.l #8, %d4 |
| subq.l #4, %d4 /* correction for (Y - 16) and rounding */ |
| move.l %d4, %d5 |
| move.l %d4, %d6 |
| |
| /* combine & write first pixel */ |
| add.l %d1, %d4 /* %d4 = blue */ |
| add.l %d2, %d5 /* %d5 = green */ |
| add.l %d3, %d6 /* %d6 = red */ |
| |
| move.l %d4, %d0 /* clamping */ |
| or.l %d5, %d0 |
| or.l %d6, %d0 |
| asr.l #6, %d0 |
| beq.s .yuv_all_ok1 |
| moveq.l #63, %d0 |
| cmp.l %d0, %d4 |
| bls.s .yuv_blue_ok1 |
| spl.b %d4 |
| and.l %d0, %d4 |
| .yuv_blue_ok1: |
| cmp.l %d0, %d5 |
| bls.s .yuv_green_ok1 |
| spl.b %d5 |
| and.l %d0, %d5 |
| .yuv_green_ok1: |
| cmp.l %d0, %d6 |
| bls.s .yuv_red_ok1 |
| spl.b %d6 |
| and.l %d0, %d6 |
| .yuv_red_ok1: |
| .yuv_all_ok1: |
| |
| lsr.l #1, %d6 /* pack, convert to RGB565 and output */ |
| lsr.l #1, %d4 |
| lsl.l #6, %d6 |
| or.l %d6, %d5 |
| lsl.l #5, %d5 |
| or.l %d5, %d4 |
| move.w %d4, (%a0) |
| |
| /* luma for second pixel */ |
| clr.l %d4 /* load y component */ |
| move.b (%a1)+, %d4 |
| moveq.l #74, %d0 |
| muls.w %d0, %d4 /* %d4 = 36 * Y */ |
| asr.l #8, %d4 |
| subq.l #4, %d4 /* correction for (Y - 16) and rounding */ |
| |
| /* combine & write second pixel */ |
| add.l %d4, %d1 /* %d1 = blue */ |
| add.l %d4, %d2 /* %d2 = green */ |
| add.l %d4, %d3 /* %d3 = red */ |
| |
| move.l %d1, %d0 /* clamping */ |
| or.l %d2, %d0 |
| or.l %d3, %d0 |
| asr.l #6, %d0 |
| beq.s .yuv_all_ok2 |
| moveq.l #63, %d0 |
| cmp.l %d0, %d1 |
| bls.s .yuv_blue_ok2 |
| spl.b %d1 |
| and.l %d0, %d1 |
| .yuv_blue_ok2: |
| cmp.l %d0, %d2 |
| bls.s .yuv_green_ok2 |
| spl.b %d2 |
| and.l %d0, %d2 |
| .yuv_green_ok2: |
| cmp.l %d0, %d3 |
| bls.s .yuv_red_ok2 |
| spl.b %d3 |
| and.l %d0, %d3 |
| .yuv_red_ok2: |
| .yuv_all_ok2: |
| |
| lsr.l #1, %d3 /* pack, convert to RGB565 and output */ |
| lsr.l #1, %d1 |
| lsl.l #6, %d3 |
| or.l %d3, %d2 |
| lsl.l #5, %d2 |
| or.l %d2, %d1 |
| move.w %d1, (%a0) |
| |
| cmp.l %a1,%a5 /* run %a1 up to end of line */ |
| bhi.w .yuv_line_loop1 |
| |
| /* Rewind chroma pointers */ |
| movem.l (36+8, %sp), %a2-%a5 /* bu data, guv data, rv data, width */ |
| lea.l (%a1, %a5), %a5 /* next end address */ |
| |
| .yuv_line_loop2: |
| /* read saved chromas and sign extend */ |
| move.b (%a2)+, %d1 |
| extb.l %d1 |
| move.b (%a3)+, %d2 |
| extb.l %d2 |
| move.b (%a4)+, %d3 |
| extb.l %d3 |
| |
| /* luma for first pixel */ |
| clr.l %d4 /* load y component */ |
| move.b (%a1)+, %d4 |
| moveq.l #74, %d0 |
| muls.w %d0, %d4 /* %d4 = 36 * Y */ |
| asr.l #8, %d4 |
| subq.l #4, %d4 /* correction for (Y - 16) and rounding */ |
| move.l %d4, %d5 |
| move.l %d4, %d6 |
| |
| /* combine & write first pixel */ |
| add.l %d1, %d4 /* %d4 = blue */ |
| add.l %d2, %d5 /* %d5 = green */ |
| add.l %d3, %d6 /* %d6 = red */ |
| |
| move.l %d4, %d0 /* clamping */ |
| or.l %d5, %d0 |
| or.l %d6, %d0 |
| asr.l #6, %d0 |
| beq.s .yuv_all_ok3 |
| moveq.l #63, %d0 |
| cmp.l %d0, %d4 |
| bls.s .yuv_blue_ok3 |
| spl.b %d4 |
| and.l %d0, %d4 |
| .yuv_blue_ok3: |
| cmp.l %d0, %d5 |
| bls.s .yuv_green_ok3 |
| spl.b %d5 |
| and.l %d0, %d5 |
| .yuv_green_ok3: |
| cmp.l %d0, %d6 |
| bls.s .yuv_red_ok3 |
| spl.b %d6 |
| and.l %d0, %d6 |
| .yuv_red_ok3: |
| .yuv_all_ok3: |
| |
| lsr.l #1, %d6 /* pack, convert to RGB565 and output */ |
| lsr.l #1, %d4 |
| lsl.l #6, %d6 |
| or.l %d6, %d5 |
| lsl.l #5, %d5 |
| or.l %d5, %d4 |
| move.w %d4, (%a0) |
| |
| /* luma for second pixel */ |
| clr.l %d4 /* load y component */ |
| move.b (%a1)+, %d4 |
| moveq.l #74, %d0 |
| muls.w %d0, %d4 /* %d4 = 36 * Y */ |
| asr.l #8, %d4 |
| subq.l #4, %d4 /* correction for (Y - 16) and rounding */ |
| |
| /* combine & write second pixel */ |
| add.l %d4, %d1 /* %d1 = blue */ |
| add.l %d4, %d2 /* %d2 = green */ |
| add.l %d4, %d3 /* %d3 = red */ |
| |
| move.l %d1, %d0 /* clamping */ |
| or.l %d2, %d0 |
| or.l %d3, %d0 |
| asr.l #6, %d0 |
| beq.s .yuv_all_ok4 |
| moveq.l #63, %d0 |
| cmp.l %d0, %d1 |
| bls.s .yuv_blue_ok4 |
| spl.b %d1 |
| and.l %d0, %d1 |
| .yuv_blue_ok4: |
| cmp.l %d0, %d2 |
| bls.s .yuv_green_ok4 |
| spl.b %d2 |
| and.l %d0, %d2 |
| .yuv_green_ok4: |
| cmp.l %d0, %d3 |
| bls.s .yuv_red_ok4 |
| spl.b %d3 |
| and.l %d0, %d3 |
| .yuv_red_ok4: |
| .yuv_all_ok4: |
| |
| lsr.l #1, %d3 /* pack, convert to RGB565 and output */ |
| lsr.l #1, %d1 |
| lsl.l #6, %d3 |
| or.l %d3, %d2 |
| lsl.l #5, %d2 |
| or.l %d2, %d1 |
| move.w %d1, (%a0) |
| |
| cmp.l %a1, %a5 /* run %a1 up to end of line */ |
| bhi.w .yuv_line_loop2 |
| |
| movem.l (%sp), %d2-%d6/%a2-%a5 |
| lea.l (36, %sp), %sp /* restore registers */ |
| |
| rts |
| .lcd_write_yuv420_lines_end: |
| .size lcd_write_yuv420_lines, .lcd_write_yuv420_lines_end - lcd_write_yuv420_lines |