Skip to content

Commit 83aa4aa

Browse files
danieldegrassekartben
authored andcommitted
drivers: mipi_dbi_nxp_lcdic: add support for mipi_dbi_configure_te
Add support for the mipi_dbi_configure_te API within the NXP LCDIC peripheral. Also, remove a redundant code patch in the write_command function that was previously used to determine when the display driver was writing to graphics RAM, as these writes should now be performed using the mipi_dbi_write_display API. Signed-off-by: Daniel DeGrasse <[email protected]>
1 parent b1d1b70 commit 83aa4aa

File tree

1 file changed

+88
-14
lines changed

1 file changed

+88
-14
lines changed

drivers/mipi_dbi/mipi_dbi_nxp_lcdic.c

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ enum lcdic_cmd_type {
3434
LCDIC_TX = 1,
3535
};
3636

37+
enum lcdic_cmd_te {
38+
LCDIC_TE_NO_SYNC = 0,
39+
LCDIC_TE_RISING_EDGE = 1,
40+
LCDIC_TE_FALLING_EDGE = 2,
41+
};
42+
3743
/* Limit imposed by size of data length field in LCDIC command */
3844
#define LCDIC_MAX_XFER 0x40000
3945
/* Max reset width (in terms of Timer0_Period, see RST_CTRL register) */
@@ -102,6 +108,10 @@ struct mipi_dbi_lcdic_data {
102108
uint32_t unaligned_word __aligned(4);
103109
/* Tracks lcdic_data_fmt value we should use for pixel data */
104110
uint8_t pixel_fmt;
111+
/* Tracks TE edge setting we should use for pixel data */
112+
uint8_t te_edge;
113+
/* Are we starting a new display frame */
114+
bool new_frame;
105115
const struct mipi_dbi_config *active_cfg;
106116
struct k_sem xfer_sem;
107117
struct k_sem lock;
@@ -376,6 +386,7 @@ static void mipi_dbi_lcdic_set_cmd(LCDIC_Type *base,
376386
enum lcdic_cmd_type dir,
377387
enum lcdic_cmd_dc dc,
378388
enum lcdic_data_fmt data_fmt,
389+
enum lcdic_cmd_te te_sync,
379390
uint32_t buf_len)
380391
{
381392
union lcdic_trx_cmd cmd = {0};
@@ -387,6 +398,7 @@ static void mipi_dbi_lcdic_set_cmd(LCDIC_Type *base,
387398
cmd.bits.trx = dir;
388399
cmd.bits.cmd_done_int = true;
389400
cmd.bits.data_format = data_fmt;
401+
cmd.bits.te_sync_mode = te_sync;
390402
/* Write command */
391403
base->TFIFO_WDATA = cmd.u32;
392404
}
@@ -401,6 +413,7 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
401413
struct mipi_dbi_lcdic_data *dev_data = dev->data;
402414
LCDIC_Type *base = config->base;
403415
int ret;
416+
enum lcdic_cmd_te te_sync = LCDIC_TE_NO_SYNC;
404417
uint32_t interrupts = 0U;
405418

406419
ret = k_sem_take(&dev_data->lock, K_FOREVER);
@@ -413,6 +426,26 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
413426
goto out;
414427
}
415428

429+
if (dev_data->new_frame) {
430+
switch (dev_data->te_edge) {
431+
case MIPI_DBI_TE_RISING_EDGE:
432+
te_sync = LCDIC_TE_RISING_EDGE;
433+
break;
434+
case MIPI_DBI_TE_FALLING_EDGE:
435+
te_sync = LCDIC_TE_FALLING_EDGE;
436+
break;
437+
default:
438+
te_sync = LCDIC_TE_NO_SYNC;
439+
break;
440+
}
441+
dev_data->new_frame = false;
442+
}
443+
444+
if (!desc->frame_incomplete) {
445+
/* Next frame will be a new one */
446+
dev_data->new_frame = true;
447+
}
448+
416449
/* State reset is required before transfer */
417450
mipi_dbi_lcdic_reset_state(dev);
418451

@@ -448,6 +481,7 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
448481
*/
449482
mipi_dbi_lcdic_set_cmd(base, LCDIC_TX, LCDIC_DATA,
450483
dev_data->pixel_fmt,
484+
te_sync,
451485
dev_data->cmd_bytes);
452486
#ifdef CONFIG_MIPI_DBI_NXP_LCDIC_DMA
453487
/* Enable command complete interrupt */
@@ -506,7 +540,7 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
506540

507541
/* Write command */
508542
mipi_dbi_lcdic_set_cmd(base, LCDIC_TX, LCDIC_COMMAND,
509-
LCDIC_DATA_FMT_BYTE, 1);
543+
LCDIC_DATA_FMT_BYTE, LCDIC_TE_NO_SYNC, 1);
510544
/* Use standard byte writes */
511545
dev_data->pixel_fmt = LCDIC_DATA_FMT_BYTE;
512546
base->TFIFO_WDATA = cmd;
@@ -530,18 +564,10 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
530564
dev_data->xfer_buf,
531565
dev_data->cmd_bytes);
532566
}
533-
if (cmd == MIPI_DCS_WRITE_MEMORY_START) {
534-
/* Use pixel format data width, so we can byte swap
535-
* if needed
536-
*/
537-
mipi_dbi_lcdic_set_cmd(base, LCDIC_TX, LCDIC_DATA,
538-
dev_data->pixel_fmt,
539-
dev_data->cmd_bytes);
540-
} else {
541-
mipi_dbi_lcdic_set_cmd(base, LCDIC_TX, LCDIC_DATA,
542-
LCDIC_DATA_FMT_BYTE,
543-
dev_data->cmd_bytes);
544-
}
567+
mipi_dbi_lcdic_set_cmd(base, LCDIC_TX, LCDIC_DATA,
568+
LCDIC_DATA_FMT_BYTE,
569+
LCDIC_TE_NO_SYNC,
570+
dev_data->cmd_bytes);
545571
#ifdef CONFIG_MIPI_DBI_NXP_LCDIC_DMA
546572
if (((((uint32_t)dev_data->xfer_buf) & 0x3) == 0) ||
547573
(dev_data->cmd_bytes < 4)) {
@@ -618,6 +644,50 @@ static int mipi_dbi_lcdic_reset(const struct device *dev, k_timeout_t delay)
618644
return 0;
619645
}
620646

