forked from len0rd/rockbox
iPod Video: Further optimised LCD data transfer (5..6% speedup, but increase in FPS measured with test_fps is less), making use of the fact that the low address bits aren't decoded by the BCM. Major cleanup of the driver, and introduced register names.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15341 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
868d3ce39c
commit
b05066de12
2 changed files with 118 additions and 105 deletions
|
|
@ -17,6 +17,47 @@
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
.section .icode, "ax", %progbits
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
.global lcd_write_data
|
||||||
|
.type lcd_write_data, %function
|
||||||
|
/* r0 = addr */
|
||||||
|
lcd_write_data: /* r1 = pixel count */
|
||||||
|
stmfd sp!, {r4-r6}
|
||||||
|
mov r2, #0x30000000 /* LCD data port */
|
||||||
|
|
||||||
|
tst r0, #2 /* first pixel unaligned? */
|
||||||
|
ldrneh r3, [r0], #2
|
||||||
|
strneh r3, [r2]
|
||||||
|
subne r1, r1, #1
|
||||||
|
|
||||||
|
subs r1, r1, #16
|
||||||
|
.loop16:
|
||||||
|
ldmgeia r0!, {r3-r6}
|
||||||
|
stmgeia r2, {r3-r6}
|
||||||
|
ldmgeia r0!, {r3-r6}
|
||||||
|
stmgeia r2, {r3-r6}
|
||||||
|
subges r1, r1, #16
|
||||||
|
bge .loop16
|
||||||
|
|
||||||
|
/* no need to correct the count, we're just checking bits from now */
|
||||||
|
tst r1, #8
|
||||||
|
ldmneia r0!, {r3-r6}
|
||||||
|
stmneia r2, {r3-r6}
|
||||||
|
tst r1, #4
|
||||||
|
ldmneia r0!, {r3-r4}
|
||||||
|
stmneia r2, {r3-r4}
|
||||||
|
tst r1, #2
|
||||||
|
ldrne r3, [r0], #4
|
||||||
|
strne r3, [r2]
|
||||||
|
tst r1, #1
|
||||||
|
ldrneh r3, [r0]
|
||||||
|
strneh r3, [r2]
|
||||||
|
|
||||||
|
ldmfd sp!, {r4-r6}
|
||||||
|
bx lr
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* void lcd_write_yuv_420_lines(unsigned char const * const src[3],
|
* void lcd_write_yuv_420_lines(unsigned char const * const src[3],
|
||||||
* int width,
|
* int width,
|
||||||
|
|
@ -30,7 +71,6 @@
|
||||||
* |G| = |74 -24 -51| |Cb - 128| >> 8
|
* |G| = |74 -24 -51| |Cb - 128| >> 8
|
||||||
* |B| |74 128 0| |Cr - 128| >> 9
|
* |B| |74 128 0| |Cr - 128| >> 9
|
||||||
*/
|
*/
|
||||||
.section .icode, "ax", %progbits
|
|
||||||
.align 2
|
.align 2
|
||||||
.global lcd_write_yuv420_lines
|
.global lcd_write_yuv420_lines
|
||||||
.type lcd_write_yuv420_lines, %function
|
.type lcd_write_yuv420_lines, %function
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,25 @@
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
|
/* The BCM bus width is 16 bits. But since the low address bits aren't decoded
|
||||||
|
* by the chip (the 3 BCM address bits are mapped to address bits 16..18 of the
|
||||||
|
* PP5022), writing 32 bits (and even more, using 'stmia') at once works. */
|
||||||
|
#define BCM_DATA (*(volatile unsigned short*)(0x30000000))
|
||||||
|
#define BCM_DATA32 (*(volatile unsigned long *)(0x30000000))
|
||||||
|
#define BCM_WR_ADDR (*(volatile unsigned short*)(0x30010000))
|
||||||
|
#define BCM_WR_ADDR32 (*(volatile unsigned long *)(0x30010000))
|
||||||
|
#define BCM_RD_ADDR (*(volatile unsigned short*)(0x30020000))
|
||||||
|
#define BCM_RD_ADDR32 (*(volatile unsigned long *)(0x30020000))
|
||||||
|
#define BCM_CONTROL (*(volatile unsigned short*)(0x30030000))
|
||||||
|
|
||||||
|
#define BCM_ALT_DATA (*(volatile unsigned short*)(0x30040000))
|
||||||
|
#define BCM_ALT_DATA32 (*(volatile unsigned long *)(0x30040000))
|
||||||
|
#define BCM_ALT_WR_ADDR (*(volatile unsigned short*)(0x30050000))
|
||||||
|
#define BCM_ALT_WR_ADDR32 (*(volatile unsigned long *)(0x30050000))
|
||||||
|
#define BCM_ALT_RD_ADDR (*(volatile unsigned short*)(0x30060000))
|
||||||
|
#define BCM_ALT_RD_ADDR32 (*(volatile unsigned long *)(0x30060000))
|
||||||
|
#define BCM_ALT_CONTROL (*(volatile unsigned short*)(0x30070000))
|
||||||
|
|
||||||
/*** hardware configuration ***/
|
/*** hardware configuration ***/
|
||||||
|
|
||||||
void lcd_set_contrast(int val)
|
void lcd_set_contrast(int val)
|
||||||
|
|
@ -74,66 +93,63 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
|
||||||
|
|
||||||
static inline void lcd_bcm_write32(unsigned address, unsigned value)
|
static inline void lcd_bcm_write32(unsigned address, unsigned value)
|
||||||
{
|
{
|
||||||
/* write out destination address as two 16bit values */
|
/* write out destination address */
|
||||||
outw(address, 0x30010000);
|
BCM_WR_ADDR32 = address;
|
||||||
outw((address >> 16), 0x30010000);
|
|
||||||
|
|
||||||
/* wait for it to be write ready */
|
/* wait for it to be write ready */
|
||||||
while ((inw(0x30030000) & 0x2) == 0);
|
while (!(BCM_CONTROL & 0x2));
|
||||||
|
|
||||||
/* write out the value low 16, high 16 */
|
/* write out the value */
|
||||||
outw(value, 0x30000000);
|
BCM_DATA32 = value;
|
||||||
outw((value >> 16), 0x30000000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcd_bcm_setup_rect(unsigned cmd,
|
static void lcd_bcm_setup_rect(unsigned cmd,
|
||||||
unsigned start_horiz,
|
unsigned x,
|
||||||
unsigned start_vert,
|
unsigned y,
|
||||||
unsigned max_horiz,
|
unsigned width,
|
||||||
unsigned max_vert,
|
unsigned height)
|
||||||
unsigned count)
|
|
||||||
{
|
{
|
||||||
lcd_bcm_write32(0x1F8, 0xFFFA0005);
|
lcd_bcm_write32(0x1F8, 0xFFFA0005);
|
||||||
lcd_bcm_write32(0xE0000, cmd);
|
lcd_bcm_write32(0xE0000, cmd);
|
||||||
lcd_bcm_write32(0xE0004, start_horiz);
|
lcd_bcm_write32(0xE0004, x);
|
||||||
lcd_bcm_write32(0xE0008, start_vert);
|
lcd_bcm_write32(0xE0008, y);
|
||||||
lcd_bcm_write32(0xE000C, max_horiz);
|
lcd_bcm_write32(0xE000C, x + width - 1);
|
||||||
lcd_bcm_write32(0xE0010, max_vert);
|
lcd_bcm_write32(0xE0010, y + height - 1);
|
||||||
lcd_bcm_write32(0xE0014, count);
|
lcd_bcm_write32(0xE0014, (width * height) << 1);
|
||||||
lcd_bcm_write32(0xE0018, count);
|
lcd_bcm_write32(0xE0018, (width * height) << 1);
|
||||||
lcd_bcm_write32(0xE001C, 0);
|
lcd_bcm_write32(0xE001C, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned lcd_bcm_read32(unsigned address) {
|
static inline unsigned lcd_bcm_read32(unsigned address)
|
||||||
while ((inw(0x30020000) & 1) == 0);
|
{
|
||||||
|
while (!(BCM_RD_ADDR & 1));
|
||||||
|
|
||||||
/* write out destination address as two 16bit values */
|
/* write out destination address */
|
||||||
outw(address, 0x30020000);
|
BCM_RD_ADDR32 = address;
|
||||||
outw((address >> 16), 0x30020000);
|
|
||||||
|
|
||||||
/* wait for it to be read ready */
|
/* wait for it to be read ready */
|
||||||
while ((inw(0x30030000) & 0x10) == 0);
|
while (!(BCM_CONTROL & 0x10));
|
||||||
|
|
||||||
/* read the value */
|
/* read the value */
|
||||||
return inw(0x30000000) | inw(0x30000000) << 16;
|
return BCM_DATA32;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int finishup_needed = 0;
|
static bool finishup_needed = false;
|
||||||
|
|
||||||
/* Update a fraction of the display. */
|
/* Update a fraction of the display. */
|
||||||
void lcd_update_rect(int x, int y, int width, int height) ICODE_ATTR;
|
|
||||||
void lcd_update_rect(int x, int y, int width, int height)
|
void lcd_update_rect(int x, int y, int width, int height)
|
||||||
{
|
{
|
||||||
{
|
const fb_data *addr;
|
||||||
int endy = x + width;
|
|
||||||
/* Ensure x and width are both even - so we can read 32-bit aligned
|
if (x + width >= LCD_WIDTH)
|
||||||
data from lcd_framebuffer */
|
width = LCD_WIDTH - x;
|
||||||
x &= ~1;
|
if (y + height >= LCD_HEIGHT)
|
||||||
width &= ~1;
|
height = LCD_HEIGHT - y;
|
||||||
if (x + width < endy) {
|
|
||||||
width += 2;
|
if ((width <= 0) || (height <= 0))
|
||||||
}
|
return; /* Nothing left to do - 0 is harmful to lcd_write_data(). */
|
||||||
}
|
|
||||||
|
addr = &lcd_framebuffer[y][x];
|
||||||
|
|
||||||
if (finishup_needed)
|
if (finishup_needed)
|
||||||
{
|
{
|
||||||
|
|
@ -146,58 +162,28 @@ void lcd_update_rect(int x, int y, int width, int height)
|
||||||
data = lcd_bcm_read32(0x1F8);
|
data = lcd_bcm_read32(0x1F8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lcd_bcm_read32(0x1FC);
|
lcd_bcm_read32(0x1FC);
|
||||||
|
|
||||||
|
lcd_bcm_setup_rect(0x34, x, y, width, height);
|
||||||
|
|
||||||
|
/* write out destination address */
|
||||||
|
BCM_WR_ADDR32 = 0xE0020;
|
||||||
|
|
||||||
|
while (!(BCM_CONTROL & 0x2)); /* wait for it to be write ready */
|
||||||
|
|
||||||
|
do
|
||||||
{
|
{
|
||||||
int rect1, rect2, rect3, rect4;
|
lcd_write_data(addr, width);
|
||||||
int count = (width * height) << 1;
|
addr += LCD_WIDTH;
|
||||||
/* calculate the drawing region */
|
|
||||||
rect1 = x; /* start horiz */
|
|
||||||
rect2 = y; /* start vert */
|
|
||||||
rect3 = (x + width) - 1; /* max horiz */
|
|
||||||
rect4 = (y + height) - 1; /* max vert */
|
|
||||||
|
|
||||||
/* setup the drawing region */
|
|
||||||
lcd_bcm_setup_rect(0x34, rect1, rect2, rect3, rect4, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write out destination address as two 16bit values */
|
|
||||||
outw((0xE0020 & 0xffff), 0x30010000);
|
|
||||||
outw((0xE0020 >> 16), 0x30010000);
|
|
||||||
|
|
||||||
/* wait for it to be write ready */
|
|
||||||
while ((inw(0x30030000) & 0x2) == 0);
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned short *src = (unsigned short*)&lcd_framebuffer[y][x];
|
|
||||||
unsigned short *end = &src[LCD_WIDTH * height];
|
|
||||||
int line_rem = (LCD_WIDTH - width);
|
|
||||||
while (src < end) {
|
|
||||||
/* Duff's Device to unroll loop */
|
|
||||||
register int count = width ;
|
|
||||||
register int n=( count + 7 ) / 8;
|
|
||||||
switch( count % 8 ) {
|
|
||||||
case 0: do{ outw(*(src++), 0x30000000);
|
|
||||||
case 7: outw(*(src++), 0x30000000);
|
|
||||||
case 6: outw(*(src++), 0x30000000);
|
|
||||||
case 5: outw(*(src++), 0x30000000);
|
|
||||||
case 4: outw(*(src++), 0x30000000);
|
|
||||||
case 3: outw(*(src++), 0x30000000);
|
|
||||||
case 2: outw(*(src++), 0x30000000);
|
|
||||||
case 1: outw(*(src++), 0x30000000);
|
|
||||||
} while(--n>0);
|
|
||||||
}
|
|
||||||
src += line_rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
while (--height > 0);
|
||||||
|
|
||||||
/* Top-half of original lcd_bcm_finishup() function */
|
/* Top-half of original lcd_bcm_finishup() function */
|
||||||
outw(0x31, 0x30030000);
|
BCM_CONTROL = 0x31;
|
||||||
|
|
||||||
lcd_bcm_read32(0x1FC);
|
lcd_bcm_read32(0x1FC);
|
||||||
|
|
||||||
finishup_needed = 1;
|
finishup_needed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the display.
|
/* Update the display.
|
||||||
|
|
@ -242,25 +228,12 @@ void lcd_yuv_blit(unsigned char * const src[3],
|
||||||
|
|
||||||
lcd_bcm_read32(0x1FC);
|
lcd_bcm_read32(0x1FC);
|
||||||
|
|
||||||
{
|
lcd_bcm_setup_rect(0x34, x, y, width, height);
|
||||||
int rect1, rect2, rect3, rect4;
|
|
||||||
int count = (width * height) << 1;
|
|
||||||
/* calculate the drawing region */
|
|
||||||
rect1 = x; /* start horiz */
|
|
||||||
rect2 = y; /* start vert */
|
|
||||||
rect3 = (x + width) - 1; /* max horiz */
|
|
||||||
rect4 = (y + height) - 1; /* max vert */
|
|
||||||
|
|
||||||
/* setup the drawing region */
|
/* write out destination address */
|
||||||
lcd_bcm_setup_rect(0x34, rect1, rect2, rect3, rect4, count);
|
BCM_WR_ADDR32 = 0xE0020;
|
||||||
}
|
|
||||||
|
|
||||||
/* write out destination address as two 16bit values */
|
while (!(BCM_CONTROL & 0x2)); /* wait for it to be write ready */
|
||||||
outw((0xE0020 & 0xffff), 0x30010000);
|
|
||||||
outw((0xE0020 >> 16), 0x30010000);
|
|
||||||
|
|
||||||
/* wait for it to be write ready */
|
|
||||||
while ((inw(0x30030000) & 0x2) == 0);
|
|
||||||
|
|
||||||
height >>= 1;
|
height >>= 1;
|
||||||
do
|
do
|
||||||
|
|
@ -274,9 +247,9 @@ void lcd_yuv_blit(unsigned char * const src[3],
|
||||||
while (--height > 0);
|
while (--height > 0);
|
||||||
|
|
||||||
/* Top-half of original lcd_bcm_finishup() function */
|
/* Top-half of original lcd_bcm_finishup() function */
|
||||||
outw(0x31, 0x30030000);
|
BCM_CONTROL = 0x31;
|
||||||
|
|
||||||
lcd_bcm_read32(0x1FC);
|
lcd_bcm_read32(0x1FC);
|
||||||
|
|
||||||
finishup_needed = 1;
|
finishup_needed = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue