Skip to content

Commit d628bfc

Browse files
KATE-WANG-NXPkartben
authored andcommitted
drivers: mipi_dsi: dsi_mcux_2l: Use NXP DCNano DBI driver for memory write
There is no smartdma on RT700, so to perform DCS memory write the CPU has to write APB buffer word by word, which is too slow for most applications. But the DCNano in DBI mode can be used to interface with the MIPI-DSI on RT700, and send data to MIPI-DSI to transfer, once it is properly configured, which solves the issue. First added new parameter first_write in display_buffer_descriptor to let NXP DCNano DBI driver know to use MIPI_DCS_WRITE_MEMORY_START or MIPI_DCS_WRITE_MEMORY_CONTINUE. Second updated the MCUX MIPI-DSI driver to support using the NXP DCNano DBI driver for memory write. Signed-off-by: Kate Wang <[email protected]>
1 parent 0017bfc commit d628bfc

File tree

2 files changed

+146
-5
lines changed

2 files changed

+146
-5
lines changed

drivers/mipi_dsi/Kconfig.mcux

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ config MIPI_DSI_MCUX_2L_SMARTDMA
2626
convert RGB565 input data to BGR565 (little endian to big endian),
2727
and write it to the MIPI DSI.
2828

29+
config MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
30+
bool "Use NXP DCNano DBI controller with MIPI DSI"
31+
default y
32+
depends on DT_HAS_NXP_MIPI_DBI_DCNANO_LCDIF_ENABLED
33+
select MIPI_DBI
34+
help
35+
Use DCNano DBI controller for the data transfer.
36+
2937
config MIPI_DSI_MCUX_2L_SWAP16
3038
bool "Swap 16 byte color"
3139
help

drivers/mipi_dsi/dsi_mcux_2l.c

Lines changed: 138 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,18 @@
2222
#include <fsl_inputmux.h>
2323
#include <fsl_smartdma.h>
2424
#endif
25+
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
26+
#include <zephyr/drivers/mipi_dbi.h>
27+
#endif
2528

2629
#include <soc.h>
2730

2831
LOG_MODULE_REGISTER(dsi_mcux_host, CONFIG_MIPI_DSI_LOG_LEVEL);
2932

