From cec6422ace933fecc02053c0fa6b239f7a6792e5 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Tue, 25 May 2021 23:41:08 +0100 Subject: x1000: LCD driver minor fixes & improvements - Use unsigned bitfields in 'lcd_tgt_config' - Set DTIMES when using an 8-bit bus width - Allow using DMA big-endian mode - Provide an #ifdef to avoid stopping DMA in the middle of a frame - Correctly #ifdef LCD sleep code when target does not implement it Change-Id: I327c6b05223638b876d5ab62cb6e48f82e6d5fa5 --- firmware/target/mips/ingenic_x1000/lcd-x1000.c | 61 +++++++++++++++----------- firmware/target/mips/ingenic_x1000/lcd-x1000.h | 23 +++++----- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/firmware/target/mips/ingenic_x1000/lcd-x1000.c b/firmware/target/mips/ingenic_x1000/lcd-x1000.c index aadf93c8ff..193ff082e0 100644 --- a/firmware/target/mips/ingenic_x1000/lcd-x1000.c +++ b/firmware/target/mips/ingenic_x1000/lcd-x1000.c @@ -65,8 +65,10 @@ static fb_data shadowfb[LCD_HEIGHT*LCD_WIDTH] __attribute__((aligned(64))); /* Signals DMA copy to shadow FB is done */ static volatile int fbcopy_done; +#if defined(HAVE_LCD_SLEEP) || defined(LCD_X1000_FASTSLEEP) /* True if we're in sleep mode */ static bool lcd_sleeping = false; +#endif /* Check if running with interrupts disabled (eg: panic screen) */ #define lcd_panic_mode \ @@ -98,16 +100,16 @@ static void lcd_init_controller(const struct lcd_tgt_config* cfg) default: break; } - if(lcd_tgt_config.use_serial) + if(cfg->use_serial) mcfg_new |= jz_orf(LCD_MCFG_NEW, DTYPE_V(SERIAL), CTYPE_V(SERIAL)); else mcfg_new |= jz_orf(LCD_MCFG_NEW, DTYPE_V(PARALLEL), CTYPE_V(PARALLEL)); jz_vwritef(mcfg_new, LCD_MCFG_NEW, - 6800_MODE(lcd_tgt_config.use_6800_mode), - CSPLY(lcd_tgt_config.wr_polarity ? 0 : 1), - RSPLY(lcd_tgt_config.dc_polarity), - CLKPLY(lcd_tgt_config.clk_polarity)); + 6800_MODE(cfg->use_6800_mode), + CSPLY(cfg->wr_polarity ? 0 : 1), + RSPLY(cfg->dc_polarity), + CLKPLY(cfg->clk_polarity)); /* Program the configuration. Note we cannot enable TE signal at * this stage, because the panel will need to be configured first. @@ -122,9 +124,9 @@ static void lcd_init_controller(const struct lcd_tgt_config* cfg) jz_write(LCD_SMWT, 0); /* DMA settings */ - jz_writef(LCD_CTRL, BURST_V(64WORD), + jz_writef(LCD_CTRL, ENABLE(0), BURST_V(64WORD), EOFM(1), SOFM(0), IFUM(0), QDM(0), - BEDN(0), PEDN(0), ENABLE(0)); + BEDN(cfg->big_endian), PEDN(0)); jz_write(LCD_DAH, LCD_WIDTH); jz_write(LCD_DAV, LCD_HEIGHT); } @@ -274,8 +276,10 @@ static void lcd_fbcopy_dma_partial(int x, int y, int width, int height) static void lcd_dma_start(void) { - /* Set format conversion bit, seems necessary for DMA mode */ - jz_writef(LCD_MCFG_NEW, FMT_CONV(1)); + /* Set format conversion bit, seems necessary for DMA mode. + * Must set DTIMES here if we use an 8-bit bus type. */ + int dtimes = lcd_tgt_config.bus_width == 8 ? (LCD_DEPTH/8 - 1) : 0; + jz_writef(LCD_MCFG_NEW, FMT_CONV(1), DTIMES(dtimes)); /* Program vsync configuration */ jz_writef(LCD_MCTRL, NARROW_TE(lcd_tgt_config.te_narrow), @@ -290,21 +294,6 @@ static void lcd_dma_start(void) jz_writef(LCD_CTRL, ENABLE(1)); } -static void lcd_dma_stop(void) -{ - /* Stop the DMA transfer */ - jz_writef(LCD_CTRL, ENABLE(0)); - jz_writef(LCD_MCTRL, DMA_TX_EN(0)); - - /* Wait for disable to take effect */ - while(jz_readf(LCD_STATE, QD) == 0); - jz_writef(LCD_STATE, QD(0)); - - /* Clear format conversion bit, disable vsync */ - jz_writef(LCD_MCFG_NEW, FMT_CONV(0)); - jz_writef(LCD_MCTRL, NARROW_TE(0), TE_INV(0), NOT_USE_TE(1)); -} - static bool lcd_wait_frame(void) { /* Bail out if DMA is not enabled */ @@ -321,6 +310,26 @@ static bool lcd_wait_frame(void) return true; } +static void lcd_dma_stop(void) +{ +#ifdef LCD_X1000_DMA_WAIT_FOR_FRAME + /* Wait for frame to finish to avoid misaligning the write pointer */ + lcd_wait_frame(); +#endif + + /* Stop the DMA transfer */ + jz_writef(LCD_CTRL, ENABLE(0)); + jz_writef(LCD_MCTRL, DMA_TX_EN(0)); + + /* Wait for disable to take effect */ + while(jz_readf(LCD_STATE, QD) == 0); + jz_writef(LCD_STATE, QD(0)); + + /* Clear format conversion bit, disable vsync */ + jz_writef(LCD_MCFG_NEW, FMT_CONV(0), DTIMES(0)); + jz_writef(LCD_MCTRL, NARROW_TE(0), TE_INV(0), NOT_USE_TE(1)); +} + static void lcd_send(uint32_t d) { while(jz_readf(LCD_MSTATE, BUSY)); @@ -404,7 +413,8 @@ void lcd_enable(bool en) restore_irq(irq); /* Deal with sleep mode */ -#ifdef LCD_X1000_FASTSLEEP +#if defined(HAVE_LCD_SLEEP) || defined(LCD_X1000_FASTSLEEP) +#if defined(LCD_X1000_FASTSLEEP) if(bit && !en) { lcd_tgt_sleep(true); lcd_sleeping = true; @@ -414,6 +424,7 @@ void lcd_enable(bool en) lcd_tgt_sleep(false); lcd_sleeping = false; } +#endif /* Handle turning the LCD back on */ if(!bit && en) diff --git a/firmware/target/mips/ingenic_x1000/lcd-x1000.h b/firmware/target/mips/ingenic_x1000/lcd-x1000.h index 96085ac207..749fac8240 100644 --- a/firmware/target/mips/ingenic_x1000/lcd-x1000.h +++ b/firmware/target/mips/ingenic_x1000/lcd-x1000.h @@ -38,34 +38,37 @@ struct lcd_tgt_config { /* Data bus width, in bits */ - int bus_width: 8; + unsigned bus_width: 8; /* Command bus width, in bits */ - int cmd_width: 8; + unsigned cmd_width: 8; /* 1 = use 6800 timings, 0 = use 8080 timings */ - int use_6800_mode: 1; + unsigned use_6800_mode: 1; /* 1 = serial interface, 0 = parallel interface */ - int use_serial: 1; + unsigned use_serial: 1; /* Clock active edge: 0 = falling edge, 1 = rising edge */ - int clk_polarity: 1; + unsigned clk_polarity: 1; /* DC pin levels: 1 = data high, command low; 0 = data low, command high */ - int dc_polarity: 1; + unsigned dc_polarity: 1; /* WR pin level during idle: 1 = keep high; 0 = keep low */ - int wr_polarity: 1; + unsigned wr_polarity: 1; /* 1 to enable vsync, so DMA transfer is synchronized with TE signal */ - int te_enable: 1; + unsigned te_enable: 1; /* Active level of TE signal: 1 = high, 0 = low */ - int te_polarity: 1; + unsigned te_polarity: 1; /* 1 = support narrow TE signal (<=3 pixel clocks); 0 = don't support */ - int te_narrow: 1; + unsigned te_narrow: 1; + + /* 1 = big endian mode, 0 = little endian mode */ + unsigned big_endian: 1; /* Commands used to initiate a framebuffer write. Buffer must be * aligned to 64-byte boundary and size must be a multiple of 4, -- cgit v1.2.3