From 4093874f80571f32e2aedd2b09b2be9eb5efc47c Mon Sep 17 00:00:00 2001 From: Mark Arigo Date: Wed, 1 Jul 2009 02:18:49 +0000 Subject: Philips SA9200. Add LCD features: enable, sleep, flip, contrast, and invert. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21583 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/config-sa9200.h | 24 +- .../target/arm/philips/sa9200/backlight-sa9200.c | 1 + firmware/target/arm/philips/sa9200/lcd-sa9200.c | 258 +++++++++++++++++++-- firmware/target/arm/philips/sa9200/power-sa9200.c | 7 + 4 files changed, 258 insertions(+), 32 deletions(-) diff --git a/firmware/export/config-sa9200.h b/firmware/export/config-sa9200.h index 37c0b50035..30aad93898 100755 --- a/firmware/export/config-sa9200.h +++ b/firmware/export/config-sa9200.h @@ -42,18 +42,21 @@ #define LCD_DEPTH 16 /* 65536 colours */ #define LCD_PIXELFORMAT RGB565 /* rgb565 */ +#ifndef BOOTLOADER /* define this if you have LCD enable function */ -/* #define HAVE_LCD_ENABLE */ +#define HAVE_LCD_ENABLE -/* Define this if your LCD can be put to sleep. HAVE_LCD_ENABLE - should be defined as well. */ -/* #define HAVE_LCD_SLEEP */ +/* Define this if your LCD can be put to sleep. + HAVE_LCD_ENABLE should be defined as well. */ +#define HAVE_LCD_SLEEP +#define HAVE_LCD_SLEEP_SETTING +#endif /* define this if you can flip your LCD */ -/* #define HAVE_LCD_FLIP */ +#define HAVE_LCD_FLIP /* define this if you can invert the colours on your LCD */ -/* #define HAVE_LCD_INVERT */ +#define HAVE_LCD_INVERT /* #define IRAM_LCDFRAMEBUFFER IDATA_ATTR *//* put the lcd frame buffer in IRAM */ @@ -150,9 +153,16 @@ /* Define this to the CPU frequency */ #define CPU_FREQ 75000000 -/* Type of LCD TODO: hopefully the same as the x5 but check this*/ +/* Type of LCD */ #define CONFIG_LCD LCD_SA9200 +/* Define this if your LCD can set contrast */ +#define HAVE_LCD_CONTRAST + +#define MIN_CONTRAST_SETTING 0 +#define MAX_CONTRAST_SETTING 31 +#define DEFAULT_CONTRAST_SETTING 22 /* Match boot contrast */ + /* USB On-the-go */ #define CONFIG_USBOTG USBOTG_ARC diff --git a/firmware/target/arm/philips/sa9200/backlight-sa9200.c b/firmware/target/arm/philips/sa9200/backlight-sa9200.c index 22aae1ae6b..0de4c05df5 100644 --- a/firmware/target/arm/philips/sa9200/backlight-sa9200.c +++ b/firmware/target/arm/philips/sa9200/backlight-sa9200.c @@ -25,6 +25,7 @@ #include "ascodec.h" #include "as3514.h" #include "synaptics-mep.h" +#include "lcd.h" void _backlight_set_brightness(int brightness) { diff --git a/firmware/target/arm/philips/sa9200/lcd-sa9200.c b/firmware/target/arm/philips/sa9200/lcd-sa9200.c index d7fe2e9c12..3937c078c6 100755 --- a/firmware/target/arm/philips/sa9200/lcd-sa9200.c +++ b/firmware/target/arm/philips/sa9200/lcd-sa9200.c @@ -24,6 +24,19 @@ #include "kernel.h" #include "system.h" +/* Settings to remember when display is turned off */ +static bool invert; +static bool flip; +static int contrast; + +static bool power_on; +static bool display_on; + +/* Forward declarations */ +#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) +static void lcd_display_off(void); +#endif + /* The SA9200 controller closely matches the register defines for the Samsung S6D0151 */ #define R_START_OSC 0x00 @@ -95,12 +108,11 @@ static void lcd_write_reg(unsigned reg, unsigned data) lcd_send_data(data); } +/* LCD init */ void lcd_init_device(void) { #if 0 - /* This is the init done by the OF bootloader. - Re-initializing the lcd causes it to flash - a white screen, so for now disable this. */ + /* This is done by the OF bootloader, no need to redo */ DEV_INIT1 &= ~0x3000; DEV_INIT1 = DEV_INIT1; DEV_INIT2 &= ~0x400; @@ -115,82 +127,272 @@ void lcd_init_device(void) LCD1_CONTROL &= ~0x800; LCD1_CONTROL &= ~0x400; udelay(30000); +#endif + + power_on = true; + display_on = true; + invert = false; + flip = false; + contrast = DEFAULT_CONTRAST_SETTING; +} +#ifdef HAVE_LCD_SLEEP +static void lcd_power_on(void) +{ LCD1_CONTROL |= 0x1; + /** Power ON Sequence **/ + + /* Start Oscillation */ lcd_write_reg(R_START_OSC, 0x0001); - udelay(50000); + + sleep(HZ/20); /* 50ms or more */ + + /* DSTB=0, SAP2-0=001, BT2-0=101, DC2-0=000, AP2-0=001, SLP=0, STB=0 */ + lcd_write_reg(R_POWER_CONTROL1, 0x0d04); + /* VR1C=0, VRN14-10=10111, VRP14-10=11111 */ lcd_write_reg(R_GAMMA_CONTROL1, 0x171f); + + /* SVC3-0=0000, VRH5-4=01 */ lcd_write_reg(R_POWER_CONTROL2, 0x0001); - lcd_write_reg(R_POWER_CONTROL3, 0x08cd); - lcd_write_reg(R_POWER_CONTROL4, 0x0416); + + /* VCMR=1, PON=0, VRH3-0=1101 */ + lcd_write_reg(R_POWER_CONTROL3, 0x080d); + + /* VDV6-0=0000100, VCOMG=0, VCM6-0=xxxxxxx */ + lcd_write_reg(R_POWER_CONTROL4, 0x0400 | contrast); + + /* DSTB=0, SAP2-0=010, BT2-0=010, DC2-0=000, AP2-0=010, SLP=0, STB=0 */ lcd_write_reg(R_POWER_CONTROL1, 0x1208); - udelay(50000); + sleep(HZ/20); /* 50ms or more */ + + /* VCMR=1, PON=1, VRH3-0=1100 */ lcd_write_reg(R_POWER_CONTROL3, 0x081c); - udelay(200000); - lcd_write_reg(R_DRV_OUTPUT_CONTROL, 0x0a0c); + sleep(HZ/20); /* OF bootlaoder uses 200ms, no delay in OF firmware */ + + /* Instructions for other mode settings (in register order). */ + + lcd_write_reg(R_DRV_OUTPUT_CONTROL, flip ? 0x090c : 0x0a0c); + + /* FL1-0=10, FDL=0 */ lcd_write_reg(R_INVERSION_CONTROL, 0x0200); + + /* BGR=1, MDT1-0=00, I/D1-0=11, AM=0 */ lcd_write_reg(R_ENTRY_MODE, 0x1030); + + /* PT1-0=00, SPT=0, GON=0, DTE=0, CL=0, REV=1, D1-0=01 */ lcd_write_reg(R_DISP_CONTROL, 0x0005); + + /* FP3-0=0011, BT3-0=1010 */ lcd_write_reg(R_BLANK_PERIOD_CONTROL, 0x030a); + + /* DIV1-0=00, RTN3-0=0000 */ lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x0000); + + /* RM=0, DM1-0=00, RIM1-0=00 */ lcd_write_reg(R_EXT_INTERFACE_CONTROL, 0x0000); + /* PKP1=0x0, PKP0=0x0 */ lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0000); + + /* PKP3=0x2, PKP2=0x4 */ lcd_write_reg(R_GAMMA_FINE_ADJ_POS2, 0x0204); + + /* PKP5=0x0, PKP4=0x1 */ lcd_write_reg(R_GAMMA_FINE_ADJ_POS3, 0x0001); + + /* PRP1=0x6, PRP0=0x0 */ lcd_write_reg(R_GAMMA_GRAD_ADJ_POS, 0x0600); + + /* PKN1=0x6, PKN0=0x7 */ lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1, 0x0607); + + /* PKN3=0x3, PKN2=0x5 */ lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2, 0x0305); + + /* PKN5=0x7, PKN4=0x7 */ lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3, 0x0707); + + /* PRN1=0x0, PRN0=0x6 */ lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG, 0x0006); + + /* VRN0=0x4, VRP=0x0 */ lcd_write_reg(R_GAMMA_CONTROL3, 0x0400); + /* SCN=0x0 */ lcd_write_reg(R_GATE_SCAN_START_POS, 0x0000); + + /* SE1=LCD_HEIGHT-1, SS1=0x0 */ lcd_write_reg(R_1ST_SCR_DRV_POS, 0x9f00); + + /* SE2=0x0, SS2=0x0 */ lcd_write_reg(R_2ND_SCR_DRV_POS, 0x0000); + + /* HEA=LCD_WIDTH-1, HSA=0x0 */ lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 0x7f00); + + /* VEA=LCD_HEIGHT-1, VSA=0x0 */ lcd_write_reg(R_VERT_RAM_ADDR_POS, 0x9f00); + /* Unknown registers */ lcd_write_reg(0x00a8, 0x0125); lcd_write_reg(0x00a9, 0x0014); lcd_write_reg(0x00a7, 0x0022); + power_on = true; +} + +static void lcd_power_off(void) +{ + /* Display must be off first */ + if (display_on) + lcd_display_off(); + + power_on = false; + + /** Power OFF sequence **/ + + /* DSTB=0, SAP2-0=000, BT2-0=001, DC2-0=000, AP2-0=000, SLP=0, STB=0 */ + lcd_write_reg(R_POWER_CONTROL1, 0x0100); + + /* VCMR=1, PON=0, VRH3-0=1101 */ + lcd_write_reg(R_POWER_CONTROL3, 0x080d); +} + +void lcd_sleep(void) +{ + if (power_on) + lcd_power_off(); + + /* Set standby mode */ + + /* PT1-0=00, SPT=0, GON=1, DTE=1, CL=0, REV=1, D1-0=10 */ + lcd_write_reg(R_DISP_CONTROL, 0x0036); + + /* DSTB=0, SAP2-0=000, BT2-0=101, DC2-0=000, AP2-0=000, SLP=0, STB=1 */ + lcd_write_reg(R_POWER_CONTROL1, 0x0501); + + LCD1_CONTROL &= ~0xffff0001; +} +#endif + +#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) +static void lcd_display_off(void) +{ + display_on = false; + + /** Display OFF sequence **/ + + /* PT1-0=10, SPT=0, GON=1, DTE=1, CL=0, REV=1, D1-0=10 */ + lcd_write_reg(R_DISP_CONTROL, 0x1036); + + sleep(HZ/25); /* 2 or more frames */ + + /* PT1-0=10, SPT=0, GON=1, DTE=0, CL=0, REV=1, D1-0=00 */ + lcd_write_reg(R_DISP_CONTROL, 0x1034); + + sleep(HZ/500); /* 1ms or more */ + + /* PT1-0=10, SPT=0, GON=0, DTE=0, CL=0, REV=1, D1-0=00 */ + lcd_write_reg(R_DISP_CONTROL, 0x1004); + + sleep(HZ/25); /* 2 or more frames */ +} +#endif + +#if defined(HAVE_LCD_ENABLE) +static void lcd_display_on(void) +{ + /* Be sure power is on first */ + if (!power_on) + lcd_power_on(); + + /** Display ON Sequence **/ + + /* PT1-0=00, SPT=0, GON=1, DTE=0, CL=0, REV=0, D1-0=01 */ lcd_write_reg(R_DISP_CONTROL, 0x0021); - udelay(40000); + + sleep(HZ/500); /* 1ms or more */ + + /* PT1-0=00, SPT=0, GON=1, DTE=0, CL=0, REV=0, D1-0=11 */ lcd_write_reg(R_DISP_CONTROL, 0x0023); - udelay(40000); - lcd_write_reg(R_DISP_CONTROL, 0x1037); - lcd_write_reg(R_RAM_ADDR_SET, 0x0000); + sleep(HZ/25); /* 2 or more frames */ + + /* PT1-0=10, SPT=0, GON=1, DTE=1, CL=0, REV=x, D1-0=11 */ + lcd_write_reg(R_DISP_CONTROL, invert ? 0x1033 : 0x1037); + + display_on = true; +} + +void lcd_enable(bool on) +{ + if (on == display_on) + return; + + if (on) + { + lcd_display_on(); + /* Probably out of sync and we don't wanna pepper the code with + lcd_update() calls for this. */ + lcd_update(); + lcd_activation_call_hook(); + } + else + { + lcd_display_off(); + } +} #endif + +#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) +bool lcd_active(void) +{ + return display_on; } +#endif /*** hardware configuration ***/ -#if 0 int lcd_default_contrast(void) { return DEFAULT_CONTRAST_SETTING; } -#endif void lcd_set_contrast(int val) { - (void)val; + contrast = val & 0x7f; + + if (!display_on) + return; + + /* VDV6-0=0000100, VCOMG=0, VCM6-0=xxxxxxx */ + lcd_write_reg(R_POWER_CONTROL4, 0x0400 | contrast); } void lcd_set_invert_display(bool yesno) { - (void)yesno; + invert = yesno; + + if (!display_on) + return; + + /* PT1-0=10, SPT=0, GON=1, DTE=1, CL=0, REV=x, D1-0=11 */ + lcd_write_reg(R_DISP_CONTROL, invert ? 0x1033 : 0x1037); } /* turn the display upside down (call lcd_update() afterwards) */ void lcd_set_flip(bool yesno) { - (void)yesno; + flip = yesno; + + if (!display_on) + return; + + /* DPL=0, EPL=1, SM=0, GS=x, SS=x, NL4-0=01100 */ + lcd_write_reg(R_DRV_OUTPUT_CONTROL, flip ? 0x090c : 0x0a0c); } void lcd_yuv_set_options(unsigned options) @@ -224,21 +426,27 @@ void lcd_update(void) void lcd_update_rect(int x, int y, int width, int height) { const fb_data *addr; - - if (x + width >= LCD_WIDTH) + + if (!display_on) + return; + + if (x + width > LCD_WIDTH) width = LCD_WIDTH - x; - if (y + height >= LCD_HEIGHT) + + if (y + height > LCD_HEIGHT) height = LCD_HEIGHT - y; - + if ((width <= 0) || (height <= 0)) return; /* Nothing left to do. */ addr = &lcd_framebuffer[y][x]; - do { - lcd_write_reg(R_RAM_ADDR_SET, ((y++ & 0xff) << 8) | (x & 0xff)); - lcd_send_command(R_WRITE_DATA_2_GRAM); + lcd_write_reg(R_HORIZ_RAM_ADDR_POS, ((x + width - 1) << 8) | x); + lcd_write_reg(R_VERT_RAM_ADDR_POS, ((y + height -1) << 8) | y); + lcd_write_reg(R_RAM_ADDR_SET, ((y & 0xff) << 8) | (x & 0xff)); + lcd_send_command(R_WRITE_DATA_2_GRAM); + do { int w = width; do { lcd_send_data(*addr++); diff --git a/firmware/target/arm/philips/sa9200/power-sa9200.c b/firmware/target/arm/philips/sa9200/power-sa9200.c index e0bdfcf8ea..236dd72a72 100644 --- a/firmware/target/arm/philips/sa9200/power-sa9200.c +++ b/firmware/target/arm/philips/sa9200/power-sa9200.c @@ -26,6 +26,7 @@ #include "as3514.h" #include "power.h" #include "synaptics-mep.h" +#include "lcd.h" #include "logf.h" void power_init(void) @@ -72,6 +73,12 @@ void power_off(void) { char byte; + /* Backlight off */ + ascodec_write(AS3514_DCDC15, 0); + + /* LCD off/sleep (otherwise the image slowly fades out) */ + lcd_sleep(); + /* Send shutdown command to PMU */ byte = ascodec_read(AS3514_SYSTEM); byte &= ~0x1; -- cgit v1.2.3