1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Aidan MacDonald 2021-05-25 23:41:08 +01:00
parent a6b5de6a89
commit cec6422ace
2 changed files with 49 additions and 35 deletions

View file

@ -65,8 +65,10 @@ static fb_data shadowfb[LCD_HEIGHT*LCD_WIDTH] __attribute__((aligned(64)));
/* Signals DMA copy to shadow FB is done */ /* Signals DMA copy to shadow FB is done */
static volatile int fbcopy_done; static volatile int fbcopy_done;
#if defined(HAVE_LCD_SLEEP) || defined(LCD_X1000_FASTSLEEP)
/* True if we're in sleep mode */ /* True if we're in sleep mode */
static bool lcd_sleeping = false; static bool lcd_sleeping = false;
#endif
/* Check if running with interrupts disabled (eg: panic screen) */ /* Check if running with interrupts disabled (eg: panic screen) */
#define lcd_panic_mode \ #define lcd_panic_mode \
@ -98,16 +100,16 @@ static void lcd_init_controller(const struct lcd_tgt_config* cfg)
default: break; 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)); mcfg_new |= jz_orf(LCD_MCFG_NEW, DTYPE_V(SERIAL), CTYPE_V(SERIAL));
else else
mcfg_new |= jz_orf(LCD_MCFG_NEW, DTYPE_V(PARALLEL), CTYPE_V(PARALLEL)); mcfg_new |= jz_orf(LCD_MCFG_NEW, DTYPE_V(PARALLEL), CTYPE_V(PARALLEL));
jz_vwritef(mcfg_new, LCD_MCFG_NEW, jz_vwritef(mcfg_new, LCD_MCFG_NEW,
6800_MODE(lcd_tgt_config.use_6800_mode), 6800_MODE(cfg->use_6800_mode),
CSPLY(lcd_tgt_config.wr_polarity ? 0 : 1), CSPLY(cfg->wr_polarity ? 0 : 1),
RSPLY(lcd_tgt_config.dc_polarity), RSPLY(cfg->dc_polarity),
CLKPLY(lcd_tgt_config.clk_polarity)); CLKPLY(cfg->clk_polarity));
/* Program the configuration. Note we cannot enable TE signal at /* Program the configuration. Note we cannot enable TE signal at
* this stage, because the panel will need to be configured first. * 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); jz_write(LCD_SMWT, 0);
/* DMA settings */ /* 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), 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_DAH, LCD_WIDTH);
jz_write(LCD_DAV, LCD_HEIGHT); 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) static void lcd_dma_start(void)
{ {
/* Set format conversion bit, seems necessary for DMA mode */ /* Set format conversion bit, seems necessary for DMA mode.
jz_writef(LCD_MCFG_NEW, FMT_CONV(1)); * 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 */ /* Program vsync configuration */
jz_writef(LCD_MCTRL, NARROW_TE(lcd_tgt_config.te_narrow), 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)); 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) static bool lcd_wait_frame(void)
{ {
/* Bail out if DMA is not enabled */ /* Bail out if DMA is not enabled */
@ -321,6 +310,26 @@ static bool lcd_wait_frame(void)
return true; 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) static void lcd_send(uint32_t d)
{ {
while(jz_readf(LCD_MSTATE, BUSY)); while(jz_readf(LCD_MSTATE, BUSY));
@ -404,7 +413,8 @@ void lcd_enable(bool en)
restore_irq(irq); restore_irq(irq);
/* Deal with sleep mode */ /* 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) { if(bit && !en) {
lcd_tgt_sleep(true); lcd_tgt_sleep(true);
lcd_sleeping = true; lcd_sleeping = true;
@ -414,6 +424,7 @@ void lcd_enable(bool en)
lcd_tgt_sleep(false); lcd_tgt_sleep(false);
lcd_sleeping = false; lcd_sleeping = false;
} }
#endif
/* Handle turning the LCD back on */ /* Handle turning the LCD back on */
if(!bit && en) if(!bit && en)

View file

@ -38,34 +38,37 @@
struct lcd_tgt_config { struct lcd_tgt_config {
/* Data bus width, in bits */ /* Data bus width, in bits */
int bus_width: 8; unsigned bus_width: 8;
/* Command bus width, in bits */ /* Command bus width, in bits */
int cmd_width: 8; unsigned cmd_width: 8;
/* 1 = use 6800 timings, 0 = use 8080 timings */ /* 1 = use 6800 timings, 0 = use 8080 timings */
int use_6800_mode: 1; unsigned use_6800_mode: 1;
/* 1 = serial interface, 0 = parallel interface */ /* 1 = serial interface, 0 = parallel interface */
int use_serial: 1; unsigned use_serial: 1;
/* Clock active edge: 0 = falling edge, 1 = rising edge */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 /* Commands used to initiate a framebuffer write. Buffer must be
* aligned to 64-byte boundary and size must be a multiple of 4, * aligned to 64-byte boundary and size must be a multiple of 4,