From 41cd44caa7b4799dcc14eda33f0f5cf93152a6e0 Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Sat, 12 Jan 2008 00:59:18 +0000 Subject: Greyscale ipod lcd driver: * Assembler optimised low level functions. PP5002 targets benefit most (lcd_update() speedup >50%, and the greyscale overlay no longer makes mp3 playback skip). * Consistent brace placement style. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16060 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/ipod/lcd-as-gray.S | 290 +++++++++++++++++++++++++++++++++ firmware/target/arm/ipod/lcd-gray.c | 176 +++++--------------- 2 files changed, 333 insertions(+), 133 deletions(-) create mode 100644 firmware/target/arm/ipod/lcd-as-gray.S (limited to 'firmware/target') diff --git a/firmware/target/arm/ipod/lcd-as-gray.S b/firmware/target/arm/ipod/lcd-as-gray.S new file mode 100644 index 0000000000..d16d09b8e2 --- /dev/null +++ b/firmware/target/arm/ipod/lcd-as-gray.S @@ -0,0 +1,290 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 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" + +#if CONFIG_CPU == PP5002 + .section .icode,"ax",%progbits +#else + .text +#endif + .align 2 + + + .global lcd_write_data + .type lcd_write_data,%function + +lcd_write_data: + stmfd sp!, {r4, lr} + ldr r2, =LCD1_BASE + +.loop: + ldrb r3, [r0], #1 + +#ifdef IPOD_MINI2G + ldrb r4, [r0], #1 + orr r3, r4, r3, lsl #8 + orr r3, r3, #0x760000 +1: + ldr r4, [r2] + tst r4, #0x8000 + bne 1b + str r3, [r2, #0x08] +#else +1: + ldr r4, [r2] + tst r4, #0x8000 + bne 1b + str r3, [r2, #0x10] + + ldrb r3, [r0], #1 +1: + ldr r4, [r2] + tst r4, #0x8000 + bne 1b + str r3, [r2, #0x10] +#endif + + subs r1, r1, #1 + bne .loop + + ldmfd sp!, {r4, pc} + +.wd_end: + .size lcd_write_data,.wd_end-lcd_write_data + + +#ifdef IPOD_MINI2G + + .global lcd_write_data_shifted + .type lcd_write_data_shifted,%function + +lcd_write_data_shifted: + stmfd sp!, {r4-r6, lr} + ldr r2, =LCD1_BASE + mov r6, #0x760000 + ldrb r3, [r0], #1 + +.sloop: + ldrb r4, [r0], #1 + orr r3, r4, r3, lsl #8 + ldrb r4, [r0], #1 + orr r3, r4, r3, lsl #8 + mov r5, r3, lsl #12 + orr r5, r6, r5, lsr #16 +1: + ldr r4, [r2] + tst r4, #0x8000 + bne 1b + str r5, [r2, #0x08] + + subs r1, r1, #1 + bne .sloop + + ldmfd sp!, {r4-r6, pc} + +.wds_end: + .size lcd_write_data_shifted,.wds_end-lcd_write_data_shifted + +#elif defined IPOD_MINI + + .global lcd_write_data_shifted + .type lcd_write_data_shifted,%function + +lcd_write_data_shifted: + stmfd sp!, {r4, r5, lr} + ldr r2, =LCD1_BASE + ldrb r3, [r0], #1 + +.sloop: + ldrb r4, [r0], #1 + orr r3, r4, r3, lsl #8 + mov r5, r3, lsr #4 +1: + ldr r4, [r2] + tst r4, #0x8000 + bne 1b + str r5, [r2, #0x10] + + ldrb r4, [r0], #1 + orr r3, r4, r3, lsl #8 + mov r5, r3, lsr #4 +1: + ldr r4, [r2] + tst r4, #0x8000 + bne 1b + str r5, [r2, #0x10] + + subs r1, r1, #1 + bne .sloop + + ldmfd sp!, {r4, r5, pc} +.wds_end: + .size lcd_write_data_shifted,.wds_end-lcd_write_data_shifted + +#endif + + .global lcd_mono_data + .type lcd_mono_data,%function + +lcd_mono_data: + stmfd sp!, {r4-r6, lr} + ldr r2, =LCD1_BASE + adr r6, .dibits + +.mloop: + ldrb r3, [r0], #1 + mov r4, r3, lsr #4 + ldrb r5, [r6, r4] + +#ifdef IPOD_MINI2G + and r4, r3, #0x0f + ldrb r4, [r6, r4] + orr r5, r4, r5, lsl #8 + orr r5, r5, #0x760000 +1: + ldr r4, [r2] + tst r4, #0x8000 + bne 1b + str r5, [r2, #0x08] +#else +1: + ldr r4, [r2] + tst r4, #0x8000 + bne 1b + str r5, [r2, #0x10] + + and r4, r3, #0x0f + ldrb r5, [r6, r4] +1: + ldr r4, [r2] + tst r4, #0x8000 + bne 1b + str r5, [r2, #0x10] +#endif + + subs r1, r1, #1 + bne .mloop + + ldmfd sp!, {r4-r6, pc} + +.dibits: + .byte 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F + .byte 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF + +.md_end: + .size lcd_mono_data,.md_end-lcd_mono_data + + + .global lcd_grey_data + .type lcd_grey_data,%function + +/* A high performance function to write grey phase data to the display, + * one or multiple pixels. + * + * Arguments: + * r0 - pixel value data address + * r1 - pixel phase data address + * r2 - pixel block count + * + * Register usage: + * r3/r4 - current block of phases + * r5/r6 - current block of values + * r7 - lcd data accumulator + * r8 - phase signs mask + * r9 - lcd bridge address + */ + +lcd_grey_data: + stmfd sp!, {r4-r9, lr} + mov r8, #0x80 + orr r8, r8, r8, lsl #8 + orr r8, r8, r8, lsl #16 + ldr r9, =LCD1_BASE + +.greyloop: + ldmia r1, {r3-r4} /* Fetch 8 pixel phases */ + ldmia r0!, {r5-r6} /* Fetch 8 pixel values */ + +#ifdef IPOD_MINI2G /* Serial bridge mode */ + mov r7, #0x760000 + tst r3, #0x80 + orreq r7, r7, #0xc000 + tst r3, #0x8000 + orreq r7, r7, #0x3000 + tst r3, #0x800000 + orreq r7, r7, #0x0c00 + tst r3, #0x80000000 + orreq r7, r7, #0x0300 + bic r3, r3, r8 + add r3, r3, r5 +#else /* Parallel bridge mode */ + mov r7, #0 + tst r3, #0x80 + orreq r7, r7, #0xc0 + tst r3, #0x8000 + orreq r7, r7, #0x30 + tst r3, #0x800000 + orreq r7, r7, #0x0c + tst r3, #0x80000000 + orreq r7, r7, #0x03 + bic r3, r3, r8 + add r3, r3, r5 + +1: + ldr r5, [r9] + tst r5, #0x8000 + bne 1b + + str r7, [r9, #0x10] + mov r7, #0 +#endif + + tst r4, #0x80 + orreq r7, r7, #0xc0 + tst r4, #0x8000 + orreq r7, r7, #0x30 + tst r4, #0x800000 + orreq r7, r7, #0x0c + tst r4, #0x80000000 + orreq r7, r7, #0x03 + bic r4, r4, r8 + add r4, r4, r6 + + stmia r1!, {r3-r4} + +1: + ldr r5, [r9] + tst r5, #0x8000 + bne 1b +#ifdef IPOD_MINI2G + str r7, [r9, #0x08] +#else + str r7, [r9, #0x10] +#endif + + subs r2, r2, #1 + bne .greyloop + + ldmfd sp!, {r4-r9, pc} + +.gd_end: + .size lcd_grey_data,.gd_end-lcd_grey_data + diff --git a/firmware/target/arm/ipod/lcd-gray.c b/firmware/target/arm/ipod/lcd-gray.c index 5734480bee..b77d3eb7f6 100644 --- a/firmware/target/arm/ipod/lcd-gray.c +++ b/firmware/target/arm/ipod/lcd-gray.c @@ -74,56 +74,47 @@ static unsigned short contrast_reg_h; static int addr_offset; #if defined(IPOD_MINI) || defined(IPOD_MINI2G) static int pix_offset; +void lcd_write_data_shifted(const fb_data* p_bytes, int count); #endif -static const unsigned char dibits[16] ICONST_ATTR = { - 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, - 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF -}; - /* wait for LCD with timeout */ static inline void lcd_wait_write(void) { while (LCD1_CONTROL & LCD1_BUSY_MASK); } -/* send LCD data */ -#if CONFIG_CPU == PP5002 -STATICIRAM void ICODE_ATTR lcd_send_data(unsigned data) -#else -static void lcd_send_data(unsigned data) -#endif +/* send LCD command */ +static void lcd_prepare_cmd(unsigned cmd) { lcd_wait_write(); #ifdef IPOD_MINI2G - LCD1_CMD = data | 0x760000; + LCD1_CMD = cmd | 0x740000; #else - LCD1_DATA = data >> 8; + LCD1_CMD = 0; lcd_wait_write(); - LCD1_DATA = data & 0xff; + LCD1_CMD = cmd; #endif } -/* send LCD command */ -static void lcd_prepare_cmd(unsigned cmd) +/* send LCD command and data */ +static void lcd_cmd_and_data(unsigned cmd, unsigned data) { lcd_wait_write(); #ifdef IPOD_MINI2G LCD1_CMD = cmd | 0x740000; + lcd_wait_write(); + LCD1_CMD = data | 0x760000; #else LCD1_CMD = 0; lcd_wait_write(); LCD1_CMD = cmd; + lcd_wait_write(); + LCD1_DATA = data >> 8; + lcd_wait_write(); + LCD1_DATA = data & 0xff; #endif } -/* send LCD command and data */ -static void lcd_cmd_and_data(unsigned cmd, unsigned data) -{ - lcd_prepare_cmd(cmd); - lcd_send_data(data); -} - /* LCD init */ void lcd_init_device(void) { @@ -230,27 +221,29 @@ void lcd_set_invert_display(bool yesno) void lcd_set_flip(bool yesno) { #if defined(IPOD_MINI) || defined(IPOD_MINI2G) - if (yesno) { - /* 168x112, inverse COM order */ + if (yesno) + { /* 168x112, inverse COM order */ lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x020d); lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x8316); /* 22..131 */ addr_offset = (22 << 5) | (20 - 4); pix_offset = -2; - } else { - /* 168x112, inverse SEG order */ + } + else + { /* 168x112, inverse SEG order */ lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x010d); lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x6d00); /* 0..109 */ addr_offset = 20; pix_offset = 0; } #else - if (yesno) { - /* 168x128, inverse SEG & COM order */ + if (yesno) + { /* 168x128, inverse SEG & COM order */ lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x030f); lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x8304); /* 4..131 */ addr_offset = (4 << 5) | (20 - 1); - } else { - /* 168x128 */ + } + else + { /* 168x128 */ lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x000f); lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x7f00); /* 0..127 */ addr_offset = 20; @@ -279,108 +272,38 @@ void lcd_enable(bool on) /*** update functions ***/ +/* Helper function. */ +void lcd_mono_data(const unsigned char *data, int count); + /* Performance function that works with an external buffer note that x, bwidtht and stride are in 8-pixel units! */ void lcd_blit(const unsigned char* data, int bx, int y, int bwidth, int height, int stride) { - const unsigned char *src, *src_end; - - while (height--) { - src = data; - src_end = data + bwidth; + while (height--) + { lcd_cmd_and_data(R_RAM_ADDR_SET, (y++ << 5) + addr_offset - bx); lcd_prepare_cmd(R_RAM_DATA); - do { - unsigned byte = *src++; - lcd_send_data((dibits[byte>>4] << 8) | dibits[byte&0x0f]); - } while (src < src_end); + + lcd_mono_data(data, bwidth); data += stride; } } +/* Helper function for lcd_grey_phase_blit(). */ +void lcd_grey_data(unsigned char *values, unsigned char *phases, int count); + /* Performance function that works with an external buffer note that bx and bwidth are in 8-pixel units! */ void lcd_grey_phase_blit(unsigned char *values, unsigned char *phases, int bx, int y, int bwidth, int height, int stride) { - unsigned char *val, *ph; - int bw; - - while (height--) { + while (height--) + { lcd_cmd_and_data(R_RAM_ADDR_SET, (y++ << 5) + addr_offset - bx); lcd_prepare_cmd(R_RAM_DATA); - val = values; - ph = phases; - bw = bwidth; - asm volatile ( - "10: \n" - "ldmia %[ph], {r0-r1} \n" /* Fetch 8 pixel phases */ - "ldmia %[val]!, {r2-r3} \n" /* Fetch 8 pixel values */ -#ifdef IPOD_MINI2G - "mov r4, #0x7600 \n" -#else - "mov r4, #0 \n" -#endif - "tst r0, #0x80 \n" - "orreq r4, r4, #0xc0 \n" - "tst r0, #0x8000 \n" - "orreq r4, r4, #0x30 \n" - "tst r0, #0x800000 \n" - "orreq r4, r4, #0x0c \n" - "tst r0, #0x80000000 \n" - "orreq r4, r4, #0x03 \n" - "bic r0, r0, %[clbt] \n" - "add r0, r0, r2 \n" - -#ifdef IPOD_MINI2G - "mov r4, r4, lsl #8 \n" -#else - "1: \n" - "ldr r2, [%[lcdb]] \n" - "tst r2, #0x8000 \n" - "bne 1b \n" - - "str r4, [%[lcdb], #0x10] \n" - "mov r4, #0 \n" -#endif - - "tst r1, #0x80 \n" - "orreq r4, r4, #0xc0 \n" - "tst r1, #0x8000 \n" - "orreq r4, r4, #0x30 \n" - "tst r1, #0x800000 \n" - "orreq r4, r4, #0x0c \n" - "tst r1, #0x80000000 \n" - "orreq r4, r4, #0x03 \n" - "bic r1, r1, %[clbt] \n" - "add r1, r1, r3 \n" - - "stmia %[ph]!, {r0-r1} \n" - - "1: \n" - "ldr r2, [%[lcdb]] \n" - "tst r2, #0x8000 \n" - "bne 1b \n" -#ifdef IPOD_MINI2G - "str r4, [%[lcdb], #0x08] \n" -#else - "str r4, [%[lcdb], #0x10] \n" -#endif - - "subs %[bw], %[bw], #1 \n" - "bne 10b \n" - : /* outputs */ - [val]"+r"(val), - [ph] "+r"(ph), - [bw] "+r"(bw) - : /* inputs */ - [clbt]"r"(0x80808080), - [lcdb]"r"(LCD1_BASE) - : /* clobbers */ - "r0", "r1", "r2", "r3", "r4" - ); + lcd_grey_data(values, phases, bwidth); values += stride; phases += stride; } @@ -407,30 +330,17 @@ void lcd_update_rect(int x, int y, int width, int height) x >>= 3; width = xmax - x + 1; - for (; y <= ymax; y++) { - unsigned char *data, *data_end; - + for (; y <= ymax; y++) + { lcd_cmd_and_data(R_RAM_ADDR_SET, (y << 5) + addr_offset - x); lcd_prepare_cmd(R_RAM_DATA); - data = &lcd_framebuffer[y][2*x]; - data_end = data + 2 * width; #if defined(IPOD_MINI) || defined(IPOD_MINI2G) - if (pix_offset == -2) { - unsigned cur_word = *data++; - do { - cur_word = (cur_word << 8) | *data++; - cur_word = (cur_word << 8) | *data++; - lcd_send_data((cur_word >> 4) & 0xffff); - } while (data <= data_end); - } else + if (pix_offset == -2) + lcd_write_data_shifted(&lcd_framebuffer[y][2*x], width); + else #endif - { - do { - unsigned highbyte = *data++; - lcd_send_data((highbyte << 8) | *data++); - } while (data < data_end); - } + lcd_write_data(&lcd_framebuffer[y][2*x], width); } } -- cgit v1.2.3