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 <yumeng.wang@nxp.com>
This commit is contained in:
parent
0017bfcedc
commit
d628bfc148
2 changed files with 146 additions and 5 deletions
|
@ -26,6 +26,14 @@ config MIPI_DSI_MCUX_2L_SMARTDMA
|
|||
convert RGB565 input data to BGR565 (little endian to big endian),
|
||||
and write it to the MIPI DSI.
|
||||
|
||||
config MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
|
||||
bool "Use NXP DCNano DBI controller with MIPI DSI"
|
||||
default y
|
||||
depends on DT_HAS_NXP_MIPI_DBI_DCNANO_LCDIF_ENABLED
|
||||
select MIPI_DBI
|
||||
help
|
||||
Use DCNano DBI controller for the data transfer.
|
||||
|
||||
config MIPI_DSI_MCUX_2L_SWAP16
|
||||
bool "Swap 16 byte color"
|
||||
help
|
||||
|
|
|
@ -22,11 +22,18 @@
|
|||
#include <fsl_inputmux.h>
|
||||
#include <fsl_smartdma.h>
|
||||
#endif
|
||||
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
|
||||
#include <zephyr/drivers/mipi_dbi.h>
|
||||
#endif
|
||||
|
||||
#include <soc.h>
|
||||
|
||||
LOG_MODULE_REGISTER(dsi_mcux_host, CONFIG_MIPI_DSI_LOG_LEVEL);
|
||||
|
||||
#if CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
|
||||
#define MIPI_DSI_MAX_PAYLOAD_SIZE 0xFFFF
|
||||
#endif
|
||||
|
||||
struct mcux_mipi_dsi_config {
|
||||
MIPI_DSI_HOST_Type *base;
|
||||
dsi_dpi_config_t dpi_config;
|
||||
|
@ -44,6 +51,9 @@ struct mcux_mipi_dsi_config {
|
|||
#else
|
||||
void (*irq_config_func)(const struct device *dev);
|
||||
#endif
|
||||
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
|
||||
const struct device *mipi_dbi;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mcux_mipi_dsi_data {
|
||||
|
@ -60,6 +70,11 @@ struct mcux_mipi_dsi_data {
|
|||
uint32_t smartdma_stack[32];
|
||||
uint8_t dma_slot;
|
||||
#endif
|
||||
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t src_bytes_per_pixel;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -196,7 +211,111 @@ static void dsi_transfer_complete(MIPI_DSI_HOST_Type *base,
|
|||
k_sem_give(&data->transfer_sem);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
|
||||
static status_t dsi_mcux_dcnano_transfer(const struct device *dev, uint8_t channel,
|
||||
struct mipi_dsi_msg *msg, dsi_transfer_t *dsi_xfer)
|
||||
{
|
||||
const struct mcux_mipi_dsi_config *config = dev->config;
|
||||
struct mcux_mipi_dsi_data *data = dev->data;
|
||||
uint8_t *tx_buf = (uint8_t *)msg->tx_buf;
|
||||
|
||||
/* Record the bpp, width, height of the buffer according to command. They are
|
||||
* necessary to configure the DCNano DBI in the following memory write.
|
||||
*/
|
||||
if (channel == 0U) {
|
||||
if (msg->cmd == MIPI_DCS_SET_PIXEL_FORMAT) {
|
||||
if (tx_buf[0] == MIPI_DCS_PIXEL_FORMAT_16BIT) {
|
||||
data->src_bytes_per_pixel = 2U;
|
||||
} else {
|
||||
data->src_bytes_per_pixel = 3U;
|
||||
}
|
||||
} else if (msg->cmd == MIPI_DCS_SET_COLUMN_ADDRESS) {
|
||||
data->width = ((tx_buf[2] << 8U) | tx_buf[3]) -
|
||||
((tx_buf[0] << 8U) | tx_buf[1]) + 1U;
|
||||
} else if (msg->cmd == MIPI_DCS_SET_PAGE_ADDRESS) {
|
||||
data->height = ((tx_buf[2] << 8U) | tx_buf[3]) -
|
||||
((tx_buf[0] << 8U) | tx_buf[1]) + 1U;
|
||||
}
|
||||
}
|
||||
|
||||
/* When the DSI channel is 0, for and only for DCS long write like
|
||||
* MIPI_DCS_WRITE_MEMORY_START or MIPI_DCS_WRITE_MEMORY_CONTINUE, we can
|
||||
* use DCNano DBI to speed up the frame buffer write. The DCS command and the
|
||||
* following data are all handled by DCNano DBI, while on MIPI-DSI side special
|
||||
* handling shall be done so that it can be properly used with DCNano DBI,
|
||||
* like MIPI DBI FIFO configuration of send level and payload size, etc.
|
||||
*/
|
||||
if (((msg->cmd == MIPI_DCS_WRITE_MEMORY_START) ||
|
||||
(msg->cmd == MIPI_DCS_WRITE_MEMORY_CONTINUE)) && (channel == 0U)) {
|
||||
enum display_pixel_format pixfmt;
|
||||
struct mipi_dbi_config dbi_config = {
|
||||
.mode = MIPI_DBI_MODE_8080_BUS_16_BIT,
|
||||
};
|
||||
struct display_buffer_descriptor desc = {
|
||||
.width = data->width,
|
||||
.height = data->height,
|
||||
.pitch = data->width,
|
||||
};
|
||||
|
||||
/* Every time buffer 64 pixels first before the transfer. */
|
||||
DSI_SetDbiPixelFifoSendLevel(config->base, 64U);
|
||||
|
||||
/* Set payload size. */
|
||||
if ((desc.height * desc.width * data->src_bytes_per_pixel) >
|
||||
MIPI_DSI_MAX_PAYLOAD_SIZE) {
|
||||
desc.height = MIPI_DSI_MAX_PAYLOAD_SIZE /
|
||||
(desc.width * data->src_bytes_per_pixel);
|
||||
}
|
||||
|
||||
DSI_SetDbiPixelPayloadSize(config->base,
|
||||
(desc.height * desc.width * data->src_bytes_per_pixel) >> 1U);
|
||||
|
||||
/* Get the source buffer pixel format and DBI output format
|
||||
* Currently only support RGB565 and RGB888 when using DCNano DBI.
|
||||
*/
|
||||
switch (data->src_bytes_per_pixel) {
|
||||
case 2:
|
||||
pixfmt = PIXEL_FORMAT_RGB_565;
|
||||
dbi_config.mode |= MIPI_DBI_MODE_RGB565;
|
||||
DSI_SetDbiPixelFormat(config->base, kDSI_DbiRGB565);
|
||||
break;
|
||||
case 3:
|
||||
pixfmt = PIXEL_FORMAT_RGB_888;
|
||||
/* If using the DBI, only RGB888 option 1 is supported. */
|
||||
dbi_config.mode |= MIPI_DBI_MODE_RGB888_1;
|
||||
DSI_SetDbiPixelFormat(config->base, kDSI_DbiRGB888);
|
||||
break;
|
||||
default:
|
||||
/* MIPI-DSI do not support other format of DBI pixel. */
|
||||
LOG_ERR("Pixel type not supported yet.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Send the command first. */
|
||||
if (msg->cmd == MIPI_DCS_WRITE_MEMORY_START) {
|
||||
mipi_dbi_command_write(config->mipi_dbi, &dbi_config,
|
||||
MIPI_DCS_WRITE_MEMORY_START, NULL, 0);
|
||||
} else {
|
||||
mipi_dbi_command_write(config->mipi_dbi, &dbi_config,
|
||||
MIPI_DCS_WRITE_MEMORY_CONTINUE, NULL, 0);
|
||||
}
|
||||
|
||||
/* Send the frame buffer data. */
|
||||
mipi_dbi_write_display(config->mipi_dbi, &dbi_config, msg->tx_buf,
|
||||
&desc, pixfmt);
|
||||
|
||||
msg->tx_len = desc.height * desc.width * data->src_bytes_per_pixel;
|
||||
} else {
|
||||
/* For other DCS commands, the DCNano DBI cannot be used. */
|
||||
if (DSI_TransferBlocking(config->base, dsi_xfer) != kStatus_Success) {
|
||||
LOG_ERR("Transmission failed");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
/* Helper function to transfer DSI color (Interrupt based implementation) */
|
||||
static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
|
||||
struct mipi_dsi_msg *msg)
|
||||
|
@ -246,6 +365,7 @@ static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel,
|
|||
}
|
||||
return xfer.txDataSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ISR is used for DSI interrupt based implementation, unnecessary if DMA is used */
|
||||
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,
|
|||
static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
|
||||
struct mipi_dsi_msg *msg)
|
||||
{
|
||||
#if DT_PROP(DT_NODELABEL(mipi_dsi), ulps_control)
|
||||
struct mcux_mipi_dsi_data *data = dev->data;
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
|
||||
const struct mcux_mipi_dsi_config *config = dev->config;
|
||||
#endif
|
||||
|
||||
dsi_transfer_t dsi_xfer = {0};
|
||||
status_t status;
|
||||
int ret;
|
||||
|
||||
dsi_xfer.virtualChannel = channel;
|
||||
dsi_xfer.txDataSize = msg->tx_len;
|
||||
|
@ -494,8 +619,6 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
|
|||
dsi_xfer.flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : kDSI_TransferUseHighSpeed;
|
||||
|
||||
#if DT_PROP(DT_NODELABEL(mipi_dsi), ulps_control)
|
||||
struct mcux_mipi_dsi_data *data = dev->data;
|
||||
|
||||
data->flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? MIPI_DSI_MSG_USE_LPM : 0U;
|
||||
if (msg->flags & MCUX_DSI_2L_ULPS) {
|
||||
data->flags |= MCUX_DSI_2L_ULPS;
|
||||
|
@ -522,6 +645,9 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
|
|||
dsi_xfer.sendDscCmd = true;
|
||||
dsi_xfer.dscCmd = msg->cmd;
|
||||
dsi_xfer.txDataType = kDSI_TxDataDcsLongWr;
|
||||
#ifndef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
|
||||
int ret;
|
||||
|
||||
if (msg->flags & MCUX_DSI_2L_FB_DATA) {
|
||||
/*
|
||||
* Special case- transfer framebuffer data using
|
||||
|
@ -535,6 +661,7 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
|
||||
dsi_xfer.txDataType = kDSI_TxDataGenShortWrNoParam;
|
||||
|
@ -560,15 +687,19 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF
|
||||
status = dsi_mcux_dcnano_transfer(dev, channel, msg, &dsi_xfer);
|
||||
#else
|
||||
status = DSI_TransferBlocking(config->base, &dsi_xfer);
|
||||
|
||||
dsi_mcux_transfer_complete(dev);
|
||||
#endif
|
||||
|
||||
if (status != kStatus_Success) {
|
||||
LOG_ERR("Transmission failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dsi_mcux_transfer_complete(dev);
|
||||
|
||||
if (msg->rx_len != 0) {
|
||||
/* Return rx_len on a read */
|
||||
return msg->rx_len;
|
||||
|
@ -648,6 +779,8 @@ static int mcux_mipi_dsi_init(const struct device *dev)
|
|||
COND_CODE_1(CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA, \
|
||||
(.smart_dma = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(id, smartdma)),), \
|
||||
(.irq_config_func = mipi_dsi_##n##_irq_config_func,)) \
|
||||
COND_CODE_1(CONFIG_MIPI_DSI_MCUX_NXP_DCNANO_LCDIF, \
|
||||
(.mipi_dbi = DEVICE_DT_GET(DT_NODELABEL(zephyr_lcdif)),), ()) \
|
||||
.base = (MIPI_DSI_HOST_Type *)DT_INST_REG_ADDR(id), \
|
||||
.auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp), \
|
||||
.noncontinuous_hs_clk = DT_INST_PROP(id, noncontinuous_hs_clk), \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue