diff --git a/firmware/SOURCES b/firmware/SOURCES index 6258e43e68..42dc5fb82f 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -737,6 +737,38 @@ target/arm/as3525/pcm-as3525.c #endif /* BOOTLOADER */ #endif /* CONFIG_CPU == AS3525 */ +#if CONFIG_CPU == S5L8702 || CONFIG_CPU == S5L8720 +target/arm/ipod/button-clickwheel.c +target/arm/s5l8702/kernel-s5l8702.c +target/arm/s5l8702/system-s5l8702.c +target/arm/s5l8702/timer-s5l8702.c +target/arm/s5l8702/gpio-s5l8702.c +target/arm/s5l8702/pl080.c +target/arm/s5l8702/dma-s5l8702.c +target/arm/s5l8702/clocking-s5l8702.c +#if 0 // TODO +target/arm/s5l8702/postmortemstub.S +#endif +#ifndef BOOTLOADER +target/arm/s5l8702/pcm-s5l8702.c +target/arm/s5l8702/debug-s5l8702.c +#endif +#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) +target/arm/s5l8702/usb-s5l8702.c +#endif +#ifdef HAVE_SERIAL +target/arm/uc87xx.c +target/arm/s5l8702/uart-s5l8702.c +#endif +target/arm/s5l8702/crypto-s5l8702.c +#if CONFIG_CPU == S5L8702 +target/arm/s5l8702/spi-s5l8702.c +target/arm/s5l8702/norboot-s5l8702.c +#elif CONFIG_CPU == S5L8720 +/* target/arm/s5l8702/nandboot-s5l8702.c */ +#endif +#endif /* S5L8702 || S5L8720 */ + #if defined(CPU_PP) target/arm/pp/i2s-pp.c target/arm/pp/kernel-pp.c @@ -788,7 +820,7 @@ target/arm/tcc780x/crt0.S target/arm/imx31/crt0.S #elif CONFIG_CPU==S5L8700 || CONFIG_CPU==S5L8701 target/arm/s5l8700/crt0.S -#elif CONFIG_CPU==S5L8702 +#elif CONFIG_CPU==S5L8702 || CONFIG_CPU==S5L8720 target/arm/s5l8702/crt0.S #elif CONFIG_CPU==IMX233 target/arm/imx233/crt0.S @@ -850,6 +882,9 @@ target/arm/rk27xx/ihifi2/lcd-ihifi770.c target/arm/rk27xx/ihifi2/lcd-ihifi770c.c #elif CONFIG_LCD == LCD_IHIFI800 target/arm/rk27xx/ihifi2/lcd-ihifi800.c +#elif CONFIG_LCD == LCD_IPOD6GNANO3G4G +target/arm/s5l8702/lcd-s5l8702.c +target/arm/s5l8702/lcd-asm-s5l8702.S #endif /* USB Stack */ @@ -1538,6 +1573,7 @@ target/arm/s5l8700/udacodec-meizu.c #ifdef IPOD_NANO2G target/arm/ipod/button-clickwheel.c target/arm/s5l8700/postmortemstub.S +target/arm/s5l8700/usb-s5l8701.c target/arm/s5l8700/ipodnano2g/backlight-nano2g.c target/arm/s5l8700/ipodnano2g/lcd-nano2g.c target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S @@ -1546,8 +1582,9 @@ target/arm/s5l8700/ipodnano2g/power-nano2g.c target/arm/s5l8700/ipodnano2g/ftl-nano2g.c target/arm/s5l8700/ipodnano2g/nand-nano2g.c target/arm/s5l8700/ipodnano2g/pmu-nano2g.c +#if (CONFIG_RTC == RTC_NANO2G) target/arm/s5l8700/ipodnano2g/rtc-nano2g.c -target/arm/s5l8700/usb-s5l8701.c +#endif #ifdef HAVE_SERIAL target/arm/uc87xx.c target/arm/s5l8700/uart-s5l8701.c @@ -1557,44 +1594,24 @@ target/arm/s5l8700/ipodnano2g/serial-nano2g.c target/arm/s5l8700/ipodnano2g/audio-nano2g.c target/arm/s5l8700/ipodnano2g/piezo-nano2g.c #endif -#endif +#endif /* IPOD_NANO2G */ #ifdef IPOD_6G -target/arm/ipod/button-clickwheel.c -target/arm/s5l8702/ipod6g/storage_ata-6g.c +target/arm/s5l8702/ipod6g/lcd-6g.c target/arm/s5l8702/ipod6g/backlight-6g.c +target/arm/s5l8702/ipod6g/piezo-6g.c +target/arm/s5l8702/ipod6g/pmu-6g.c +target/arm/s5l8702/ipod6g/adc-6g.c target/arm/s5l8702/ipod6g/powermgmt-6g.c target/arm/s5l8702/ipod6g/power-6g.c -target/arm/s5l8702/kernel-s5l8702.c -target/arm/s5l8702/system-s5l8702.c -target/arm/s5l8702/timer-s5l8702.c -target/arm/s5l8702/gpio-s5l8702.c -target/arm/s5l8702/pl080.c -target/arm/s5l8702/dma-s5l8702.c -target/arm/s5l8702/clocking-s5l8702.c -target/arm/s5l8702/ipod6g/lcd-6g.c -target/arm/s5l8702/ipod6g/lcd-asm-6g.S -target/arm/s5l8702/ipod6g/piezo-6g.c -target/arm/s5l8702/spi-s5l8702.c -target/arm/s5l8702/crypto-s5l8702.c -target/arm/s5l8702/norboot-s5l8702.c -#if 0 //TODO -target/arm/s5l8702/postmortemstub.S -#endif -target/arm/s5l8702/ipod6g/pmu-6g.c +target/arm/s5l8702/ipod6g/storage_ata-6g.c +#if (CONFIG_RTC == RTC_NANO2G) target/arm/s5l8702/ipod6g/rtc-6g.c -target/arm/s5l8702/ipod6g/adc-6g.c -#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) -target/arm/s5l8702/usb-s5l8702.c #endif #ifdef HAVE_SERIAL -target/arm/uc87xx.c -target/arm/s5l8702/uart-s5l8702.c target/arm/s5l8702/ipod6g/serial-6g.c #endif #ifndef BOOTLOADER -target/arm/s5l8702/debug-s5l8702.c -target/arm/s5l8702/pcm-s5l8702.c target/arm/s5l8702/ipod6g/audio-6g.c target/arm/s5l8702/ipod6g/cscodec-6g.c #endif /* BOOTLOADER */ diff --git a/firmware/target/arm/s5l8702/ipod6g/backlight-6g.c b/firmware/target/arm/s5l8702/ipod6g/backlight-6g.c index 7d1c8bde13..84b70bd7ab 100644 --- a/firmware/target/arm/s5l8702/ipod6g/backlight-6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/backlight-6g.c @@ -43,8 +43,6 @@ void backlight_hw_on(void) if (!lcd_active()) { lcd_awake(); - lcd_update(); - sleep(HZ/20); } #endif pmu_write(0x29, 1); @@ -67,3 +65,10 @@ bool backlight_hw_init(void) return true; } + +/* Kill the backlight, instantly. */ +void backlight_hw_kill(void) +{ + pmu_write(0x2b, 0); /* T_dimstep = 0 */ + backlight_hw_off(); +} diff --git a/firmware/target/arm/s5l8702/ipod6g/backlight-target.h b/firmware/target/arm/s5l8702/ipod6g/backlight-target.h index 21ff6c30e1..89ed552b2e 100644 --- a/firmware/target/arm/s5l8702/ipod6g/backlight-target.h +++ b/firmware/target/arm/s5l8702/ipod6g/backlight-target.h @@ -26,4 +26,6 @@ void backlight_hw_on(void); void backlight_hw_off(void); void backlight_hw_brightness(int brightness); +void backlight_hw_kill(void); + #endif diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c b/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c index 103e7e2232..0f74787b45 100644 --- a/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c @@ -18,63 +18,28 @@ * KIND, either express or implied. * ****************************************************************************/ +#include +#include + #include "config.h" -#include "hwcompat.h" -#include "kernel.h" -#include "lcd.h" -#include "system.h" -#include "cpu.h" -#include "pmu-target.h" -#include "power.h" -#include "string.h" -#include "dma-s5l8702.h" +#include "s5l87xx.h" +#include "lcd-s5l8702.h" -#define R_HORIZ_GRAM_ADDR_SET 0x200 -#define R_VERT_GRAM_ADDR_SET 0x201 -#define R_WRITE_DATA_TO_GRAM 0x202 -#define R_HORIZ_ADDR_START_POS 0x210 -#define R_HORIZ_ADDR_END_POS 0x211 -#define R_VERT_ADDR_START_POS 0x212 -#define R_VERT_ADDR_END_POS 0x213 - - -/* LCD type 1 register defines */ - -#define R_COLUMN_ADDR_SET 0x2a -#define R_ROW_ADDR_SET 0x2b -#define R_MEMORY_WRITE 0x2c - - -/** globals **/ - -int lcd_type; /* also needed in debug-s5l8702.c */ -static struct mutex lcd_mutex; -static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH] CACHEALIGN_ATTR; -static bool lcd_ispowered; - -#define CMD 0 /* send command with N data */ -#define MREG 1 /* write multiple registers */ -#define SLEEP 2 -#define END 0xff - -#define CMD16(len) (CMD | ((len) << 8)) -#define MREG16(len) (MREG | ((len) << 8)) -#define SLEEP16(t) (SLEEP | ((t) << 8)) - +#if defined(HAVE_LCD_SLEEP) || defined(HAVE_LCD_SHUTDOWN) /* powersave sequences */ -static const unsigned char lcd_sleep_seq_01[] = +static const uint8_t lcd_sleep_seq_01[] = { - CMD, 0x28, 0, /* Display Off */ - SLEEP, 5, /* 50 ms */ - CMD, 0x10, 0, /* Sleep In Mode */ - SLEEP, 5, /* 50 ms */ + CMD, 0x28, 0, /* Display Off */ + SLEEP, 5, /* 50 ms */ + CMD, 0x10, 0, /* Sleep In */ + SLEEP, 5, /* 50 ms */ END }; -static const unsigned short lcd_enter_deepstby_seq_23[] = +static const uint16_t lcd_deepstandby_seq_23[] = { /* Display Off */ MREG16(1), 0x007, 0x0172, @@ -84,6 +49,8 @@ static const unsigned short lcd_enter_deepstby_seq_23[] = MREG16(1), 0x030, 0x0000, MREG16(1), 0x100, 0x0780, MREG16(1), 0x007, 0x0000, + + /* power supply off */ MREG16(1), 0x101, 0x0260, MREG16(1), 0x102, 0x00a9, SLEEP16(3), @@ -94,22 +61,43 @@ static const unsigned short lcd_enter_deepstby_seq_23[] = SLEEP16(5), END }; - -/* init sequences */ +#endif /* HAVE_LCD_SLEEP || HAVE_LCD_SHUTDOWN */ #ifdef HAVE_LCD_SLEEP -static const unsigned char lcd_awake_seq_01[] = +/* awake sequences */ + +static const uint8_t lcd_awake_seq_01[] = { - CMD, 0x11, 0, /* Sleep Out Mode */ - SLEEP, 6, /* 60 ms */ - CMD, 0x29, 0, /* Display On */ + CMD, 0x11, 0, /* Sleep Out */ + SLEEP, 6, /* 60 ms */ + CMD, 0x29, 0, /* Display On */ END }; #endif +// XXX: ili9340 DS: pag.168 B7H -> Entry Mode Set, DSTB -> enter this mode and tell how to exit + #if defined(HAVE_LCD_SLEEP) || defined(BOOTLOADER) -static const unsigned short lcd_init_seq_23[] = +/* init sequences */ + +static const uint16_t lcd_init_seq_23[] = { +#ifdef HAVE_LCD_SLEEP + /* release from deep standby mode (ili9320 DS s12.3) */ + CMD16, 0x000, /* NOP */ + DELAY16(20), /* 1024 usecs */ + CMD16, 0x000, + DELAY16(20), + CMD16, 0x000, + DELAY16(20), + CMD16, 0x000, + DELAY16(20), + CMD16, 0x000, + DELAY16(20), + CMD16, 0x000, + DELAY16(20), +#endif + /* Display settings */ MREG16(1), 0x008, 0x0808, MREG16(7), 0x010, 0x0013, 0x0300, 0x0101, 0x0a03, 0x0a0e, 0x0a19, 0x2402, @@ -124,7 +112,7 @@ static const unsigned short lcd_init_seq_23[] = MREG16(14), 0x320, 0x0206, 0x0102, 0x0404, 0x0303, 0x0300, 0x0407, 0x1c1f, 0x0206, 0x0102, 0x0404, 0x0303, 0x0300, 0x0407, 0x1c1f, - /* GRAM and Base Imagen settings (ili9326ds) */ + /* GRAM and Base Imagen settings (ili9326 DS) */ MREG16(2), 0x400, 0x001d, 0x0001, MREG16(1), 0x205, 0x0060, @@ -149,23 +137,22 @@ static const unsigned short lcd_init_seq_23[] = MREG16(1), 0x007, 0x0173, END }; -#endif /* HAVE_LCD_SLEEP || BOOTLOADER */ #ifdef BOOTLOADER -static const unsigned char lcd_init_seq_0[] = +static const uint8_t lcd_init_seq_0[] = { - CMD, 0x11, 0, /* Sleep Out Mode */ - SLEEP, 0x03, /* 30 ms */ - CMD, 0x35, 1, 0x00, /* TEON (TBC) */ - CMD, 0x3a, 1, 0x06, /* COLMOD (TBC) */ - CMD, 0x36, 1, 0x00, /* MADCTR (TBC) */ - CMD, 0x13, 0, /* NORON: Normal Mode On (Partial - Mode Off, Scroll Mode Off) */ + CMD, 0x11, 0, /* Sleep Out */ + SLEEP, 3, /* 30 ms */ + CMD, 0x35, 1, 0x00, /* Tearing Effect Line On */ + CMD, 0x3a, 1, 0x06, /* Pixel Format Set */ + CMD, 0x36, 1, 0x00, /* Memory Access Control */ + + CMD, 0x13, 0, /* Normal Mode On */ CMD, 0x29, 0, /* Display On */ END }; -static const unsigned char lcd_init_seq_1[] = +static const uint8_t lcd_init_seq_1[] = { CMD, 0xb0, 21, 0x3a, 0x3a, 0x80, 0x80, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x3c, 0x30, 0x0f, 0x00, @@ -177,7 +164,7 @@ static const unsigned char lcd_init_seq_1[] = 0x14, 0x09, 0x15, 0x57, 0x27, 0x04, 0x05, CMD, 0xd2, 1, 0x01, - /* Gamma settings (TBC) */ + /* Gamma settings */ CMD, 0xe0, 13, 0x00, 0x00, 0x00, 0x05, 0x0b, 0x12, 0x16, 0x1f, 0x25, 0x22, 0x24, 0x29, 0x1c, CMD, 0xe1, 13, 0x08, 0x01, 0x01, 0x06, 0x0b, 0x11, 0x15, 0x1f, @@ -191,388 +178,84 @@ static const unsigned char lcd_init_seq_1[] = CMD, 0xe5, 13, 0x07, 0x01, 0x01, 0x05, 0x09, 0x0f, 0x13, 0x1e, 0x26, 0x25, 0x28, 0x2e, 0x1e, - CMD, 0x3a, 1, 0x06, /* COLMOD (TBC) */ - CMD, 0xc2, 1, 0x00, /* Power Control 3 (TBC) */ - CMD, 0x35, 1, 0x00, /* TEON (TBC) */ - CMD, 0x11, 0, /* Sleep Out Mode */ - SLEEP, 0x06, /* 60 ms */ - CMD, 0x13, 0, /* NORON: Normal Mode On (Partial - Mode Off, Scroll Mode Off) */ + CMD, 0x3a, 1, 0x06, /* Pixel Format Set */ + CMD, 0xc2, 1, 0x00, /* Power Control */ + CMD, 0x35, 1, 0x00, /* Tearing Effect Line On */ + + CMD, 0x11, 0, /* Sleep Out */ + SLEEP, 6, /* 60 ms */ + CMD, 0x13, 0, /* Normal Mode On */ CMD, 0x29, 0, /* Display On */ END }; -#endif +#endif /* BOOTLOADER */ +#endif /* HAVE_LCD_SLEEP || BOOTLOADER */ -/* DMA configuration */ -/* one single transfer at once, needed LLIs: - * screen_size / (DMAC_LLI_MAX_COUNT << swidth) = - * (320*240*2) / (4095*2) = 19 - */ -#define LCD_DMA_TSKBUF_SZ 1 /* N tasks, MUST be pow2 */ -#define LCD_DMA_LLIBUF_SZ 32 /* N LLIs, MUST be pow2 */ +static struct lcd_info_rec lcd_info_list[] = +{ + [0] = { + .lcd_type = 0, + .mpuiface = LCD_MPUIFACE_PAR18, + .cmdset = LCD_CMDSET_8BIT, + #if defined(HAVE_LCD_SLEEP) || defined(HAVE_LCD_SHUTDOWN) + .seq_sleep = (void*) lcd_sleep_seq_01, + #endif + #ifdef HAVE_LCD_SLEEP + .seq_awake = (void*) lcd_awake_seq_01, + #endif + #ifdef BOOTLOADER + .seq_init = (void*) lcd_init_seq_0, + #endif + }, -static struct dmac_tsk lcd_dma_tskbuf[LCD_DMA_TSKBUF_SZ]; -static struct dmac_lli volatile \ - lcd_dma_llibuf[LCD_DMA_LLIBUF_SZ] CACHEALIGN_ATTR; + [1] = { + .lcd_type = 1, + .mpuiface = LCD_MPUIFACE_PAR18, + .cmdset = LCD_CMDSET_8BIT, + #if defined(HAVE_LCD_SLEEP) || defined(HAVE_LCD_SHUTDOWN) + .seq_sleep = (void*) lcd_sleep_seq_01, + #endif + #ifdef HAVE_LCD_SLEEP + .seq_awake = (void*) lcd_awake_seq_01, + #endif + #ifdef BOOTLOADER + .seq_init = (void*) lcd_init_seq_1, + #endif + }, -static struct dmac_ch lcd_dma_ch = { - .dmac = &s5l8702_dmac0, - .prio = DMAC_CH_PRIO(4), - .cb_fn = NULL, + [2] = { + .lcd_type = 2, + .mpuiface = LCD_MPUIFACE_PAR18, + .cmdset = LCD_CMDSET_16BIT, + #if defined(HAVE_LCD_SLEEP) || defined(HAVE_LCD_SHUTDOWN) + .seq_sleep = (void*) lcd_deepstandby_seq_23, + #endif + #ifdef HAVE_LCD_SLEEP + .seq_awake = (void*) lcd_init_seq_23, + #endif + #ifdef BOOTLOADER + .seq_init = (void*) lcd_init_seq_23, + #endif + }, - .tskbuf = lcd_dma_tskbuf, - .tskbuf_mask = LCD_DMA_TSKBUF_SZ - 1, - .queue_mode = QUEUE_NORMAL, - - .llibuf = lcd_dma_llibuf, - .llibuf_mask = LCD_DMA_LLIBUF_SZ - 1, - .llibuf_bus = DMAC_MASTER_AHB1, + [3] = { + .lcd_type = 3, + .mpuiface = LCD_MPUIFACE_PAR18, + .cmdset = LCD_CMDSET_16BIT, + #if defined(HAVE_LCD_SLEEP) || defined(HAVE_LCD_SHUTDOWN) + .seq_sleep = (void*) lcd_deepstandby_seq_23, + #endif + #ifdef HAVE_LCD_SLEEP + .seq_awake = (void*) lcd_init_seq_23, + #endif + #ifdef BOOTLOADER + .seq_init = (void*) lcd_init_seq_23, + #endif + }, }; -static struct dmac_ch_cfg lcd_dma_ch_cfg = { - .srcperi = S5L8702_DMAC0_PERI_MEM, - .dstperi = S5L8702_DMAC0_PERI_LCD_WR, - .sbsize = DMACCxCONTROL_BSIZE_1, - .dbsize = DMACCxCONTROL_BSIZE_1, - .swidth = DMACCxCONTROL_WIDTH_16, - .dwidth = DMACCxCONTROL_WIDTH_16, - .sbus = DMAC_MASTER_AHB1, - .dbus = DMAC_MASTER_AHB1, - .sinc = DMACCxCONTROL_INC_ENABLE, - .dinc = DMACCxCONTROL_INC_DISABLE, - .prot = DMAC_PROT_CACH | DMAC_PROT_BUFF | DMAC_PROT_PRIV, - .lli_xfer_max_count = DMAC_LLI_MAX_COUNT, -}; - -static inline void s5l_lcd_write_reg(int cmd, unsigned int data) +struct lcd_info_rec* lcd_target_get_info(void) { - while (LCD_STATUS & 0x10); - LCD_WCMD = cmd; - - while (LCD_STATUS & 0x10); - /* 16-bit/1-transfer data format (ili9320ds s7.2.2) */ - LCD_WDATA = (data & 0x78ff) | - ((data & 0x0300) << 1) | ((data & 0x0400) << 5); -} - -static inline void s5l_lcd_write_cmd(unsigned short cmd) -{ - while (LCD_STATUS & 0x10); - LCD_WCMD = cmd; -} - -static inline void s5l_lcd_write_data(unsigned short data) -{ - while (LCD_STATUS & 0x10); - LCD_WDATA = data; -} - -static void lcd_run_seq8(const unsigned char *seq) -{ - int n; - - while (1) switch (*seq++) - { - case CMD: - s5l_lcd_write_cmd(*seq++); - n = *seq++; - while (n--) - s5l_lcd_write_data(*seq++); - break; - case SLEEP: - sleep(*seq++); - break; - case END: - default: - /* bye */ - return; - } -} - -static void lcd_run_seq16(const unsigned short *seq) -{ - int action, param; - unsigned short reg; - - while (1) - { - action = *seq & 0xff; - param = *seq++ >> 8; - - switch (action) - { - case MREG: - reg = *seq++; - while (param--) - s5l_lcd_write_reg(reg++, *seq++); - break; - case SLEEP: - sleep(param); - break; - case END: - default: - /* bye */ - return; - } - } -} - -/*** hardware configuration ***/ - -int lcd_default_contrast(void) -{ - return 0x1f; -} - -void lcd_set_contrast(int val) -{ - (void)val; -} - -void lcd_set_invert_display(bool yesno) -{ - (void)yesno; -} - -void lcd_set_flip(bool yesno) -{ - (void)yesno; -} - -bool lcd_active(void) -{ - return lcd_ispowered; -} - -void lcd_powersave(void) -{ - mutex_lock(&lcd_mutex); - - if (lcd_type & 2) - lcd_run_seq16(lcd_enter_deepstby_seq_23); - else - lcd_run_seq8(lcd_sleep_seq_01); - - /* mask lcd controller clock gate */ - PWRCON(0) |= (1 << CLOCKGATE_LCD); - - lcd_ispowered = false; - - mutex_unlock(&lcd_mutex); -} - -void lcd_shutdown(void) -{ - pmu_write(0x2b, 0); /* Kill the backlight, instantly. */ - pmu_write(0x29, 0); - - lcd_powersave(); -} - -#ifdef HAVE_LCD_SLEEP -void lcd_sleep(void) -{ - lcd_powersave(); -} - -void lcd_awake(void) -{ - mutex_lock(&lcd_mutex); - - /* unmask lcd controller clock gate */ - PWRCON(0) &= ~(1 << CLOCKGATE_LCD); - - if (lcd_type & 2) { - /* release from deep standby mode (ili9320ds s12.3) */ - for (int i = 0; i < 6; i++) { - s5l_lcd_write_cmd(0x000); - udelay(1000); - } - - lcd_run_seq16(lcd_init_seq_23); - } - else - lcd_run_seq8(lcd_awake_seq_01); - - lcd_ispowered = true; - - mutex_unlock(&lcd_mutex); - - send_event(LCD_EVENT_ACTIVATION, NULL); -} -#endif - -/* LCD init */ -void lcd_init_device(void) -{ - mutex_init(&lcd_mutex); - - /* unmask lcd controller clock gate */ - PWRCON(0) &= ~(1 << CLOCKGATE_LCD); - - /* Detect lcd type */ - lcd_type = (PDAT6 & 0x30) >> 4; - - while (!(LCD_STATUS & 0x2)); - LCD_CON = 0x80100db0; - LCD_PHTIME = 0x33; - - /* Configure DMA channel */ - dmac_ch_init(&lcd_dma_ch, &lcd_dma_ch_cfg); - -#ifdef BOOTLOADER - switch (lcd_type) { - case 0: lcd_run_seq8(lcd_init_seq_0); break; - case 1: lcd_run_seq8(lcd_init_seq_1); break; - default: lcd_run_seq16(lcd_init_seq_23); break; - } -#endif - - lcd_ispowered = true; -} - -/*** Update functions ***/ - -static inline void lcd_write_pixel(fb_data pixel) -{ - mutex_lock(&lcd_mutex); - LCD_WDATA = pixel; - mutex_unlock(&lcd_mutex); -} - -/* Update the display. - This must be called after all other LCD functions that change the display. */ -void lcd_update(void) ICODE_ATTR; -void lcd_update(void) -{ - lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); -} - -/* Line write helper function. */ -extern void lcd_write_line(const fb_data *addr, - int pixelcount, - const unsigned int lcd_base_addr); - -static void displaylcd_setup(int x, int y, int width, int height) ICODE_ATTR; -static void displaylcd_setup(int x, int y, int width, int height) -{ - /* TODO: ISR()->panicf()->lcd_update() blocks forever */ - mutex_lock(&lcd_mutex); - while (dmac_ch_running(&lcd_dma_ch)) - yield(); - - int xe = (x + width) - 1; /* max horiz */ - int ye = (y + height) - 1; /* max vert */ - - if (lcd_type & 2) { - s5l_lcd_write_reg(R_HORIZ_ADDR_START_POS, x); - s5l_lcd_write_reg(R_HORIZ_ADDR_END_POS, xe); - s5l_lcd_write_reg(R_VERT_ADDR_START_POS, y); - s5l_lcd_write_reg(R_VERT_ADDR_END_POS, ye); - - s5l_lcd_write_reg(R_HORIZ_GRAM_ADDR_SET, x); - s5l_lcd_write_reg(R_VERT_GRAM_ADDR_SET, y); - - s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); - } else { - s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); - s5l_lcd_write_data(x >> 8); - s5l_lcd_write_data(x & 0xff); - s5l_lcd_write_data(xe >> 8); - s5l_lcd_write_data(xe & 0xff); - - s5l_lcd_write_cmd(R_ROW_ADDR_SET); - s5l_lcd_write_data(y >> 8); - s5l_lcd_write_data(y & 0xff); - s5l_lcd_write_data(ye >> 8); - s5l_lcd_write_data(ye & 0xff); - - s5l_lcd_write_cmd(R_MEMORY_WRITE); - } -} - -static void displaylcd_dma(int pixels) ICODE_ATTR; -static void displaylcd_dma(int pixels) -{ - commit_dcache(); - dmac_ch_queue(&lcd_dma_ch, lcd_dblbuf, - (void*)S5L8702_DADDR_PERI_LCD_WR, pixels*2, NULL); - mutex_unlock(&lcd_mutex); -} - -/* Update a fraction of the display. */ -void lcd_update_rect(int, int, int, int) ICODE_ATTR; -void lcd_update_rect(int x, int y, int width, int height) -{ - int pixels = width * height; - fb_data* p = FBADDR(x,y); - uint16_t* out = lcd_dblbuf[0]; - -#ifdef HAVE_LCD_SLEEP - if (!lcd_active()) return; -#endif - - displaylcd_setup(x, y, width, height); - - /* Copy display bitmap to hardware */ - if (LCD_WIDTH == width) { - /* Write all lines at once */ - memcpy(out, p, pixels * 2); - } else { - do { - /* Write a single line */ - memcpy(out, p, width * 2); - p += LCD_WIDTH; - out += width; - } while (--height); - } - - displaylcd_dma(pixels); -} - -/* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */ -extern void lcd_write_yuv420_lines(unsigned char const * const src[3], - uint16_t* outbuf, - int width, - int stride); - -/* Blit a YUV bitmap directly to the LCD */ -void lcd_blit_yuv(unsigned char * const src[3], - int src_x, int src_y, int stride, - int x, int y, int width, int height) ICODE_ATTR; -void lcd_blit_yuv(unsigned char * const src[3], - int src_x, int src_y, int stride, - int x, int y, int width, int height) -{ - unsigned int z; - unsigned char const * yuv_src[3]; - -#ifdef HAVE_LCD_SLEEP - if (!lcd_active()) return; -#endif - - width = (width + 1) & ~1; /* ensure width is even */ - - int pixels = width * height; - uint16_t* out = lcd_dblbuf[0]; - - z = stride * src_y; - yuv_src[0] = src[0] + z + src_x; - yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); - yuv_src[2] = src[2] + (yuv_src[1] - src[1]); - - displaylcd_setup(x, y, width, height); - - height >>= 1; - - do { - lcd_write_yuv420_lines(yuv_src, out, width, stride); - yuv_src[0] += stride << 1; - yuv_src[1] += stride >> 1; /* Skip down one chroma line */ - yuv_src[2] += stride >> 1; - out += width << 1; - } while (--height); - - displaylcd_dma(pixels); + return &lcd_info_list[(PDAT6 & 0x30) >> 4]; } diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-target.h b/firmware/target/arm/s5l8702/ipod6g/lcd-target.h new file mode 100644 index 0000000000..0f663757a9 --- /dev/null +++ b/firmware/target/arm/s5l8702/ipod6g/lcd-target.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: lcd-nano2g.c 28868 2010-12-21 06:59:17Z Buschel $ + * + * Copyright (C) 2009 by Dave Chapman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __LCD_TARGET_H__ +#define __LCD_TARGET_H__ + +// #include "config.h" + +/* define this to add support for LCDs with 16-bit command set */ +#define S5L_LCD_WITH_CMDSET16 + +/* define this to include support for LCD read ID command */ +// #define S5L_LCD_WITH_READID + +// struct lcd_info_rec* lcd_target_get_info(void); + + +#endif /* __LCD_TARGET_H__ */ diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-asm-6g.S b/firmware/target/arm/s5l8702/lcd-asm-s5l8702.S similarity index 100% rename from firmware/target/arm/s5l8702/ipod6g/lcd-asm-6g.S rename to firmware/target/arm/s5l8702/lcd-asm-s5l8702.S diff --git a/firmware/target/arm/s5l8702/lcd-s5l8702.c b/firmware/target/arm/s5l8702/lcd-s5l8702.c new file mode 100644 index 0000000000..3dcb788a43 --- /dev/null +++ b/firmware/target/arm/s5l8702/lcd-s5l8702.c @@ -0,0 +1,615 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: lcd-nano2g.c 28868 2010-12-21 06:59:17Z Buschel $ + * + * Copyright (C) 2009 by Dave Chapman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include +#include + +#include "config.h" + +#include "kernel.h" +#include "system.h" +#include "cpu.h" +#include "lcd.h" +#ifdef IPOD_6G +#include "pmu-target.h" +#endif +#include "backlight-target.h" + +#include "s5l87xx.h" +#include "clocking-s5l8702.h" +#include "dma-s5l8702.h" +#include "lcd-s5l8702.h" +#include "lcd-target.h" + + +// TODO TODO TODO: HAVE_LCD_ENABLE + +/* Switch command/frame mode: + * + * XXX: WIP, TBC + * + * Configures MPU interface and pixel mode. + * + * Frame mode: + * 6g: + * 16-bit 8080-series parallel MPU interface + * pixel mode: RBG565/1-transfer + * APB[15:0] -> D[17:10,8:1] + * nano3g: + * 9-bit 8080-series parallel PMU interface (TBC) + * pixel mode: RGB565/2-transfers (TBC) + * APB[15:0] -> D[8:1] + D[8:1] (TBC) + * + * Command mode: + * LCD HW that uses 8-bit command set (6g, nano3g): + * 8-bit 8080-series parallel MPU interface + * APB[7:0] -> D[8:1] + * LCD HW that uses 16-bit command set (6g): + * 18-bit 8080-series parallel MPU interface (TBC) + * APB[15:0] -> D[17:10,8:1] + * + * See ILI9320, ILI9326, ILI9340 DS. + */ +/* XXX: see ili9340, pg.27 for MCU interface selection, + * bit31 could be the one that selects interface D[7:0] or D[8:1] for 8-bit), Type-I uses D[7:0] and Type-II uses D[17:10] (ILI9340) + * 9-bit D[8:0] D[17:9] + * 16-bit D[15:0] D[17:10],D[8:1] + * 18-bit D[17:0] D[17:0] + * bit24 could be the one that selects interface D[8:1] or D[17:10] + * MCU_interface Mode Pins Write Read + * #define LCD_MODE_8 0x80000c20 8080 MCU 8-bit bus iface D[8:1] APB[7:0] -> D[8:1] D[8:1] -> LCD_DBUFF[8:1] + * #define LCD_MODE_9 0x81100db8 9-bit + * #define LCD_MODE_16 0x80100db0 16-bit D[17:10,8:1] APB[15:0] -> D[17:10,8:1] + * #define LCD_MODE_18 0x80000da8 18-bit D[17:0] APB[17:0] -> D[17:0] (TBC) + * + * #define LCD_MODE_8 0x80000c20 // LCD_MODE_P8T1 // paralled 8-bit, 1 transfer, TBC: DB[17:10] or DB[8:1] ??? + * #define LCD_MODE_9 0x81100db8 // LCD_MODE_P9T2 // TBC: DB[8:1] or DB[17:10] ???, 2-transfers or 1.5-transfers, RGB565 or RBG666 ??? + * #define LCD_MODE_16 0x80100db0 // LCD_MODE_P16T1 // TBC: DB[17:10,8:1] + * #define LCD_MODE_18 0x80000da8 // LCD_MODE_P18T1 // TBC: DB[17:10,8:1] + */ + +#define LCD_MODE_P8 0x80000c20 // LCD_MODE_P8T1 // paralled 8-bit, 1 transfer, TBC: DB[17:10] or DB[8:1] ??? +#define LCD_MODE_P8b 0x80100c20 // TODO: see if it influences, so far we are using it in nano3g with 0x80000c20 and it seems to be working fine + // It may be a "pixel format" setting for 8 bit, which would only affect DATA and not CMD ??? +#define LCD_MODE_P9 0x81100db8 // LCD_MODE_P9T2 // TBC: DB[8:1] or DB[17:10] ???, 2-transfers or 1.5-transfers, RGB565 or RBG666 ??? +#define LCD_MODE_P16 0x80100db0 // LCD_MODE_P16T1 // TBC: DB[17:10,8:1] +#define LCD_MODE_P18 0x80000da8 // LCD_MODE_P18T1 // TBC: DB[17:10,8:1] + +#define LCD_MODE_S8 0x41000c20 // nano4g +#define LCD_MODE_S9 0x41100db8 // nano4g + + + +#ifdef S5L_LCD_WITH_CMDSET16 +/* LCD type 16-bit register defines */ +#define R_HORIZ_GRAM_ADDR_SET 0x200 +#define R_VERT_GRAM_ADDR_SET 0x201 +#define R_WRITE_DATA_TO_GRAM 0x202 +#define R_HORIZ_ADDR_START_POS 0x210 +#define R_HORIZ_ADDR_END_POS 0x211 +#define R_VERT_ADDR_START_POS 0x212 +#define R_VERT_ADDR_END_POS 0x213 +#endif + +/* LCD type 8-bit register defines */ +#define R_COLUMN_ADDR_SET 0x2a +#define R_ROW_ADDR_SET 0x2b +#define R_MEMORY_WRITE 0x2c + + +/** globals **/ + +int lcd_type; /* also needed in debug-s5l8702.c */ +static struct mutex lcd_mutex; +static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH] CACHEALIGN_ATTR; +static bool lcd_ispowered; + +/* TODO: there is no info about these specific drivers, + some useful info on similar HW such as ILI9320, ILI9326, ILI9340 and */ + +static struct lcd_info_rec *lcd_info; +static void (*lcd_run_seq)(void*); + +/* LCD_CONFIG values for command/frame modes */ +static uint32_t lcd_cmd_mode IDATA_ATTR; +static uint32_t lcd_frame_mode IDATA_ATTR; + + +// TODO +/* Each target must define a list containing all supported LCD types */ +// extern struct lcd_info_rec lcd_info_list[]; +// static struct lcd_info_rec lcd_info_list[]; + + +/* DMA configuration */ + +/* One single transfer at once, needed LLIs: + * screen_size / (DMAC_LLI_MAX_COUNT << swidth) = + * (320*240*2) / (4095*2) = 19 + */ +#define LCD_DMA_TSKBUF_SZ 1 /* N tasks, MUST be pow2 */ +#define LCD_DMA_LLIBUF_SZ 32 /* N LLIs, MUST be pow2 */ + +static struct dmac_tsk lcd_dma_tskbuf[LCD_DMA_TSKBUF_SZ]; +static struct dmac_lli volatile \ + lcd_dma_llibuf[LCD_DMA_LLIBUF_SZ] CACHEALIGN_ATTR; + +static struct dmac_ch lcd_dma_ch = +{ + .dmac = &s5l8702_dmac0, + .prio = DMAC_CH_PRIO(4), + .cb_fn = NULL, + + .tskbuf = lcd_dma_tskbuf, + .tskbuf_mask = LCD_DMA_TSKBUF_SZ - 1, + .queue_mode = QUEUE_NORMAL, + + .llibuf = lcd_dma_llibuf, + .llibuf_mask = LCD_DMA_LLIBUF_SZ - 1, + .llibuf_bus = DMAC_MASTER_AHB1, +}; + +static struct dmac_ch_cfg lcd_dma_ch_cfg = +{ + .srcperi = S5L8702_DMAC0_PERI_MEM, + .dstperi = S5L8702_DMAC0_PERI_LCD_WR, + .sbsize = DMACCxCONTROL_BSIZE_1, + .dbsize = DMACCxCONTROL_BSIZE_1, + .swidth = DMACCxCONTROL_WIDTH_16, + .dwidth = DMACCxCONTROL_WIDTH_16, + .sbus = DMAC_MASTER_AHB1, + .dbus = DMAC_MASTER_AHB1, + .sinc = DMACCxCONTROL_INC_ENABLE, + .dinc = DMACCxCONTROL_INC_DISABLE, + .prot = DMAC_PROT_CACH | DMAC_PROT_BUFF | DMAC_PROT_PRIV, + .lli_xfer_max_count = DMAC_LLI_MAX_COUNT, +}; + + +/*** clocks ***/ + +// TODO: In mks5lboot --mkraw put a command to specify the address of the binary, +// for example --address 0x6000, it must be greater than 0x310 which would be the default address, +// pass this address (0x310..128Kb) in the dfu_options flag + +// TODO: to lcd-target.c +static void lcd_target_enable_clocks(bool enable) +{ + clockgate_enable(CLOCKGATE_LCD, enable); +#ifdef IPOD_NANO4G + clockgate_enable(CLOCKGATE_LCD_2, enable); +#endif +} + + +/*** LCD controller - low level functions ***/ + +static void s5l_lcd_write_config(uint32_t config) ICODE_ATTR; +static void s5l_lcd_write_config(uint32_t config) +{ + while (!(LCD_STATUS & 0x2)); + udelay(1); + LCD_CON = config; +} + +static void s5l_lcd_write_cmd(uint16_t cmd) ICODE_ATTR; +static void s5l_lcd_write_cmd(uint16_t cmd) +{ + while (LCD_STATUS & 0x10); + LCD_WCMD = cmd; +} + +static void s5l_lcd_write_data(uint16_t data) ICODE_ATTR; +static void s5l_lcd_write_data(uint16_t data) +{ + while (LCD_STATUS & 0x10); + LCD_WDATA = data; +} + +static void s5l_lcd_send_cmd8(uint8_t cmd, int len, uint8_t *data) ICODE_ATTR; +static void s5l_lcd_send_cmd8(uint8_t cmd, int len, uint8_t *data) +{ + s5l_lcd_write_cmd(cmd); + while (len--) + s5l_lcd_write_data(*data++); +} + +#ifdef S5L_LCD_WITH_READID +static void s5l_lcd_recv_cmd8(uint8_t cmd, int len, uint8_t *buf) +{ + s5l_lcd_write_cmd(cmd); + while (len--) { + while (!(LCD_STATUS & 0x2)); + LCD_RDATA = 0; + while (!(LCD_STATUS & 1)); + *buf++ = LCD_DBUFF >> 1; + } +} +#endif + +#define s5l_lcd_set_command_mode() s5l_lcd_write_config(lcd_cmd_mode) +#define s5l_lcd_set_frame_mode() s5l_lcd_write_config(lcd_frame_mode) + +static void s5l_lcd_run_seq8(void *seq8) +{ + uint8_t *seq = seq8; + + while (1) switch (*seq++) + { + case CMD: + { + uint8_t cmd = *seq++; + int len = *seq++; + s5l_lcd_send_cmd8(cmd, len, seq); + seq += len; + break; + } + case SLEEP: + sleep(*seq++); + break; + case END: + default: + /* bye */ + return; + } +} + +#ifdef S5L_LCD_WITH_CMDSET16 +static void s5l_lcd_write_reg(uint16_t cmd, uint16_t data) ICODE_ATTR; +static void s5l_lcd_write_reg(uint16_t cmd, uint16_t data) +{ + s5l_lcd_write_cmd(cmd); + s5l_lcd_write_data(data); +} + +static void s5l_lcd_run_seq16(void *seq16) +{ + uint16_t *seq = seq16; + int action, param; + uint16_t reg; + + while (1) + { + action = *seq & 0xff; + param = *seq++ >> 8; + + switch (action) + { + case CMD: + s5l_lcd_write_cmd(*seq++); + break; + case MREG: + reg = *seq++; + while (param--) + s5l_lcd_write_reg(reg++, *seq++); + break; + case SLEEP: + sleep(param); + break; + case DELAY: + udelay(param<<6); + break; + case END: + default: + /* bye */ + return; + } + } +} +#endif /* S5L_LCD_WITH_CMDSET16 */ + + +/*** Update functions ***/ + +/* Update the display. + This must be called after all other LCD functions that change the display. */ +void lcd_update(void) ICODE_ATTR; +void lcd_update(void) +{ + lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); +} + +static void displaylcd_setup(int x, int y, int width, int height) ICODE_ATTR; +static void displaylcd_setup(int x, int y, int width, int height) +{ + int xe = (x + width) - 1; /* max horiz */ + int ye = (y + height) - 1; /* max vert */ + + s5l_lcd_set_command_mode(); + +#ifdef S5L_LCD_WITH_CMDSET16 + if (lcd_info->cmdset == LCD_CMDSET_16BIT) + { + s5l_lcd_write_reg(R_HORIZ_ADDR_START_POS, x); + s5l_lcd_write_reg(R_HORIZ_ADDR_END_POS, xe); + s5l_lcd_write_reg(R_VERT_ADDR_START_POS, y); + s5l_lcd_write_reg(R_VERT_ADDR_END_POS, ye); + + s5l_lcd_write_reg(R_HORIZ_GRAM_ADDR_SET, x); + s5l_lcd_write_reg(R_VERT_GRAM_ADDR_SET, y); + + s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); + } + else +#endif + { + uint8_t col[] = { x >> 8, x & 0xff, xe >> 8, xe & 0xff }; + uint8_t row[] = { y >> 8, y & 0xff, ye >> 8, ye & 0xff }; + s5l_lcd_send_cmd8(R_COLUMN_ADDR_SET, 4, col); + s5l_lcd_send_cmd8(R_ROW_ADDR_SET, 4, row); + + s5l_lcd_write_cmd(R_MEMORY_WRITE); + } +} + +static void displaylcd_dma(int pixels) ICODE_ATTR; +static void displaylcd_dma(int pixels) +{ + s5l_lcd_set_frame_mode(); + commit_dcache(); + dmac_ch_queue(&lcd_dma_ch, lcd_dblbuf, + (void*)S5L8702_DADDR_PERI_LCD_WR, pixels*2, NULL); +} + +// TODO: wait if there is a DMA transfer in progress +static void displaylcd_wait_dma(void) ICODE_ATTR; +static void displaylcd_wait_dma(void) +{ + while (dmac_ch_running(&lcd_dma_ch)) + yield(); +} + +/* Update a fraction of the display. */ +void lcd_update_rect(int, int, int, int) ICODE_ATTR; +void lcd_update_rect(int x, int y, int width, int height) +{ + int pixels = width * height; + fb_data* p = FBADDR(x,y); + uint16_t* out = lcd_dblbuf[0]; + + /* FIXME: ISR()->panicf()->lcd_update() blocks forever */ + mutex_lock(&lcd_mutex); + if (lcd_ispowered) + { + // XXX: We contemplate the case where the LCD has entered SLEEP, + // the s5l_lcd_set_command_mode() writes LCD_CONFIG + // XXX: It is also possible that if the LCD clockgate has been disabled, + // the LCD_CONFIG = xxx may still be blocked by the while(status == ok), + // since it does not check the same status bit as when writing command/data + + displaylcd_wait_dma(); + + displaylcd_setup(x, y, width, height); + + /* Copy display bitmap to hardware */ + if (LCD_WIDTH == width) { + /* Write all lines at once */ + memcpy(out, p, pixels * 2); + } else { + do { + /* Write a single line */ + memcpy(out, p, width * 2); + p += LCD_WIDTH; + out += width; + } while (--height); + } + + displaylcd_dma(pixels); + } + mutex_unlock(&lcd_mutex); +} + +/* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */ +extern void lcd_write_yuv420_lines(unsigned char const * const src[3], + uint16_t* outbuf, + int width, + int stride); + +/* Blit a YUV bitmap directly to the LCD */ +void lcd_blit_yuv(unsigned char * const src[3], + int src_x, int src_y, int stride, + int x, int y, int width, int height) ICODE_ATTR; +void lcd_blit_yuv(unsigned char * const src[3], + int src_x, int src_y, int stride, + int x, int y, int width, int height) +{ + unsigned int z; + unsigned char const * yuv_src[3]; + + width = (width + 1) & ~1; /* ensure width is even */ + + int pixels = width * height; + uint16_t* out = lcd_dblbuf[0]; + + z = stride * src_y; + yuv_src[0] = src[0] + z + src_x; + yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); + yuv_src[2] = src[2] + (yuv_src[1] - src[1]); + + /* TODO: ISR()->panicf()->lcd_update() blocks forever */ + mutex_lock(&lcd_mutex); + if (lcd_ispowered) + { + displaylcd_wait_dma(); + + displaylcd_setup(x, y, width, height); + + height >>= 1; + + do { + lcd_write_yuv420_lines(yuv_src, out, width, stride); + yuv_src[0] += stride << 1; + yuv_src[1] += stride >> 1; /* Skip down one chroma line */ + yuv_src[2] += stride >> 1; + out += width << 1; + } while (--height); + + displaylcd_dma(pixels); + } + mutex_unlock(&lcd_mutex); +} + + +/*** hardware configuration ***/ + +int lcd_default_contrast(void) +{ + return 0x1f; +} + +void lcd_set_contrast(int val) +{ + (void)val; +} + +void lcd_set_invert_display(bool yesno) +{ + (void)yesno; +} + +void lcd_set_flip(bool yesno) +{ + (void)yesno; +} + +#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) +bool lcd_active(void) +{ + return lcd_ispowered; +} +#endif + +#if defined(HAVE_LCD_SHUTDOWN) || defined(HAVE_LCD_SLEEP) +static void lcd_powersave(void) +{ + mutex_lock(&lcd_mutex); + + displaylcd_wait_dma(); + // XXX: Do not change modes while data is being sent + s5l_lcd_set_command_mode(); + lcd_run_seq(lcd_info->seq_sleep); + + lcd_target_enable_clocks(false); + + lcd_ispowered = false; + + mutex_unlock(&lcd_mutex); +} +#endif /* HAVE_LCD_SHUTDOWN || HAVE_LCD_SLEEP */ + +#ifdef HAVE_LCD_SHUTDOWN +void lcd_shutdown(void) +{ + backlight_hw_kill(); /* Kill the backlight, instantly. */ + lcd_powersave(); +} +#endif + +#ifdef HAVE_LCD_SLEEP +void lcd_sleep(void) +{ + lcd_powersave(); +} + +void lcd_awake(void) +{ + mutex_lock(&lcd_mutex); + + lcd_target_enable_clocks(true); + // XXX: Do not change modes while data is being sent + s5l_lcd_set_command_mode(); + lcd_run_seq(lcd_info->seq_awake); + lcd_ispowered = true; // XXX: we have to put the lcd_ispowered before the lcd_update() + + lcd_update(); // XXX: update the display and wait for the update to finish before returning, + + displaylcd_wait_dma(); // we should really do sleep_out + lcd_update + display_on, + // we can put a command in the sequence to do it + + mutex_unlock(&lcd_mutex); + send_event(LCD_EVENT_ACTIVATION, NULL); +} +#endif + +#ifdef S5L_LCD_WITH_READID +// TODO: protect it with mutex and while(dma) if you want to call it from other places (e.g. DEBUG) +void lcd_read_display_id(int mpuiface, uint8_t *lcd_id) +{ + s5l_lcd_write_config( + (mpuiface == LCD_MPUIFACE_SERIAL) ? LCD_MODE_S8 : LCD_MODE_P8); + s5l_lcd_recv_cmd8(4, 4, lcd_id); +} +#endif + +/* LCD init */ +void lcd_init_device(void) +{ + mutex_init(&lcd_mutex); + + lcd_target_enable_clocks(true); +#if defined(IPOD_6G) || defined(IPOD_NANO3G) + LCD_PHTIME = 0x33; +#elif defined(IPOD_NANO4G) + cg16_config(&CG16_LCD, true, CG16_SEL_PLL0, 16, 1, 0x0); + s5l_lcd_write_config(LCD_MODE_S9); + cg16_config(&CG16_LCD, false, CG16_SEL_PLL0, 16, 1, 0x0); + LCD_PHTIME = 0x11; +#endif + + lcd_info = lcd_target_get_info(); + lcd_type = lcd_info->lcd_type; + + /* select mode to send commands */ +#ifdef S5L_LCD_WITH_CMDSET16 + if (lcd_info->cmdset == LCD_CMDSET_16BIT) + { + lcd_cmd_mode = LCD_MODE_P18; + lcd_run_seq = s5l_lcd_run_seq16; + } + else /* LCD_CMDSET_8BIT */ +#endif + { + if (lcd_info->mpuiface == LCD_MPUIFACE_SERIAL) + lcd_cmd_mode = LCD_MODE_S8; + else + lcd_cmd_mode = LCD_MODE_P8; + lcd_run_seq = s5l_lcd_run_seq8; + } + + /* select mode to send RGB565 data */ + if (lcd_info->mpuiface == LCD_MPUIFACE_PAR9) + lcd_frame_mode = LCD_MODE_P9; + else if (lcd_info->mpuiface == LCD_MPUIFACE_PAR18) + lcd_frame_mode = LCD_MODE_P16; + else /* LCD_MPUIFACE_SERIAL */ + lcd_frame_mode = LCD_MODE_S9; + + s5l_lcd_set_command_mode(); + + /* Configure DMA channel */ // TODO: this right after mutex_init() + dmac_ch_init(&lcd_dma_ch, &lcd_dma_ch_cfg); + +#ifdef BOOTLOADER + lcd_run_seq(lcd_info->seq_init); +#endif + + lcd_ispowered = true; +} diff --git a/firmware/target/arm/s5l8702/lcd-s5l8702.h b/firmware/target/arm/s5l8702/lcd-s5l8702.h new file mode 100644 index 0000000000..8bed192a88 --- /dev/null +++ b/firmware/target/arm/s5l8702/lcd-s5l8702.h @@ -0,0 +1,90 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: + * + * Copyright © 2009 Michael Sparmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __LCD_S5L8702_H__ +#define __LCD_S5L8702_H__ + +#include + +#include "config.h" +#include "lcd-target.h" + + +/* sequence actions */ +enum { + CMD = 0, /* send command with N data */ + SLEEP, /* unit: RB tick */ // TODO: the unit in ms. but using HZ +#ifdef S5L_LCD_WITH_CMDSET16 + MREG, /* write multiple registers */ + DELAY, /* unit: 64 us. */ +#endif + END = 0xff +}; + +#ifdef S5L_LCD_WITH_CMDSET16 +/* pack 16-bit sequence actions */ +#define CMD16 (CMD) /* send command with no data */ // TODO: why not use MREG16(0) ??? +#define MREG16(len) (MREG | ((len) << 8)) +#define SLEEP16(t) (SLEEP | ((t) << 8)) +#define DELAY16(t) (DELAY | ((t) << 8)) + +/* Supported command sets */ +enum { + LCD_CMDSET_8BIT = 0, /* 8-bit command set similar to TODO */ + LCD_CMDSET_16BIT, /* 16-bit command set similar to TODO */ +}; +#endif + +/* Supported MPU interfaces */ +enum { + LCD_MPUIFACE_PAR9 = 0, /* 8080-series 9-bit parallel */ + LCD_MPUIFACE_PAR18, /* 8080-series 18-bit parallel */ + LCD_MPUIFACE_SERIAL, /* 3-pin SPI (TBC) */ +}; + + +// TODO: typedef struct {} lcd_info_t; +struct lcd_info_rec { + uint8_t lcd_type; + uint8_t mpuiface; /* LCD_MPUIFACE_ */ +#ifdef S5L_LCD_WITH_CMDSET16 + uint8_t cmdset; /* LCD_CMDSET_ */ +#endif + /* sequences */ +#if defined(HAVE_LCD_SLEEP) || defined(HAVE_LCD_SHUTDOWN) + void *seq_sleep; +#endif +#ifdef HAVE_LCD_SLEEP + void *seq_awake; +#endif +#ifdef BOOTLOADER + void *seq_init; +#endif +}; + +void lcd_awake(void); + +#ifdef S5L_LCD_WITH_READID +void lcd_read_display_id(int mupiface, uint8_t *lcd_id); +#endif + +extern struct lcd_info_rec* lcd_target_get_info(void); + +#endif /* __LCD_S5L8702_H__ */