33+
#if CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
34+
#define MIPI_DSI_MAX_PAYLOAD_SIZE 0xFFFF
35+
#endif
36+
3037
struct mcux_mipi_dsi_config {
3138
MIPI_DSI_HOST_Type *base;
3239
dsi_dpi_config_t dpi_config;
@@ -44,6 +51,9 @@ struct mcux_mipi_dsi_config {
4451
#else
4552
void (*irq_config_func)(const struct device *dev);
4653
#endif
54+
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
55+
const struct device *mipi_dbi;
56+
#endif
4757
};
4858

4959
struct mcux_mipi_dsi_data {
@@ -60,6 +70,11 @@ struct mcux_mipi_dsi_data {
6070
uint32_t smartdma_stack[32];
6171
uint8_t dma_slot;
6272
#endif
73+
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
74+
uint32_t width;
75+
uint32_t height;
76+
uint8_t src_bytes_per_pixel;
77+
#endif
6378
};
6479

6580

@@ -196,7 +211,111 @@ static void dsi_transfer_complete(MIPI_DSI_HOST_Type *base,
196211
k_sem_give(&data->transfer_sem);
197212
}
198213

214+
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
215+
static status_t dsi_mcux_dcnano_transfer(const struct device *dev, uint8_t channel,
216+
struct mipi_dsi_msg *msg, dsi_transfer_t *dsi_xfer)
217+
{
218+
const struct mcux_mipi_dsi_config *config = dev->config;
219+
struct mcux_mipi_dsi_data *data = dev->data;
220+
uint8_t *tx_buf = (uint8_t *)msg->tx_buf;
221+
222+
/* Record the bpp, width, height of the buffer according to command. They are
223+
* necessary to configure the DCNano DBI in the following memory write.
224+
*/
225+
if (channel == 0U) {
226+
if (msg->cmd == MIPI_DCS_SET_PIXEL_FORMAT) {
227+
if (tx_buf[0] == MIPI_DCS_PIXEL_FORMAT_16BIT) {
228+
data->src_bytes_per_pixel = 2U;
229+
} else {
230+
data->src_bytes_per_pixel = 3U;
231+
}
232+
} else if (msg->cmd == MIPI_DCS_SET_COLUMN_ADDRESS) {
233+
data->width = ((tx_buf[2] << 8U) | tx_buf[3]) -
234+
((tx_buf[0] << 8U) | tx_buf[1]) + 1U;
235+
} else if (msg->cmd == MIPI_DCS_SET_PAGE_ADDRESS) {
236+
data->height = ((tx_buf[2] << 8U) | tx_buf[3]) -
237+
((tx_buf[0] << 8U) | tx_buf[1]) + 1U;
238+
}
239+
}
240+
241+
/* When the DSI channel is 0, for and only for DCS long write like
242+
* MIPI_DCS_WRITE_MEMORY_START or MIPI_DCS_WRITE_MEMORY_CONTINUE, we can
243+
* use DCNano DBI to speed up the frame buffer write. The DCS command and the
244+
* following data are all handled by DCNano DBI, while on MIPI-DSI side special
245+
* handling shall be done so that it can be properly used with DCNano DBI,
246+
* like MIPI DBI FIFO configuration of send level and payload size, etc.
247+
*/
248+
if (((msg->cmd == MIPI_DCS_WRITE_MEMORY_START) ||
249+
(msg->cmd == MIPI_DCS_WRITE_MEMORY_CONTINUE)) && (channel == 0U)) {
250+
enum display_pixel_format pixfmt;
251+
struct mipi_dbi_config dbi_config = {
252+
.mode = MIPI_DBI_MODE_8080_BUS_16_BIT,
253+
};
254+
struct display_buffer_descriptor desc = {
255+
.width = data->width,
256+
.height = data->height,
257+
.pitch = data->width,
258+
};
259+
260+
/* Every time buffer 64 pixels first before the transfer. */
261+
DSI_SetDbiPixelFifoSendLevel(config->base, 64U);
262+
263+
/* Set payload size. */
264+
if ((desc.height * desc.width * data->src_bytes_per_pixel) >
265+
MIPI_DSI_MAX_PAYLOAD_SIZE) {
266+
desc.height = MIPI_DSI_MAX_PAYLOAD_SIZE /
267+
(desc.width * data->src_bytes_per_pixel);
268+
}
269+
270+
DSI_SetDbiPixelPayloadSize(config->base,
271+
(desc.height * desc.width * data->src_bytes_per_pixel) >> 1U);
272+
273+
/* Get the source buffer pixel format and DBI output format
274+
* Currently only support RGB565 and RGB888 when using DCNano DBI.
275+
*/
276+
switch (data->src_bytes_per_pixel) {
277+
case 2:
278+
pixfmt = PIXEL_FORMAT_RGB_565;
279+
dbi_config.mode |= MIPI_DBI_MODE_RGB565;
280+
DSI_SetDbiPixelFormat(config->base, kDSI_DbiRGB565);
281+
break;
282+
case 3:
283+
pixfmt = PIXEL_FORMAT_RGB_888;
284+
/* If using the DBI, only RGB888 option 1 is supported. */
285+
dbi_config.mode |= MIPI_DBI_MODE_RGB888_1;
286+
DSI_SetDbiPixelFormat(config->base, kDSI_DbiRGB888);
287+
break;
288+
default:
289+
/* MIPI-DSI do not support other format of DBI pixel. */
290+
LOG_ERR("Pixel type not supported yet.");
291+
return -EIO;
292+
}
293+
294+
/* Send the command first. */
295+
if (msg->cmd == MIPI_DCS_WRITE_MEMORY_START) {
296+
mipi_dbi_command_write(config->mipi_dbi, &dbi_config,
297+
MIPI_DCS_WRITE_MEMORY_START, NULL, 0);
298+
} else {
299+
mipi_dbi_command_write(config->mipi_dbi, &dbi_config,
300+
MIPI_DCS_WRITE_MEMORY_CONTINUE, NULL, 0);
301+
}
302+
303+
/* Send the frame buffer data. */
304+
mipi_dbi_write_display(config->mipi_dbi, &dbi_config, msg->tx_buf,
305+
&desc, pixfmt);
306+
307+
msg->tx_len = desc.height * desc.width * data->src_bytes_per_pixel;
308+
} else {
309+
/* For other DCS commands, the DCNano DBI cannot be used. */
310+
if (DSI_TransferBlocking(config->base, dsi_xfer) != kStatus_Success) {
311+
LOG_ERR("Transmission failed");
312+
return -EIO;
313+
}
314+
}
199315

316+
return 0;
317+
}
318+
#else
200319
/* Helper function to transfer DSI color (Interrupt based implementation) */
201320
static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
202321
struct mipi_dsi_msg *msg)
@@ -246,6 +365,7 @@ static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
246365
}
247366
return xfer.txDataSize;
248367
}
368+
#endif
249369