647+
static int mipi_dbi_lcdic_configure_te(const struct device *dev,
648+
uint8_t edge,
649+
k_timeout_t delay)
650+
{
651+
const struct mipi_dbi_lcdic_config *config = dev->config;
652+
LCDIC_Type *base = config->base;
653+
struct mipi_dbi_lcdic_data *data = dev->data;
654+
uint32_t lcdic_freq, ttew, reg;
655+
uint32_t delay_us = k_ticks_to_us_ceil32(delay.ticks);
656+
657+
/* Calculate delay based off timer0 ratio. Formula given
658+
* by RM is as follows:
659+
* TE delay = Timer1_Period * ttew
660+
* Timer1_Period = 2^(TIMER_RATIO1) * Timer0_Period
661+
* Timer0_Period = 2^(TIMER_RATIO0) / LCDIC_Clock_Freq
662+
*/
663+
if (clock_control_get_rate(config->clock_dev, config->clock_subsys,
664+
&lcdic_freq)) {
665+
return -EIO;
666+
}
667+
668+
/*
669+
* Calculate TTEW. Done in multiple steps to avoid overflowing
670+
* the uint32_t type. Full formula is:
671+
* (lcdic_freq * delay_us) /
672+
* ((2 ^ (TIMER_RATIO1 + TIMER_RATIO0)) * USEC_PER_SEC)
673+
*/
674+
ttew = lcdic_freq / (1 << config->timer0_ratio);
675+
ttew *= delay_us;
676+
ttew /= (1 << config->timer1_ratio);
677+
ttew /= USEC_PER_SEC;
678+
679+
/* Check to see if the delay is shorter than we can support */
680+
if ((ttew == 0) && (delay_us != 0)) {
681+
LOG_ERR("Timer ratios too large to support this TE delay");
682+
return -ENOTSUP;
683+
}
684+
reg = base->TE_CTRL;
685+
reg &= ~LCDIC_TE_CTRL_TTEW_MASK;
686+
reg |= LCDIC_TE_CTRL_TTEW(ttew);
687+
base->TE_CTRL = reg;
688+
data->te_edge = edge;
689+
return 0;
690+
}
621691

622692

623693
/* Initializes LCDIC peripheral */
@@ -671,6 +741,8 @@ static int mipi_dbi_lcdic_init(const struct device *dev)
671741
base->TIMER_CTRL = LCDIC_TIMER_CTRL_TIMER_RATIO1(config->timer1_ratio) |
672742
LCDIC_TIMER_CTRL_TIMER_RATIO0(config->timer0_ratio);
673743

744+
data->te_edge = MIPI_DBI_TE_NO_EDGE;
745+
674746
#ifdef CONFIG_MIPI_DBI_NXP_LCDIC_DMA
675747
/* Attach the LCDIC DMA request signal to the DMA channel we will
676748
* use with hardware triggering.
@@ -687,6 +759,7 @@ static int mipi_dbi_lcdic_init(const struct device *dev)
687759
static DEVICE_API(mipi_dbi, mipi_dbi_lcdic_driver_api) = {
688760
.command_write = mipi_dbi_lcdic_write_cmd,
689761
.write_display = mipi_dbi_lcdic_write_display,
762+
.configure_te = mipi_dbi_lcdic_configure_te,
690763
.reset = mipi_dbi_lcdic_reset,
691764
};
692765

@@ -718,7 +791,8 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
718791
/* Command done. Queue next command */
719792
data->cmd_bytes = MIN(data->xfer_bytes, LCDIC_MAX_XFER);
720793
mipi_dbi_lcdic_set_cmd(base, LCDIC_TX, LCDIC_DATA,
721-
LCDIC_DATA_FMT_BYTE,
794+
data->pixel_fmt,
795+
LCDIC_TE_NO_SYNC,
722796
data->cmd_bytes);
723797
if (data->cmd_bytes & 0x3) {
724798
/* Save unaligned portion of transfer into

0 commit comments

Comments
 (0)