From 401edf8b48ea55cb50336c52f6bf7c6f63701f0a Mon Sep 17 00:00:00 2001 From: Bertrik Sikken Date: Mon, 29 Aug 2011 21:05:59 +0000 Subject: sansa clipzip: implement more functions in the lcd driver git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30376 a1c6a512-1295-4272-9138-f99709370657 --- .../target/arm/as3525/sansa-clipzip/lcd-clipzip.c | 314 ++++++++++++++++++--- 1 file changed, 276 insertions(+), 38 deletions(-) (limited to 'firmware/target') diff --git a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c index 8efbdf77b9..dd815df05e 100644 --- a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c +++ b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c @@ -26,78 +26,316 @@ #include "system.h" #include "cpu.h" -static int display_type; +#define CLAMP(x,min,max) \ + if ((x)<(min)) (x)=(min);\ + if ((x)>(max)) (x)=(max); +/* the detected lcd type (0 or 1) */ +static int lcd_type; + +/* initialises the host lcd hardware, returns the lcd type */ int lcd_hw_init(void) { + /* configure SSP */ bitset32(&CGU_PERI, CGU_SSP_CLOCK_ENABLE); + SSP_CPSR = 8; /* TODO: use AS3525_SSP_PRESCALER, OF uses 8 */ + SSP_CR0 = (0 << 8) | /* SCR, serial clock rate divider = 1 */ + (1 << 7) | /* SPH, phase = 1 */ + (1 << 6) | /* SPO, polarity = 1 */ + (0 << 4) | /* FRF, frame format = motorola SPI */ + (7 << 0); /* DSS, data size select = 8 bits */ + SSP_CR1 = (1 << 3) | /* SOD, slave output disable = 1 */ + (0 << 2) | /* MS, master/slave = master */ + (1 << 1) | /* SSE, synchronous serial port enabled = true */ + (0 << 0); /* LBM, loopback mode = normal */ + SSP_IMSC &= ~0xF; /* disable interrupts */ + SSP_DMACR &= ~0x3; /* disable DMA */ - SSP_CPSR = AS3525_SSP_PRESCALER; /* OF = 0x10 */ - SSP_CR0 = (1<<7) | (1<<6) | 7; /* Motorola SPI frame format, 8 bits */ - SSP_CR1 = (1<<3) | (1<<1); /* SSP Operation enabled */ - SSP_IMSC = 0; /* No interrupts */ - - /* configure GPIO B2 (display D/C#) as output */ + /* configure GPIO B2 (lcd D/C#) as output */ GPIOB_DIR |= (1<<2); - /* configure GPIO B3 (display type detect) as input */ + /* configure GPIO B3 (lcd type detect) as input */ GPIOB_DIR &= ~(1<<3); - /* set GPIO A5 (display RESET# ?) */ - GPIOA_DIR |= (1<<5); - GPIOA_PIN(5) = (1<<5); + /* configure GPIO A5 (lcd reset# ?) as output and set low */ + GPIOA_DIR |= (1 << 5); + GPIOA_PIN(5) = 0; - /* detect display type on GPIO B3 */ + /* detect lcd type on GPIO B3 */ return GPIOB_PIN(3) ? 1 : 0; } -void lcd_write_command(int byte) +/* writes a command byte to the LCD */ +static void lcd_write_cmd(uint8_t byte) { - while(SSP_SR & (1<<4)) /* BSY flag */ - ; + /* wait until not busy */ + while (SSP_SR & (1<<4)); /* LCD command mode */ GPIOB_PIN(2) = 0; + /* write data */ SSP_DATA = byte; - while(SSP_SR & (1<<4)) /* BSY flag */ - ; + + /* wait until not busy */ + while (SSP_SR & (1<<4)); + + /* LCD data mode */ + GPIOB_PIN(2) = (1 << 2); } -void lcd_write_data(const fb_data* p_bytes, int count) +/* writes a data byte to the LCD */ +static void lcd_write_dat(uint8_t data) { - /* LCD data mode */ - GPIOB_PIN(2) = (1<<2); + /* wait while transmit FIFO */ + while (!(SSP_SR & (1<<1))); - while (count--) - { - while(!(SSP_SR & (1<<1))) /* wait until transmit FIFO is not full */ - ; + /* write data */ + SSP_DATA = data; +} - SSP_DATA = *p_bytes++; - } +/* writes both a command and data value to the lcd */ +static void lcd_write(uint8_t cmd, uint8_t data) +{ + lcd_write_cmd(cmd); + lcd_write_dat(data); } -void lcd_update(void) +/* delays during lcd initialisation (for type 0 LCDs) */ +static void lcd_delay(int us) +{ + udelay(us); +} + +/* initialises lcd type 0 */ +static void lcd_init_type0(void) { - /* TODO */ + lcd_write(0x01, 0x00); + lcd_write(0x14, 0x01); + lcd_delay(5); + + lcd_write(0x14, 0x00); + lcd_delay(5); + + lcd_write(0x0F, 0x41); + lcd_write(0xEA, 0x0A); + lcd_write(0xEB, 0x42); + lcd_write(0x18, 0x08); + lcd_write(0x1A, 0x0B); + lcd_write(0x48, 0x03); + + /* lcd width/height */ + lcd_write(0x30, 0x00); + lcd_write(0x31, 0x5F); + lcd_write(0x32, 0x00); + lcd_write(0x33, 0x5F); + + lcd_write(0xE0, 0x10); + lcd_write(0xE1, 0x00); + lcd_write(0xE5, 0x00); + lcd_write(0x0D, 0x00); + lcd_write(0x1D, 0x01); + lcd_write(0x09, 0x00); + lcd_write(0x13, 0x00); + lcd_write(0x16, 0x05); + lcd_write(0x3A, 0x03); + lcd_write(0x3B, 0x03); + lcd_write(0x3C, 0x03); + lcd_write(0x3D, 0x45); + lcd_write(0x3E, 0x45); + lcd_write(0x3F, 0x45); + lcd_write(0x40, 0x62); + lcd_write(0x41, 0x3D); + lcd_write(0x42, 0x46); +} + +/* writes a table entry (for type 1 LCDs) */ +static void lcd_write_table(uint8_t val) +{ + lcd_write_dat((val >> 4) & 0x07); + lcd_write_dat((val >> 0) & 0x0F); +} + +/* initialises lcd type 1 */ +static void lcd_init_type1(void) +{ + static const uint8_t curve[256] = { + /* 5-bit curve */ + 0, 5, 10, 15, 20, 25, 30, 35, 39, 43, 47, 51, 55, 59, 63, 67, + 71, 75, 79, 83, 87, 91, 95, 99, 103, 105, 109, 113, 117, 121, 123, 127, + /* 6-bit curve */ + 0, 2, 4, 6, 8, 10, 12, 16, 18, 24, 26, 28, 30, 32, 34, 36, + 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, + 70, 72, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, + 104, 106, 108, 110, 112, 114, 116, 118, 120, 121, 122, 123, 124, 125, 126, 127, + /* 5-bit curve */ + 0, 5, 10, 15, 20, 25, 30, 35, 39, 43, 47, 51, 55, 59, 63, 67, + 71, 75, 79, 83, 87, 91, 93, 97, 101, 105, 109, 113, 117, 121, 124, 127 + }; + int i; + + lcd_write_cmd(0x02); + lcd_write_dat(0x00); + + lcd_write_cmd(0x01); + + lcd_write_cmd(0x03); + lcd_write_dat(0x00); + + lcd_write_cmd(0x04); + lcd_write_dat(0x03); + + lcd_write_cmd(0x05); + lcd_write_dat(0x08); + + lcd_write_cmd(0x06); + lcd_write_dat(0x00); + + lcd_write_cmd(0x07); + lcd_write_dat(0x00); + lcd_write_dat(0x00); + lcd_write_dat(0x04); + lcd_write_dat(0x1F); + lcd_write_dat(0x00); + lcd_write_dat(0x00); + lcd_write_dat(0x05); + lcd_write_dat(0x0F); + + lcd_write_cmd(0x08); + lcd_write_dat(0x01); + + lcd_write_cmd(0x09); + lcd_write_dat(0x07); + + /* lcd width/height */ + lcd_write_cmd(0x0A); + lcd_write_dat(0x00); + lcd_write_dat(0x00); + lcd_write_dat(0x05); + lcd_write_dat(0x0F); + lcd_write_dat(0x00); + lcd_write_dat(0x00); + lcd_write_dat(0x05); + lcd_write_dat(0x0F); + + lcd_write_cmd(0x0B); + lcd_write_dat(0x00); + lcd_write_dat(0x00); + lcd_write_dat(0x00); + lcd_write_dat(0x00); + + lcd_write_cmd(0x0E); + lcd_write_dat(0x04); + lcd_write_dat(0x02); + lcd_write_dat(0x02); + lcd_write_dat(0x05); + lcd_write_dat(0x03); + lcd_write_dat(0x0F); + + lcd_write_cmd(0x0F); + lcd_write_dat(0x0A); + lcd_write_dat(0x0A); + lcd_write_dat(0x0A); + + lcd_write_cmd(0x1C); + lcd_write_dat(0x08); + + lcd_write_cmd(0x1D); + lcd_write_dat(0x00); + lcd_write_dat(0x00); + lcd_write_dat(0x00); + + lcd_write_cmd(0x1E); + lcd_write_dat(0x05); + + lcd_write_cmd(0x1F); + lcd_write_dat(0x00); + + lcd_write_cmd(0x30); + lcd_write_dat(0x10); + + lcd_write_cmd(0x3A); + for (i = 0; i < 256; i++) { + lcd_write_table(curve[i]); + } + + lcd_write_cmd(0x3C); + lcd_write_dat(0x00); + + lcd_write_cmd(0x3D); + lcd_write_dat(0x00); } +/* initialises the lcd */ void lcd_init_device(void) { - /* TODO */ - display_type = lcd_hw_init(); + lcd_type = lcd_hw_init(); + if (lcd_type == 0) { + lcd_init_type0(); + } + else { + lcd_init_type1(); + } } -/* Update a fraction of the display. */ +/* sets up the lcd to receive frame buffer data */ +static void lcd_setup_rect(int x, int x_end, int y, int y_end) +{ + if (lcd_type == 0) { + lcd_write(0x34, x); + lcd_write(0x35, x_end); + lcd_write(0x36, y); + lcd_write(0x37, y_end); + } + else { + lcd_write_cmd(0x0A); + lcd_write_dat((x >> 8) & 0xFF); + lcd_write_dat((x >> 0) & 0xFF); + lcd_write_dat((x_end >> 8) & 0xFF); + lcd_write_dat((x_end >> 0) & 0xFF); + lcd_write_dat((y >> 8) & 0xFF); + lcd_write_dat((y >> 0) & 0xFF); + lcd_write_dat((y_end >> 8) & 0xFF); + lcd_write_dat((y_end >> 0) & 0xFF); + } +} + +/* Updates a fraction of the display. */ void lcd_update_rect(int x, int y, int width, int height) { - (void) x; - (void) y; - (void) width; - (void) height; - - /* TODO not implemented yet, do a full update instead */ - lcd_update(); + fb_data *ptr; + fb_data pixel; + int row, col; + int x_end = x + width - 1; + int y_end = y + height - 1; + + /* check/correct bounds */ + CLAMP(x, 0, LCD_WIDTH - 1); + CLAMP(x_end, 0, LCD_WIDTH - 1); + CLAMP(y, 0, LCD_HEIGHT - 1); + CLAMP(y_end, 0, LCD_HEIGHT - 1); + if ((x > x_end) || (y > y_end)) { + return; + } + + /* setup GRAM write window */ + lcd_setup_rect(x, x_end, y, y_end); + + /* write to GRAM */ + lcd_write_cmd((lcd_type == 0) ? 0x08 : 0x0C); + for (row = y; row <= y_end; row++) { + ptr = &lcd_framebuffer[row][x]; + for (col = x; col <= x_end; col++) { + pixel = *ptr++; + lcd_write_dat((pixel >> 8) & 0xFF); + lcd_write_dat((pixel >> 0) & 0xFF); + } + } +} + +/* updates the entire lcd */ +void lcd_update(void) +{ + lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); } -- cgit v1.2.3