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 */
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)

View file

@ -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,