summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2008-01-12 00:59:18 +0000
committerJens Arnold <amiconn@rockbox.org>2008-01-12 00:59:18 +0000
commit41cd44caa7b4799dcc14eda33f0f5cf93152a6e0 (patch)
treefcaa7a94441ace95ba74faa9f01397a7d720a7d7
parent9f686700d47e8fcfa0fec65bfbfcf5d5cde3f752 (diff)
downloadrockbox-41cd44caa7b4799dcc14eda33f0f5cf93152a6e0.zip
rockbox-41cd44caa7b4799dcc14eda33f0f5cf93152a6e0.tar.gz
rockbox-41cd44caa7b4799dcc14eda33f0f5cf93152a6e0.tar.bz2
rockbox-41cd44caa7b4799dcc14eda33f0f5cf93152a6e0.tar.xz
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
-rw-r--r--firmware/SOURCES5
-rw-r--r--firmware/target/arm/ipod/lcd-as-gray.S290
-rw-r--r--firmware/target/arm/ipod/lcd-gray.c176
3 files changed, 338 insertions, 133 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index ca06d86..0f943a0 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -694,6 +694,7 @@ target/arm/ata-pp5020.c
target/arm/ipod/adc-ipod-pcf.c
target/arm/ipod/backlight-4g_color.c
target/arm/ipod/button-clickwheel.c
+target/arm/ipod/lcd-as-gray.S
target/arm/ipod/lcd-gray.c
target/arm/ipod/power-ipod.c
target/arm/ipod/powermgmt-ipod-pcf.c
@@ -762,6 +763,7 @@ target/arm/i2s-pp.c
target/arm/ipod/adc-ipod-pcf.c
target/arm/ipod/3g/backlight-3g.c
target/arm/ipod/button-1g-3g.c
+target/arm/ipod/lcd-as-gray.S
target/arm/ipod/lcd-gray.c
target/arm/ipod/power-ipod.c
target/arm/ipod/powermgmt-ipod-pcf.c
@@ -778,6 +780,7 @@ target/arm/ipod/1g2g/adc-ipod-1g2g.c
target/arm/ipod/1g2g/backlight-1g2g.c
target/arm/ipod/1g2g/powermgmt-1g2g.c
target/arm/ipod/button-1g-3g.c
+target/arm/ipod/lcd-as-gray.S
target/arm/ipod/lcd-gray.c
target/arm/ipod/power-ipod.c
target/arm/usb-fw-pp5002.c
@@ -794,6 +797,7 @@ target/arm/i2s-pp.c
target/arm/ipod/adc-ipod-pcf.c
target/arm/ipod/backlight-mini1g_mini2g.c
target/arm/ipod/button-mini1g.c
+target/arm/ipod/lcd-as-gray.S
target/arm/ipod/lcd-gray.c
target/arm/ipod/power-ipod.c
target/arm/ipod/powermgmt-ipod-pcf.c
@@ -811,6 +815,7 @@ target/arm/i2s-pp.c
target/arm/ipod/adc-ipod-pcf.c
target/arm/ipod/backlight-mini1g_mini2g.c
target/arm/ipod/button-clickwheel.c
+target/arm/ipod/lcd-as-gray.S
target/arm/ipod/lcd-gray.c
target/arm/ipod/power-ipod.c
target/arm/ipod/powermgmt-ipod-pcf.c
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 0000000..d16d09b
--- /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 5734480..b77d3eb 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);
}
}