From 8aeed2d32e4312da426a1ba16f975923adc3cfbe Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Fri, 12 Oct 2007 00:28:57 +0000 Subject: PP LCD drivers: * Optimised and cleaned up PP colour LCD drivers. Immeasurable speedup on iPod Color, huge speedup on small H10 (a factor of 3). Should be a bit faster on big H10 too. * Big H10 changed bitmap format, so needs reconfiguring + full rebuild. * Better register naming for the mono LCD bridge. Register names for the colour LCD bridge. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15082 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/config-h10.h | 2 +- firmware/export/pp5002.h | 10 +- firmware/export/pp5020.h | 25 ++++- firmware/target/arm/ipod/lcd-color_nano.c | 100 +++++++----------- firmware/target/arm/ipod/lcd-gray.c | 4 +- firmware/target/arm/iriver/h10/lcd-h10_20gb.c | 48 ++++----- firmware/target/arm/iriver/h10/lcd-h10_5gb.c | 117 ++++++++++------------ firmware/target/arm/sandisk/sansa-c200/lcd-c200.c | 8 +- 8 files changed, 142 insertions(+), 172 deletions(-) (limited to 'firmware') diff --git a/firmware/export/config-h10.h b/firmware/export/config-h10.h index 93ec226c50..8054152c77 100644 --- a/firmware/export/config-h10.h +++ b/firmware/export/config-h10.h @@ -39,7 +39,7 @@ #define LCD_WIDTH 160 #define LCD_HEIGHT 128 #define LCD_DEPTH 16 /* 65536 colours */ -#define LCD_PIXELFORMAT RGB565 /* rgb565 */ +#define LCD_PIXELFORMAT RGB565SWAPPED /* rgb565 byte-swapped */ /* Define this if your LCD can be enabled/disabled */ #define HAVE_LCD_ENABLE diff --git a/firmware/export/pp5002.h b/firmware/export/pp5002.h index c4baa7cfd3..b2e02f6174 100644 --- a/firmware/export/pp5002.h +++ b/firmware/export/pp5002.h @@ -23,11 +23,13 @@ #define DRAM_START 0x28000000 /* LCD bridge */ -#define LCD1_BASE (*(volatile unsigned long *)(0xc0001000)) -#define LCD1_CMD (*(volatile unsigned long *)(0xc0001008)) -#define LCD1_DATA (*(volatile unsigned long *)(0xc0001010)) +#define LCD1_BASE 0xc0001000 -#define LCD1_BUSY_MASK 0x8000 +#define LCD1_CONTROL (*(volatile unsigned long *)(0xc0001000)) +#define LCD1_CMD (*(volatile unsigned long *)(0xc0001008)) +#define LCD1_DATA (*(volatile unsigned long *)(0xc0001010)) + +#define LCD1_BUSY_MASK 0x8000 /* I2S controller */ #define IISCONFIG (*(volatile unsigned long *)(0xc0002500)) diff --git a/firmware/export/pp5020.h b/firmware/export/pp5020.h index 2c939300ab..5654a7de63 100644 --- a/firmware/export/pp5020.h +++ b/firmware/export/pp5020.h @@ -407,16 +407,33 @@ /* Note: didn't bother to see of levels 0 and 16 actually work */ /* First ("mono") LCD bridge */ -#define LCD1_BASE (*(volatile unsigned long *)(0x70003000)) -#define LCD1_CMD (*(volatile unsigned long *)(0x70003008)) -#define LCD1_DATA (*(volatile unsigned long *)(0x70003010)) +#define LCD1_BASE 0x70003000 -#define LCD1_BUSY_MASK 0x8000 +#define LCD1_CONTROL (*(volatile unsigned long *)(0x70003000)) +#define LCD1_CMD (*(volatile unsigned long *)(0x70003008)) +#define LCD1_DATA (*(volatile unsigned long *)(0x70003010)) + +#define LCD1_BUSY_MASK 0x8000 /* Serial Controller */ #define SERIAL0 (*(volatile unsigned long*)(0x70006000)) #define SERIAL1 (*(volatile unsigned long*)(0x70006040)) +/* Second ("color") LCD bridge */ +#define LCD2_BASE 0x70008a00 + +#define LCD2_PORT (*(volatile unsigned long*)(0x70008a0c)) +#define LCD2_BLOCK_CTRL (*(volatile unsigned long*)(0x70008a20)) +#define LCD2_BLOCK_CONFIG (*(volatile unsigned long*)(0x70008a24)) +#define LCD2_BLOCK_DATA (*(volatile unsigned long*)(0x70008b00)) + +#define LCD2_BUSY_MASK 0x80000000 +#define LCD2_CMD_MASK 0x80000000 +#define LCD2_DATA_MASK 0x81000000 + +#define LCD2_BLOCK_READY 0x04000000 +#define LCD2_BLOCK_TXOK 0x01000000 + /* I2C */ #define I2C_BASE 0x7000c000 diff --git a/firmware/target/arm/ipod/lcd-color_nano.c b/firmware/target/arm/ipod/lcd-color_nano.c index c17b99b859..f3a5819d6b 100644 --- a/firmware/target/arm/ipod/lcd-color_nano.c +++ b/firmware/target/arm/ipod/lcd-color_nano.c @@ -30,15 +30,6 @@ #include "system.h" #include "hwcompat.h" -/* check if number of useconds has past */ -static inline bool timer_check(int clock_start, int usecs) -{ - return ((int)(USEC_TIMER - clock_start)) >= usecs; -} - -#define IPOD_LCD_BASE 0x70008a0c -#define IPOD_LCD_BUSY_MASK 0x80000000 - /* LCD command codes for HD66789R */ #define LCD_CNTL_RAM_ADDR_SET 0x21 #define LCD_CNTL_WRITE_TO_GRAM 0x22 @@ -48,39 +39,25 @@ static inline bool timer_check(int clock_start, int usecs) /*** globals ***/ int lcd_type = 1; /* 0 = "old" Color/Photo, 1 = "new" Color & Nano */ -static void lcd_wait_write(void) -{ - if ((inl(IPOD_LCD_BASE) & IPOD_LCD_BUSY_MASK) != 0) { - int start = USEC_TIMER; - - do { - if ((inl(IPOD_LCD_BASE) & IPOD_LCD_BUSY_MASK) == 0) break; - } while (timer_check(start, 1000) == 0); - } -} - -static void lcd_send_lo(int v) -{ - lcd_wait_write(); - outl(v | 0x80000000, IPOD_LCD_BASE); -} - -static void lcd_send_hi(int v) +static inline void lcd_wait_write(void) { - lcd_wait_write(); - outl(v | 0x81000000, IPOD_LCD_BASE); + while (LCD2_PORT & LCD2_BUSY_MASK); } -static void lcd_cmd_data(int cmd, int data) +static void lcd_cmd_data(unsigned cmd, unsigned data) { - if (lcd_type == 0) { - lcd_send_lo(cmd); - lcd_send_lo(data); + if (lcd_type == 0) { /* 16 bit transfers */ + lcd_wait_write(); + LCD2_PORT = LCD2_CMD_MASK | cmd; + lcd_wait_write(); + LCD2_PORT = LCD2_CMD_MASK | data; } else { - lcd_send_lo(0x0); - lcd_send_lo(cmd); - lcd_send_hi((data >> 8) & 0xff); - lcd_send_hi(data & 0xff); + lcd_wait_write(); + LCD2_PORT = LCD2_CMD_MASK; + LCD2_PORT = LCD2_CMD_MASK | cmd; + lcd_wait_write(); + LCD2_PORT = LCD2_DATA_MASK | (data >> 8); + LCD2_PORT = LCD2_DATA_MASK | (data & 0xff); } } @@ -229,8 +206,9 @@ void lcd_yuv_blit(unsigned char * const src[3], lcd_cmd_data(LCD_CNTL_RAM_ADDR_SET, ((x0 << 8) | y0)); /* start drawing */ - lcd_send_lo(0x0); - lcd_send_lo(LCD_CNTL_WRITE_TO_GRAM); + lcd_wait_write(); + LCD2_PORT = LCD2_CMD_MASK; + LCD2_PORT = (LCD2_CMD_MASK|LCD_CNTL_WRITE_TO_GRAM); } const int stride_div_csub_x = stride/CSUB_X; @@ -257,8 +235,8 @@ void lcd_yuv_blit(unsigned char * const src[3], fb_data pixel1,pixel2; if (h==0) { - while ((inl(0x70008a20) & 0x4000000) == 0); - outl(0x0, 0x70008a24); + while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); + LCD2_BLOCK_CONFIG = 0; if (height == 0) break; @@ -272,9 +250,9 @@ void lcd_yuv_blit(unsigned char * const src[3], } height -= h; - outl(0x10000080, 0x70008a20); - outl((pixels_to_write - 1) | 0xc0010000, 0x70008a24); - outl(0x34000000, 0x70008a20); + LCD2_BLOCK_CTRL = 0x10000080; + LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1); + LCD2_BLOCK_CTRL = 0x34000000; } do @@ -368,10 +346,10 @@ void lcd_yuv_blit(unsigned char * const src[3], bbits = blue2 >> 16 ; pixel2 = swap16((rbits << 11) | (gbits << 5) | bbits); - while ((inl(0x70008a20) & 0x1000000) == 0); + while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK)); /* output 2 pixels */ - outl((pixel2<<16)|pixel1, 0x70008b00); + LCD2_BLOCK_DATA = (pixel2 << 16) | pixel1; } while (ysrc < row_end); @@ -379,8 +357,8 @@ void lcd_yuv_blit(unsigned char * const src[3], h--; } - while ((inl(0x70008a20) & 0x4000000) == 0); - outl(0x0, 0x70008a24); + while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); + LCD2_BLOCK_CONFIG = 0; } @@ -389,8 +367,7 @@ void lcd_update_rect(int x, int y, int width, int height) { int y0, x0, y1, x1; int newx,newwidth; - - unsigned long *addr = (unsigned long *)lcd_framebuffer; + unsigned long *addr; /* Ensure x and width are both even - so we can read 32-bit aligned data from lcd_framebuffer */ @@ -449,8 +426,9 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_cmd_data(LCD_CNTL_RAM_ADDR_SET, ((x0 << 8) | y0)); /* start drawing */ - lcd_send_lo(0x0); - lcd_send_lo(LCD_CNTL_WRITE_TO_GRAM); + lcd_wait_write(); + LCD2_PORT = LCD2_CMD_MASK; + LCD2_PORT = (LCD2_CMD_MASK|LCD_CNTL_WRITE_TO_GRAM); } addr = (unsigned long*)&lcd_framebuffer[y][x]; @@ -468,28 +446,26 @@ void lcd_update_rect(int x, int y, int width, int height) pixels_to_write = (width * h) * 2; } - outl(0x10000080, 0x70008a20); - outl((pixels_to_write - 1) | 0xc0010000, 0x70008a24); - outl(0x34000000, 0x70008a20); + LCD2_BLOCK_CTRL = 0x10000080; + LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1); + LCD2_BLOCK_CTRL = 0x34000000; /* for each row */ for (r = 0; r < h; r++) { /* for each column */ for (c = 0; c < width; c += 2) { - while ((inl(0x70008a20) & 0x1000000) == 0); + while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK)); /* output 2 pixels */ - outl(*(addr++), 0x70008b00); + LCD2_BLOCK_DATA = *addr++; } - addr += (LCD_WIDTH - width)/2; } - while ((inl(0x70008a20) & 0x4000000) == 0); - - outl(0x0, 0x70008a24); + while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); + LCD2_BLOCK_CONFIG = 0; - height = height - h; + height -= h; } } diff --git a/firmware/target/arm/ipod/lcd-gray.c b/firmware/target/arm/ipod/lcd-gray.c index bea1ed46ed..c375d95ea6 100644 --- a/firmware/target/arm/ipod/lcd-gray.c +++ b/firmware/target/arm/ipod/lcd-gray.c @@ -84,7 +84,7 @@ static const unsigned char dibits[16] ICONST_ATTR = { /* wait for LCD with timeout */ static inline void lcd_wait_write(void) { - while (LCD1_BASE & LCD1_BUSY_MASK); + while (LCD1_CONTROL & LCD1_BUSY_MASK); } /* send LCD data */ @@ -155,7 +155,7 @@ void lcd_init_device(void) power_reg_h = 0x1100; #elif defined IPOD_MINI2G lcd_wait_write(); - LCD1_BASE = (LCD1_BASE & ~0x1f00000) | 0x1700000; + LCD1_CONTROL = (LCD1_CONTROL & ~0x1f00000) | 0x1700000; #endif lcd_cmd_and_data(R_POWER_CONTROL, POWER_REG_H | 0xc); diff --git a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c index f6ea87c1d0..a52e98f364 100644 --- a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c +++ b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c @@ -22,12 +22,6 @@ #include "kernel.h" #include "system.h" -/* check if number of useconds has past */ -static inline bool timer_check(int clock_start, int usecs) -{ - return ((int)(USEC_TIMER - clock_start)) >= usecs; -} - /** Initialized in lcd_init_device() **/ /* Is the power turned on? */ static bool power_on; @@ -43,17 +37,6 @@ static int lcd_contrast; /* Forward declarations */ static void lcd_display_off(void); -/* Hardware address of LCD. Bits are: - * 31 - set to write, poll for completion. - * 24 - 0 for command, 1 for data - * 7..0 - command/data to send - * Commands/Data are always sent in 16-bits, msb first. - */ -#define LCD_BASE *(volatile unsigned int *)0x70008a0c -#define LCD_BUSY_MASK 0x80000000 -#define LCD_CMD 0x80000000 -#define LCD_DATA 0x81000000 - /* register defines for the Renesas HD66773R */ #define R_START_OSC 0x00 #define R_DEVICE_CODE_READ 0x00 @@ -91,31 +74,34 @@ static void lcd_display_off(void); static inline void lcd_wait_write(void) { - if ((LCD_BASE & LCD_BUSY_MASK) != 0) { - int start = USEC_TIMER; - - do { - if ((LCD_BASE & LCD_BUSY_MASK) == 0) break; - } while (timer_check(start, 1000) == 0); - } + while (LCD2_PORT & LCD2_BUSY_MASK); } /* Send command */ -static inline void lcd_send_cmd(int v) +static inline void lcd_send_cmd(unsigned v) { lcd_wait_write(); - LCD_BASE = 0x00000000 | LCD_CMD; - LCD_BASE = v | LCD_CMD; + LCD2_PORT = LCD2_CMD_MASK; + LCD2_PORT = LCD2_CMD_MASK | v; } /* Send 16-bit data */ -static inline void lcd_send_data(int v) +static inline void lcd_send_data(unsigned v) { lcd_wait_write(); - LCD_BASE = ((v>>8) & 0xff) | LCD_DATA; /* Send MSB first */ - LCD_BASE = ( v & 0xff) | LCD_DATA; + LCD2_PORT = LCD2_DATA_MASK | (v >> 8); /* Send MSB first */ + LCD2_PORT = LCD2_DATA_MASK | (v & 0xff); } +/* Send 16-bit data byte-swapped. Only needed until we can use block transfer. */ +static inline void lcd_send_data_swapped(unsigned v) +{ + lcd_wait_write(); + LCD2_PORT = LCD2_DATA_MASK | (v & 0xff); /* Send LSB first */ + LCD2_PORT = LCD2_DATA_MASK | (v >> 8); +} + + /* Write value to register */ static inline void lcd_write_reg(int reg, int val) { @@ -635,7 +621,7 @@ void lcd_update_rect(int x0, int y0, int width, int height) /* for each column */ for (c = 0; c < width; c++) { /* output 1 pixel */ - lcd_send_data(*(addr++)); + lcd_send_data_swapped(*addr++); } addr += LCD_WIDTH - width; diff --git a/firmware/target/arm/iriver/h10/lcd-h10_5gb.c b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c index c1f447a80c..7555c566f0 100644 --- a/firmware/target/arm/iriver/h10/lcd-h10_5gb.c +++ b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c @@ -22,23 +22,6 @@ #include "kernel.h" #include "system.h" -/* check if number of useconds has past */ -static inline bool timer_check(int clock_start, int usecs) -{ - return ((int)(USEC_TIMER - clock_start)) >= usecs; -} - -/* Hardware address of LCD. Bits are: - * 31 - set to write, poll for completion. - * 24 - 0 for command, 1 for data - * 7..0 - command/data to send - * Commands/Data are always sent in 16-bits, msb first. - */ -#define LCD_BASE *(volatile unsigned int *)0x70008a0c -#define LCD_BUSY_MASK 0x80000000 -#define LCD_CMD 0x80000000 -#define LCD_DATA 0x81000000 - /* register defines for TL1771 */ #define R_START_OSC 0x00 #define R_DEVICE_CODE_READ 0x00 @@ -72,38 +55,23 @@ static inline bool timer_check(int clock_start, int usecs) static inline void lcd_wait_write(void) { - if ((LCD_BASE & LCD_BUSY_MASK) != 0) { - int start = USEC_TIMER; - - do { - if ((LCD_BASE & LCD_BUSY_MASK) == 0) break; - } while (timer_check(start, 1000) == 0); - } + while (LCD2_PORT & LCD2_BUSY_MASK); } /* Send command */ -static inline void lcd_send_cmd(int v) +static inline void lcd_send_cmd(unsigned v) { lcd_wait_write(); - LCD_BASE = 0x00000000 | LCD_CMD; - LCD_BASE = v | LCD_CMD; + LCD2_PORT = LCD2_CMD_MASK; + LCD2_PORT = LCD2_CMD_MASK | v; } /* Send 16-bit data */ -static inline void lcd_send_data(int v) +static inline void lcd_send_data(unsigned v) { lcd_wait_write(); - LCD_BASE = ( v & 0xff) | LCD_DATA; /* Send MSB first */ - LCD_BASE = ((v>>8) & 0xff) | LCD_DATA; -} - -/* Send two 16-bit data */ -static inline void lcd_send_data2(int v) -{ - unsigned int vsr = v; - lcd_send_data(vsr); - vsr = v >> 16; - lcd_send_data(vsr); + LCD2_PORT = LCD2_DATA_MASK | (v >> 8); /* Send MSB first */ + LCD2_PORT = LCD2_DATA_MASK | (v & 0xff); } @@ -181,17 +149,17 @@ void lcd_yuv_blit(unsigned char * const src[3], y0 = y; y1 = y + height - 1; - /* start horiz << 8 | max horiz */ + /* max horiz << 8 | start horiz */ lcd_send_cmd(R_HORIZ_RAM_ADDR_POS); - lcd_send_data((x0 << 8) | x1); + lcd_send_data((x1 << 8) | x0); - /* start vert << 8 | max vert */ + /* max vert << 8 | start vert */ lcd_send_cmd(R_VERT_RAM_ADDR_POS); - lcd_send_data((y0 << 8) | y1); + lcd_send_data((y1 << 8) | y0); - /* start horiz << 8 | start vert */ + /* start vert << 8 | start horiz */ lcd_send_cmd(R_RAM_ADDR_SET); - lcd_send_data(((x0 << 8) | y0)); + lcd_send_data((y0 << 8) | x0); /* start drawing */ lcd_send_cmd(R_WRITE_DATA_2_GRAM); @@ -302,12 +270,12 @@ void lcd_yuv_blit(unsigned char * const src[3], rbits = red1 >> 16 ; gbits = green1 >> 15 ; bbits = blue1 >> 16 ; - lcd_send_data(swap16((rbits << 11) | (gbits << 5) | bbits)); + lcd_send_data((rbits << 11) | (gbits << 5) | bbits); rbits = red2 >> 16 ; gbits = green2 >> 15 ; bbits = blue2 >> 16 ; - lcd_send_data(swap16((rbits << 11) | (gbits << 5) | bbits)); + lcd_send_data((rbits << 11) | (gbits << 5) | bbits); } while (ysrc < row_end); @@ -321,8 +289,7 @@ void lcd_update_rect(int x0, int y0, int width, int height) { int x1, y1; int newx,newwidth; - - unsigned long *addr = (unsigned long *)lcd_framebuffer; + unsigned long *addr; /* Ensure x and width are both even - so we can read 32-bit aligned data from lcd_framebuffer */ @@ -352,34 +319,56 @@ void lcd_update_rect(int x0, int y0, int width, int height) x1 = t; } - /* start horiz << 8 | max horiz */ + /* max horiz << 8 | start horiz */ lcd_send_cmd(R_HORIZ_RAM_ADDR_POS); - lcd_send_data((x0 << 8) | x1); - - /* start vert << 8 | max vert */ + lcd_send_data((x1 << 8) | x0); + + /* max vert << 8 | start vert */ lcd_send_cmd(R_VERT_RAM_ADDR_POS); - lcd_send_data((y0 << 8) | y1); + lcd_send_data((y1 << 8) | y0); - /* start horiz << 8 | start vert */ + /* start vert << 8 | start horiz */ lcd_send_cmd(R_RAM_ADDR_SET); - lcd_send_data(((x0 << 8) | y0)); + lcd_send_data((y0 << 8) | x0); /* start drawing */ lcd_send_cmd(R_WRITE_DATA_2_GRAM); addr = (unsigned long*)&lcd_framebuffer[y0][x0]; - int c, r; + while (height > 0) { + int c, r; + int h, pixels_to_write; + + pixels_to_write = (width * height) * 2; + h = height; - /* for each row */ - for (r = 0; r < height; r++) { - /* for each column */ - for (c = 0; c < width; c += 2) { - /* output 2 pixels */ - lcd_send_data2(*(addr++)); + /* calculate how much we can do in one go */ + if (pixels_to_write > 0x10000) { + h = (0x10000/2) / width; + pixels_to_write = (width * h) * 2; } - addr += (LCD_WIDTH - width)/2; + LCD2_BLOCK_CTRL = 0x10000080; + LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1); + LCD2_BLOCK_CTRL = 0x34000000; + + /* for each row */ + for (r = 0; r < h; r++) { + /* for each column */ + for (c = 0; c < width; c += 2) { + while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK)); + + /* output 2 pixels */ + LCD2_BLOCK_DATA = *addr++; + } + addr += (LCD_WIDTH - width)/2; + } + + while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); + LCD2_BLOCK_CONFIG = 0; + + height -= h; } } diff --git a/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c b/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c index d503fd2c9b..24a7585508 100644 --- a/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c +++ b/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c @@ -62,7 +62,7 @@ /* wait for LCD */ static inline void lcd_wait_write(void) { - while (LCD1_BASE & LCD1_BUSY_MASK); + while (LCD1_CONTROL & LCD1_BUSY_MASK); } /* send LCD data */ @@ -91,13 +91,13 @@ void lcd_init_device(void) DEV_INIT &= ~0x400; udelay(10000); - LCD1_BASE &= ~0x4; + LCD1_CONTROL &= ~0x4; udelay(15); - LCD1_BASE |= 0x4; + LCD1_CONTROL |= 0x4; udelay(10); - LCD1_BASE = 0x4687; + LCD1_CONTROL = 0x4687; udelay(10000); lcd_send_command(R_STANDBY_OFF); -- cgit v1.2.3