From 418169aff8faf2cf90124cd95dba0af821cea73d Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Thu, 13 Oct 2022 11:03:53 -0400 Subject: Revert "Remove YUV blitting functions and LCD modes" This reverts commit fe6aa21e9eb88f49005863efd2003d0982920048. Change-Id: I8bb1e5d6c52ed1478002d2140ef494ec5d62b8e3 --- firmware/target/coldfire/iriver/h300/lcd-as-h300.S | 246 +++++++++++++++++++++ firmware/target/coldfire/iriver/h300/lcd-h300.c | 61 +++++ 2 files changed, 307 insertions(+) create mode 100644 firmware/target/coldfire/iriver/h300/lcd-as-h300.S (limited to 'firmware/target/coldfire/iriver') diff --git a/firmware/target/coldfire/iriver/h300/lcd-as-h300.S b/firmware/target/coldfire/iriver/h300/lcd-as-h300.S new file mode 100644 index 0000000000..223c183860 --- /dev/null +++ b/firmware/target/coldfire/iriver/h300/lcd-as-h300.S @@ -0,0 +1,246 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Jens Arnold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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() + * + * 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 RGB565: + * |R| |19611723 0 26881894| |Y' - 16| >> 27 + * |G| = |19611723 -6406711 -13692816| |Cb - 128| >> 26 + * |B| |19611723 33976259 0| |Cr - 128| >> 27 + * + * Needs EMAC set to saturated, signed integer mode. + * + * register usage: + * %a0 - LCD data port + * %a1 - Y pointer + * %a2 - C pointer + * %a3 - C width + * %a4 - Y end address + * %a5 - Y factor + * %a6 - BU factor + * %d0 - scratch + * %d1 - B, previous Y \ alternating + * %d2 - U / B, previous Y / + * %d3 - V / G + * %d4 - R / output pixel + * %d5 - GU factor + * %d6 - GV factor + * %d7 - RGB signed -> unsigned conversion mask + */ + .align 2 + .global lcd_write_yuv420_lines + .type lcd_write_yuv420_lines, @function + +lcd_write_yuv420_lines: + lea.l (-44, %sp), %sp /* free up some registers */ + movem.l %d2-%d7/%a2-%a6, (%sp) + + lea.l 0xf0000002, %a0 /* LCD data port */ + movem.l (44+4, %sp), %a1-%a3 /* Y data, C data, C width */ + lea.l (%a1, %a3*2), %a4 /* Y end address */ + + move.l #19611723, %a5 /* y factor */ + move.l #33976259, %a6 /* bu factor */ + move.l #-6406711, %d5 /* gu factor */ + move.l #-13692816, %d6 /* gv factor */ + move.l #0x8410, %d7 /* bitmask for signed->unsigned conversion + * of R, G and B within RGB565 at once */ + + /* chroma for first 2x2 pixel block */ + clr.l %d3 /* load v component */ + move.b (%a2, %a3), %d3 + clr.l %d2 /* load u component */ + move.b (%a2)+, %d2 + moveq.l #-128, %d0 + add.l %d0, %d2 + add.l %d0, %d3 + + mac.l %a6, %d2, %acc0 /* bu */ + mac.l %d5, %d2, %acc1 /* gu */ + mac.l %d6, %d3, %acc1 /* gv */ + move.l #26881894, %d0 /* rv factor */ + mac.l %d0, %d3, %acc2 /* rv */ + + /* luma for very first pixel (top left) */ + clr.l %d1 + move.b (%a1, %a3*2), %d1 + moveq.l #-126, %d0 + add.l %d1, %d0 /* y' (-0.5 ... +0.5) */ + mac.l %a5, %d0, %acc0 + mac.l %a5, %d0, %acc1 + mac.l %a5, %d0, %acc2 + + bra.b .yuv_line_entry + +.yuv_line_loop: + /* chroma for 2x2 pixel block */ + clr.l %d3 /* load v component */ + move.b (%a2, %a3), %d3 + clr.l %d2 /* load u component */ + move.b (%a2)+, %d2 + moveq.l #-128, %d0 + add.l %d0, %d2 + add.l %d0, %d3 + + mac.l %a6, %d2, %acc0 /* bu */ + mac.l %d5, %d2, %acc1 /* gu */ + mac.l %d6, %d3, %acc1 /* gv */ + move.l #26881894, %d0 /* rv factor */ + mac.l %d0, %d3, %acc2 /* rv */ + + /* luma for first pixel (top left) */ + clr.l %d1 + move.b (%a1, %a3*2), %d1 + moveq.l #-126, %d0 + add.l %d1, %d0 /* y' (-0.5 ... +0.5) */ + mac.l %a5, %d0, %acc0 + mac.l %a5, %d0, %acc1 + mac.l %a5, %d0, %acc2 + + move.w %d4, (%a0) + /* LCD write is delayed one pixel to use it for filling the EMAC latency */ + + /* convert to RGB565, pack and output */ +.yuv_line_entry: + moveq.l #27, %d0 + move.l %acc0, %d2 + move.l %acc1, %d3 + move.l %acc2, %d4 + lsr.l %d0, %d2 + lsr.l %d0, %d4 + moveq.l #26, %d0 + lsr.l %d0, %d3 + lsl.l #6, %d4 + or.l %d3, %d4 + lsl.l #5, %d4 + or.l %d2, %d4 + eor.l %d7, %d4 + + /* luma for second pixel (bottom left) as delta from the first */ + clr.l %d2 + move.b (%a1)+, %d2 + move.l %d2, %d0 + sub.l %d1, %d0 + mac.l %a5, %d0, %acc0 + mac.l %a5, %d0, %acc1 + mac.l %a5, %d0, %acc2 + + move.w %d4, (%a0) + /* LCD write is delayed one pixel to use it for filling the EMAC latency */ + + /* convert to RGB565, pack and output */ + moveq.l #27, %d0 + move.l %acc0, %d1 + move.l %acc1, %d3 + move.l %acc2, %d4 + lsr.l %d0, %d1 + lsr.l %d0, %d4 + moveq.l #26, %d0 + lsr.l %d0, %d3 + lsl.l #6, %d4 + or.l %d3, %d4 + lsl.l #5, %d4 + or.l %d1, %d4 + eor.l %d7, %d4 + + /* luma for third pixel (top right) as delta from the second */ + clr.l %d1 + move.b (%a1, %a3*2), %d1 + move.l %d1, %d0 + sub.l %d2, %d0 + mac.l %a5, %d0, %acc0 + mac.l %a5, %d0, %acc1 + mac.l %a5, %d0, %acc2 + + move.w %d4, (%a0) + /* LCD write is delayed one pixel to use it for filling the EMAC latency */ + + /* convert to RGB565, pack and output */ + moveq.l #27, %d0 + move.l %acc0, %d2 + move.l %acc1, %d3 + move.l %acc2, %d4 + lsr.l %d0, %d2 + lsr.l %d0, %d4 + moveq.l #26, %d0 + lsr.l %d0, %d3 + lsl.l #6, %d4 + or.l %d3, %d4 + lsl.l #5, %d4 + or.l %d2, %d4 + eor.l %d7, %d4 + + /* luma for fourth pixel (bottom right) as delta from the third */ + clr.l %d2 + move.b (%a1)+, %d2 + move.l %d2, %d0 + sub.l %d1, %d0 + mac.l %a5, %d0, %acc0 + mac.l %a5, %d0, %acc1 + mac.l %a5, %d0, %acc2 + + move.w %d4, (%a0) + /* LCD write is delayed one pixel to use it for filling the EMAC latency */ + + /* convert to RGB565, pack and output */ + moveq.l #27, %d0 + movclr.l %acc0, %d1 + movclr.l %acc1, %d3 + movclr.l %acc2, %d4 + lsr.l %d0, %d1 + lsr.l %d0, %d4 + moveq.l #26, %d0 + lsr.l %d0, %d3 + lsl.l #6, %d4 + or.l %d3, %d4 + lsl.l #5, %d4 + or.l %d1, %d4 + eor.l %d7, %d4 + + cmp.l %a1, %a4 /* run %a1 up to end of line */ + bhi.w .yuv_line_loop + + move.w %d4, (%a0) /* write (very) last pixel */ + + movem.l (%sp), %d2-%d7/%a2-%a6 + lea.l (44, %sp), %sp /* restore registers */ + rts +.yuv_end: + .size lcd_write_yuv420_lines, .yuv_end - lcd_write_yuv420_lines diff --git a/firmware/target/coldfire/iriver/h300/lcd-h300.c b/firmware/target/coldfire/iriver/h300/lcd-h300.c index 8d5370cdcf..7e73ea3905 100644 --- a/firmware/target/coldfire/iriver/h300/lcd-h300.c +++ b/firmware/target/coldfire/iriver/h300/lcd-h300.c @@ -325,6 +325,67 @@ bool lcd_active(void) /*** update functions ***/ +/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. + * y should have two lines of Y back to back, 2nd line first. + * c should contain the Cb and Cr data for the two lines of Y back to back. + * Needs EMAC set to saturated, signed integer mode. + */ +extern void lcd_write_yuv420_lines(const unsigned char *y, + const unsigned char *c, int cwidth); + +/* Performance function to blit a YUV bitmap directly to the LCD + * src_x, src_y, width and height should be even + * x, y, width and height have to be within LCD bounds + */ +void lcd_blit_yuv(unsigned char * const src[3], + int src_x, int src_y, int stride, + int x, int y, int width, int height) +{ + /* IRAM Y, Cb and Cb buffers. */ + unsigned char y_ibuf[LCD_WIDTH*2]; + unsigned char c_ibuf[LCD_WIDTH]; + const unsigned char *ysrc, *usrc, *vsrc; + const unsigned char *ysrc_max; + + if (!display_on) + return; + + LCD_MUTEX_LOCK(); + width &= ~1; /* stay on the safe side */ + height &= ~1; + + lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_HORZ); + /* Set start position and window */ + lcd_write_reg(R_VERT_RAM_ADDR_POS, ((xoffset + 219) << 8) | xoffset); + + ysrc = src[0] + src_y * stride + src_x; + usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1); + vsrc = src[2] + (src_y * stride >> 2) + (src_x >> 1); + ysrc_max = ysrc + height * stride; + + coldfire_set_macsr(EMAC_SATURATE); + do + { + lcd_write_reg(R_HORIZ_RAM_ADDR_POS, ((y + 1) << 8) | y); + lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y); + lcd_begin_write_gram(); + + memcpy(y_ibuf + width, ysrc, width); + memcpy(y_ibuf, ysrc + stride, width); + memcpy(c_ibuf, usrc, width >> 1); + memcpy(c_ibuf + (width >> 1), vsrc, width >> 1); + lcd_write_yuv420_lines(y_ibuf, c_ibuf, width >> 1); + + y += 2; + ysrc += 2 * stride; + usrc += stride >> 1; + vsrc += stride >> 1; + } + while (ysrc < ysrc_max) + ;; + LCD_MUTEX_UNLOCK(); +} + #ifndef BOOTLOADER /* LCD DMA ISR */ void DMA3(void) __attribute__ ((interrupt_handler, section(".icode"))); -- cgit v1.2.3