1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Jens Arnold 2008-01-12 00:59:18 +00:00
parent 9f686700d4
commit 41cd44caa7
3 changed files with 339 additions and 134 deletions

View file

@ -694,6 +694,7 @@ target/arm/ata-pp5020.c
target/arm/ipod/adc-ipod-pcf.c target/arm/ipod/adc-ipod-pcf.c
target/arm/ipod/backlight-4g_color.c target/arm/ipod/backlight-4g_color.c
target/arm/ipod/button-clickwheel.c target/arm/ipod/button-clickwheel.c
target/arm/ipod/lcd-as-gray.S
target/arm/ipod/lcd-gray.c target/arm/ipod/lcd-gray.c
target/arm/ipod/power-ipod.c target/arm/ipod/power-ipod.c
target/arm/ipod/powermgmt-ipod-pcf.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/adc-ipod-pcf.c
target/arm/ipod/3g/backlight-3g.c target/arm/ipod/3g/backlight-3g.c
target/arm/ipod/button-1g-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/lcd-gray.c
target/arm/ipod/power-ipod.c target/arm/ipod/power-ipod.c
target/arm/ipod/powermgmt-ipod-pcf.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/backlight-1g2g.c
target/arm/ipod/1g2g/powermgmt-1g2g.c target/arm/ipod/1g2g/powermgmt-1g2g.c
target/arm/ipod/button-1g-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/lcd-gray.c
target/arm/ipod/power-ipod.c target/arm/ipod/power-ipod.c
target/arm/usb-fw-pp5002.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/adc-ipod-pcf.c
target/arm/ipod/backlight-mini1g_mini2g.c target/arm/ipod/backlight-mini1g_mini2g.c
target/arm/ipod/button-mini1g.c target/arm/ipod/button-mini1g.c
target/arm/ipod/lcd-as-gray.S
target/arm/ipod/lcd-gray.c target/arm/ipod/lcd-gray.c
target/arm/ipod/power-ipod.c target/arm/ipod/power-ipod.c
target/arm/ipod/powermgmt-ipod-pcf.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/adc-ipod-pcf.c
target/arm/ipod/backlight-mini1g_mini2g.c target/arm/ipod/backlight-mini1g_mini2g.c
target/arm/ipod/button-clickwheel.c target/arm/ipod/button-clickwheel.c
target/arm/ipod/lcd-as-gray.S
target/arm/ipod/lcd-gray.c target/arm/ipod/lcd-gray.c
target/arm/ipod/power-ipod.c target/arm/ipod/power-ipod.c
target/arm/ipod/powermgmt-ipod-pcf.c target/arm/ipod/powermgmt-ipod-pcf.c

View file

@ -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

View file