250370
/* ISR is used for DSI interrupt based implementation, unnecessary if DMA is used */
251371
static int mipi_dsi_isr(const struct device *dev)
@@ -479,11 +599,16 @@ static int dsi_mcux_detach(const struct device *dev, uint8_t channel,
479599
static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
480600
struct mipi_dsi_msg *msg)
481601
{
602+
#if DT_PROP(DT_NODELABEL(mipi_dsi), ulps_control)
603+
struct mcux_mipi_dsi_data *data = dev->data;
604+
#endif
605+
606+
#ifndef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
482607
const struct mcux_mipi_dsi_config *config = dev->config;
608+
#endif
483609

484610
dsi_transfer_t dsi_xfer = {0};
485611
status_t status;
486-
int ret;
487612

488613
dsi_xfer.virtualChannel = channel;
489614
dsi_xfer.txDataSize = msg->tx_len;
@@ -494,8 +619,6 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
494619
dsi_xfer.flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : kDSI_TransferUseHighSpeed;
495620

496621
#if DT_PROP(DT_NODELABEL(mipi_dsi), ulps_control)
497-
struct mcux_mipi_dsi_data *data = dev->data;
498-
499622
data->flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? MIPI_DSI_MSG_USE_LPM : 0U;
500623
if (msg->flags & MCUX_DSI_2L_ULPS) {
501624
data->flags |= MCUX_DSI_2L_ULPS;
@@ -522,6 +645,9 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
522645
dsi_xfer.sendDscCmd = true;
523646
dsi_xfer.dscCmd = msg->cmd;
524647
dsi_xfer.txDataType = kDSI_TxDataDcsLongWr;
648+
#ifndef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
649+
int ret;
650+
525651
if (msg->flags & MCUX_DSI_2L_FB_DATA) {
526652
/*
527653
* Special case- transfer framebuffer data using
@@ -535,6 +661,7 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
535661
}
536662
return ret;
537663
}
664+
#endif
538665
break;
539666
case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
540667
dsi_xfer.txDataType = kDSI_TxDataGenShortWrNoParam;
@@ -560,15 +687,19 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
560687
return -ENOTSUP;
561688
}
562689

690+
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
691+
status = dsi_mcux_dcnano_transfer(dev, channel, msg, &dsi_xfer);
692+
#else
563693
status = DSI_TransferBlocking(config->base, &dsi_xfer);
564-
565-
dsi_mcux_transfer_complete(dev);
694+
#endif
566695

567696
if (status != kStatus_Success) {
568697
LOG_ERR("Transmission failed");
569698
return -EIO;
570699
}
571700

701+
dsi_mcux_transfer_complete(dev);
702+
572703
if (msg->rx_len != 0) {
573704
/* Return rx_len on a read */
574705
return msg->rx_len;
@@ -648,6 +779,8 @@ static int mcux_mipi_dsi_init(const struct device *dev)
648779
COND_CODE_1(CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA, \
649780
(.smart_dma = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(id, smartdma)),), \
650781
(.irq_config_func = mipi_dsi_##n##_irq_config_func,)) \
782+
COND_CODE_1(CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF, \
783+
(.mipi_dbi = DEVICE_DT_GET(DT_NODELABEL(zephyr_lcdif)),), ()) \
651784
.base = (MIPI_DSI_HOST_Type *)DT_INST_REG_ADDR(id), \
652785
.auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp), \
653786
.noncontinuous_hs_clk = DT_INST_PROP(id, noncontinuous_hs_clk), \

0 commit comments

Comments
 (0)