@ -74,36 +74,15 @@ static unsigned short contrast_reg_h;
static int addr_offset; static int addr_offset;
#if defined(IPOD_MINI) || defined(IPOD_MINI2G) #if defined(IPOD_MINI) || defined(IPOD_MINI2G)
static int pix_offset; static int pix_offset;
void lcd_write_data_shifted(const fb_data* p_bytes, int count);
#endif #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 */ /* wait for LCD with timeout */
static inline void lcd_wait_write(void) static inline void lcd_wait_write(void)
{ {
while (LCD1_CONTROL & LCD1_BUSY_MASK); 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
{
lcd_wait_write();
#ifdef IPOD_MINI2G
LCD1_CMD = data | 0x760000;
#else
LCD1_DATA = data >> 8;
lcd_wait_write();
LCD1_DATA = data & 0xff;
#endif
}
/* send LCD command */ /* send LCD command */
static void lcd_prepare_cmd(unsigned cmd) static void lcd_prepare_cmd(unsigned cmd)
{ {
@ -120,8 +99,20 @@ static void lcd_prepare_cmd(unsigned cmd)
/* send LCD command and data */ /* send LCD command and data */
static void lcd_cmd_and_data(unsigned cmd, unsigned data) static void lcd_cmd_and_data(unsigned cmd, unsigned data)
{ {
lcd_prepare_cmd(cmd); lcd_wait_write();
lcd_send_data(data); #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
} }
/* LCD init */ /* LCD init */
@ -230,27 +221,29 @@ void lcd_set_invert_display(bool yesno)
void lcd_set_flip(bool yesno) void lcd_set_flip(bool yesno)
{ {
#if defined(IPOD_MINI) || defined(IPOD_MINI2G) #if defined(IPOD_MINI) || defined(IPOD_MINI2G)
if (yesno) { if (yesno)
/* 168x112, inverse COM order */ { /* 168x112, inverse COM order */
lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x020d); lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x020d);
lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x8316); /* 22..131 */ lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x8316); /* 22..131 */
addr_offset = (22 << 5) | (20 - 4); addr_offset = (22 << 5) | (20 - 4);
pix_offset = -2; 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_DRV_OUTPUT_CONTROL, 0x010d);
lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x6d00); /* 0..109 */ lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x6d00); /* 0..109 */
addr_offset = 20; addr_offset = 20;
pix_offset = 0; pix_offset = 0;
} }
#else #else
if (yesno) { if (yesno)
/* 168x128, inverse SEG & COM order */ { /* 168x128, inverse SEG & COM order */
lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x030f); lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x030f);
lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x8304); /* 4..131 */ lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x8304); /* 4..131 */
addr_offset = (4 << 5) | (20 - 1); addr_offset = (4 << 5) | (20 - 1);
} else { }
/* 168x128 */ else
{ /* 168x128 */
lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x000f); lcd_cmd_and_data(R_DRV_OUTPUT_CONTROL, 0x000f);
lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x7f00); /* 0..127 */ lcd_cmd_and_data(R_1ST_SCR_DRV_POS, 0x7f00); /* 0..127 */
addr_offset = 20; addr_offset = 20;
@ -279,108 +272,38 @@ void lcd_enable(bool on)
/*** update functions ***/ /*** update functions ***/
/* Helper function. */
void lcd_mono_data(const unsigned char *data, int count);
/* Performance function that works with an external buffer /* Performance function that works with an external buffer
note that x, bwidtht and stride are in 8-pixel units! */ note that x, bwidtht and stride are in 8-pixel units! */
void lcd_blit(const unsigned char* data, int bx, int y, int bwidth, void lcd_blit(const unsigned char* data, int bx, int y, int bwidth,
int height, int stride) int height, int stride)
{ {
const unsigned char *src, *src_end; while (height--)
{
while (height--) {
src = data;
src_end = data + bwidth;
lcd_cmd_and_data(R_RAM_ADDR_SET, (y++ << 5) + addr_offset - bx); lcd_cmd_and_data(R_RAM_ADDR_SET, (y++ << 5) + addr_offset - bx);
lcd_prepare_cmd(R_RAM_DATA); lcd_prepare_cmd(R_RAM_DATA);
do {
unsigned byte = *src++; lcd_mono_data(data, bwidth);
lcd_send_data((dibits[byte>>4] << 8) | dibits[byte&0x0f]);
} while (src < src_end);
data += stride; 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 /* Performance function that works with an external buffer
note that bx and bwidth are in 8-pixel units! */ note that bx and bwidth are in 8-pixel units! */
void lcd_grey_phase_blit(unsigned char *values, unsigned char *phases, void lcd_grey_phase_blit(unsigned char *values, unsigned char *phases,
int bx, int y, int bwidth, int height, int stride) int bx, int y, int bwidth, int height, int stride)
{ {
unsigned char *val, *ph; while (height--)
int bw; {
while (height--) {
lcd_cmd_and_data(R_RAM_ADDR_SET, (y++ << 5) + addr_offset - bx); lcd_cmd_and_data(R_RAM_ADDR_SET, (y++ << 5) + addr_offset - bx);
lcd_prepare_cmd(R_RAM_DATA); lcd_prepare_cmd(R_RAM_DATA);
val = values; lcd_grey_data(values, phases, bwidth);
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"
);
values += stride; values += stride;
phases += stride; phases += stride;
} }
@ -407,30 +330,17 @@ void lcd_update_rect(int x, int y, int width, int height)
x >>= 3; x >>= 3;
width = xmax - x + 1; width = xmax - x + 1;
for (; y <= ymax; y++) { for (; y <= ymax; y++)
unsigned char *data, *data_end; {
lcd_cmd_and_data(R_RAM_ADDR_SET, (y << 5) + addr_offset - x); lcd_cmd_and_data(R_RAM_ADDR_SET, (y << 5) + addr_offset - x);
lcd_prepare_cmd(R_RAM_DATA); 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 defined(IPOD_MINI) || defined(IPOD_MINI2G)
if (pix_offset == -2) { if (pix_offset == -2)
unsigned cur_word = *data++; lcd_write_data_shifted(&lcd_framebuffer[y][2*x], width);
do { else
cur_word = (cur_word << 8) | *data++;
cur_word = (cur_word << 8) | *data++;
lcd_send_data((cur_word >> 4) & 0xffff);
} while (data <= data_end);
} else
#endif #endif
{ lcd_write_data(&lcd_framebuffer[y][2*x], width);
do {
unsigned highbyte = *data++;
lcd_send_data((highbyte << 8) | *data++);
} while (data < data_end);
}
} }
} }