drivers: mipi_dbi: smartbond: Add support for MIPI DBI driver class.

Add support for the MIPI DBI host controller.

Signed-off-by: Ioannis Karachalios <ioannis.karachalios.px@renesas.com>
This commit is contained in:
Ioannis Karachalios 2023-11-23 13:01:59 +02:00 committed by Fabio Baltieri
commit f011ad5bb1
5 changed files with 690 additions and 0 deletions

View file

@ -3,3 +3,5 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_sources_ifdef(CONFIG_MIPI_DBI_SPI mipi_dbi_spi.c)
zephyr_sources_ifdef(CONFIG_MIPI_DBI_SMARTBOND mipi_dbi_smartbond.c)

View file

@ -23,4 +23,6 @@ config MIPI_DBI_INIT_PRIORITY
source "drivers/mipi_dbi/Kconfig.spi"
source "drivers/mipi_dbi/Kconfig.smartbond"
endif

View file

@ -0,0 +1,12 @@
# Smartbond MIPI DBI host configuration options
# Copyright (c) 2023 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0
config MIPI_DBI_SMARTBOND
bool "Smartbond MIPI DBI host controller driver"
depends on DT_HAS_RENESAS_SMARTBOND_MIPI_DBI_ENABLED
default y
select SPI
help
Enable Smartbond MIPI DBI host controller.

View file

@ -0,0 +1,620 @@
/*
* Copyright (c) 2023 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT renesas_smartbond_mipi_dbi
#include <zephyr/drivers/mipi_dbi.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/irq.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <DA1469xAB.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/smartbond_clock_control.h>
#include <zephyr/drivers/display.h>
#include <zephyr/sys/util.h>
#include <zephyr/drivers/spi.h>
#include <da1469x_lcdc.h>
#include <da1469x_pd.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(smartbond_mipi_dbi, CONFIG_MIPI_DBI_LOG_LEVEL);
#define SMARTBOND_IRQN DT_INST_IRQN(0)
#define SMARTBOND_IRQ_PRIO DT_INST_IRQ(0, priority)
#define PINCTRL_STATE_READ PINCTRL_STATE_PRIV_START
#define MIPI_DBI_SMARTBOND_IS_READ_SUPPORTED \
DT_INST_NODE_HAS_PROP(0, spi_dev)
#define LCDC_SMARTBOND_CLK_DIV(_freq) \
((32000000U % (_freq)) ? (96000000U / (_freq)) : (32000000U / (_freq)))
#define MIPI_DBI_SMARTBOND_IS_PLL_REQUIRED \
!!(32000000U % DT_PROP(DT_CHOSEN(zephyr_display), mipi_max_frequency))
#define MIPI_DBI_SMARTBOND_IS_TE_ENABLED \
DT_INST_PROP_OR(0, te_enable, 0)
#define MIPI_DBI_SMARTBOND_IS_DMA_PREFETCH_ENABLED \
DT_INST_ENUM_IDX_OR(0, dma_prefetch, 0)
#define MIPI_DBI_SMARTBOND_IS_RESET_AVAILABLE \
DT_INST_NODE_HAS_PROP(0, reset_gpios)
#define LCDC_LAYER0_OFFSETX_REG_SET_FIELD(_field, _var, _val) \
((_var)) = \
((_var) & ~(LCDC_LCDC_LAYER0_OFFSETX_REG_ ## _field ## _Msk)) | \
(((_var) << LCDC_LCDC_LAYER0_OFFSETX_REG_ ## _field ## _Pos) & \
LCDC_LCDC_LAYER0_OFFSETX_REG_ ## _field ## _Msk)
struct mipi_dbi_smartbond_data {
/* Provide mutual exclusion when a display operation is requested. */
struct k_sem device_sem;
/* Provide synchronization between task return and ISR firing */
struct k_sem sync_sem;
/* Flag indicating whether or not an underflow took place */
volatile bool underflow_flag;
/* Layer settings */
lcdc_smartbond_layer_cfg layer;
};
struct mipi_dbi_smartbond_config {
/* Reference to device instance's pinctrl configurations */
const struct pinctrl_dev_config *pcfg;
/* Reset GPIO */
const struct gpio_dt_spec reset;
/* Host controller's timing settings */
lcdc_smartbond_timing_cfg timing_cfg;
/* Background default color configuration */
lcdc_smartbond_bgcolor_cfg bgcolor_cfg;
};
/* Mark the device is is progress and so it's not allowed to enter the sleep state. */
static void mipi_dbi_pm_get(const struct device *dev)
{
#if CONFIG_PM_DEVICE
/*
* By marking the device as busy, PM will not communicate PM events
* to the device via mipi_dbi_smartbond_pm_action. It's OK if PM is
* not used at all. Executing a single frame requires waiting for
* the frame to be completed. As such, the system might enter the idle
* state if no other tasks are pending and for as long as the frame is
* being sent.
*
* XXX: Another option would be to use a flag and mark when the controller
* is in progress so a negative value other than -ENOSYS, -ENOTSUP or
* -EALREADY is returned in mipi_dbi_smartbond_pm_action. Sideffect
* of this approach is that the sleep state will be aborted at all,
* though the system could enter a low-power state, instead (see comment
* below on how to achieve a low-power state).
*/
pm_device_busy_set(dev);
#endif
#if CONFIG_PM
/*
* LCDC controller resides in PD_SYS which is turned off when the system enters
* the extended sleep state. By calling this API, a reference counter is
* incremented, designating that the specific power domain should not be turned off.
* As a result, a low-power state (i.e. ARM WFI) will be selected, instead (when the
* system is idle).
*/
(void)da1469x_pd_acquire_noconf(MCU_PD_DOMAIN_SYS);
#endif
}
/* Mark that device is inactive and so it's allowed to enter the sleep state */
static void mipi_dbi_pm_put(const struct device *dev)
{
#if CONFIG_PM_DEVICE
(void)pm_device_busy_clear(dev);
#endif
#if CONFIG_PM
(void)da1469x_pd_release_nowait(MCU_PD_DOMAIN_SYS);
#endif
}
/* Helper function to trigger the LCDC fetching data from frame buffer to the connected display */
static void mipi_dbi_smartbond_send_single_frame(const struct device *dev)
{
struct mipi_dbi_smartbond_data *data = dev->data;
#if MIPI_DBI_SMARTBOND_IS_TE_ENABLED
da1469x_lcdc_te_set_status(true, DT_INST_PROP_OR(0, te_polarity, false));
/*
* Wait for the TE signal to be asserted so display's refresh status can be synchronized
* with the current frame update.
*/
k_sem_take(&data->sync_sem, K_FOREVER);
#endif
LCDC->LCDC_INTERRUPT_REG |= LCDC_LCDC_INTERRUPT_REG_LCDC_VSYNC_IRQ_EN_Msk;
/* Setting this bit will enable the host to start outputing pixel data */
LCDC->LCDC_MODE_REG |= LCDC_LCDC_MODE_REG_LCDC_SFRAME_UPD_Msk;
/* Wait for frame update to complete */
k_sem_take(&data->sync_sem, K_FOREVER);
if (data->underflow_flag) {
LOG_WRN("Underflow took place");
data->underflow_flag = false;
}
}
#if MIPI_DBI_SMARTBOND_IS_RESET_AVAILABLE
static int mipi_dbi_smartbond_reset(const struct device *dev, uint32_t delay)
{
const struct mipi_dbi_smartbond_config *config = dev->config;
int ret;
if (!gpio_is_ready_dt(&config->reset)) {
LOG_ERR("Reset signal not available");
return -ENODEV;
}
ret = gpio_pin_set_dt(&config->reset, 1);
if (ret < 0) {
LOG_ERR("Cannot drive reset signal");
return ret;
}
k_msleep(delay);
return gpio_pin_set_dt(&config->reset, 0);
}
#endif
/* Display pixel to output color format translation */
static inline uint8_t lcdc_smartbond_pixel_to_ocm(enum display_pixel_format pixfmt)
{
switch (pixfmt) {
case PIXEL_FORMAT_RGB_565:
return (uint8_t)LCDC_SMARTBOND_OCM_RGB565;
case PIXEL_FORMAT_RGB_888:
return (uint8_t)LCDC_SMARTBOND_OCM_RGB888;
case PIXEL_FORMAT_MONO10:
return (uint8_t)LCDC_SMARTBOND_L0_L1;
default:
LOG_ERR("Unsupported pixel format");
return 0;
};
}
static inline uint8_t lcdc_smartbond_line_mode_translation(uint8_t mode)
{
switch (mode) {
case MIPI_DBI_MODE_SPI_3WIRE:
return (uint8_t)LCDC_SMARTBOND_MODE_SPI3;
case MIPI_DBI_MODE_SPI_4WIRE:
return (uint8_t)LCDC_SMARTBOND_MODE_SPI4;
default:
LOG_ERR("Unsupported SPI mode");
return 0;
}
}
static inline uint8_t lcdc_smartbond_pixel_to_lcm(enum display_pixel_format pixfmt)
{
switch (pixfmt) {
case PIXEL_FORMAT_RGB_565:
return (uint8_t)LCDC_SMARTBOND_L0_RGB565;
case PIXEL_FORMAT_ARGB_8888:
return (uint8_t)LCDC_SMARTBOND_L0_ARGB8888;
default:
LOG_ERR("Unsupported pixel format");
return 0;
};
}
static void lcdc_smartbond_mipi_dbi_translation(const struct mipi_dbi_config *dbi_config,
lcdc_smartbond_mipi_dbi_cfg *mipi_dbi_cfg,
enum display_pixel_format pixfmt)
{
mipi_dbi_cfg->cpha = dbi_config->config.operation & SPI_MODE_CPHA;
mipi_dbi_cfg->cpol = dbi_config->config.operation & SPI_MODE_CPOL;
mipi_dbi_cfg->cs_active_high = dbi_config->config.operation & SPI_CS_ACTIVE_HIGH;
mipi_dbi_cfg->line_mode = lcdc_smartbond_line_mode_translation(dbi_config->mode);
mipi_dbi_cfg->color_mode = lcdc_smartbond_pixel_to_ocm(pixfmt);
}
#if MIPI_DBI_SMARTBOND_IS_READ_SUPPORTED
static int mipi_dbi_smartbond_command_read(const struct device *dev,
const struct mipi_dbi_config *dbi_config,
uint8_t *cmd, size_t num_cmds,
uint8_t *response, size_t len)
{
struct mipi_dbi_smartbond_data *data = dev->data;
const struct mipi_dbi_smartbond_config *config = dev->config;
int ret = 0;
lcdc_smartbond_mipi_dbi_cfg mipi_dbi_cfg;
k_sem_take(&data->device_sem, K_FOREVER);
/*
* Add an arbitrary valid color format to satisfy subroutine. The MIPI DBI command/data
* engine should not be affected.
*/
lcdc_smartbond_mipi_dbi_translation(dbi_config, &mipi_dbi_cfg, PIXEL_FORMAT_RGB_565);
ret = da1469x_lcdc_mipi_dbi_interface_configure(&mipi_dbi_cfg);
if (ret < 0) {
goto _mipi_dbi_read_exit;
}
/* Check if the cmd/data engine is busy since the #CS line will be overruled. */
if (da1469x_lcdc_is_busy()) {
LOG_WRN("MIPI DBI host is busy");
ret = -EBUSY;
goto _mipi_dbi_read_exit;
}
/* Force CS line to low. Typically, command and data are bound in the same #CS assertion */
da1469x_lcdc_force_cs_line(true, mipi_dbi_cfg.cs_active_high);
da1469x_lcdc_send_cmd_data(true, cmd, num_cmds);
if (len) {
const struct device *spi_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, spi_dev));
struct spi_buf buffer = {
.buf = (void *)response,
.len = len,
};
struct spi_buf_set buf_set = {
.buffers = &buffer,
.count = 1,
};
if (!device_is_ready(spi_dev)) {
LOG_ERR("SPI device is not ready");
ret = -ENODEV;
goto _mipi_dbi_read_exit;
}
/* Overwrite CLK and enable DI lines. CS is driven forcefully. */
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_READ);
if (ret < 0) {
LOG_ERR("Could not apply MIPI DBI pins' SPI read state (%d)", ret);
goto _mipi_dbi_read_exit;
}
/* Get response */
ret = spi_read(spi_dev, &dbi_config->config, &buf_set);
if (ret < 0) {
LOG_ERR("Could not read data from SPI");
goto _mipi_dbi_read_exit;
}
}
_mipi_dbi_read_exit:
/* Restore #CS line */
da1469x_lcdc_force_cs_line(false, mipi_dbi_cfg.cs_active_high);
/* Make sure default LCDC pins are applied upon exit */
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret < 0) {
LOG_ERR("Could not apply MIPI DBI pins' default state (%d)", ret);
}
k_sem_give(&data->device_sem);
return ret;
}
#endif
static int mipi_dbi_smartbond_command_write(const struct device *dev,
const struct mipi_dbi_config *dbi_config,
uint8_t cmd, const uint8_t *data_buf,
size_t len)
{
struct mipi_dbi_smartbond_data *data = dev->data;
int ret;
lcdc_smartbond_mipi_dbi_cfg mipi_dbi_cfg;
k_sem_take(&data->device_sem, K_FOREVER);
mipi_dbi_pm_get(dev);
/*
* Add an arbitrary valid color format to satisfy subroutine. The MIPI DBI command/data
* engine should not be affected.
*/
lcdc_smartbond_mipi_dbi_translation(dbi_config, &mipi_dbi_cfg, PIXEL_FORMAT_RGB_565);
ret = da1469x_lcdc_mipi_dbi_interface_configure(&mipi_dbi_cfg);
if (ret < 0) {
k_sem_give(&data->device_sem);
return ret;
}
/* Command and accompanied data should be transmitted via the DBIB interface */
da1469x_lcdc_send_cmd_data(true, &cmd, 1);
if (len) {
/* Data should be transmitted via the DBIB interface */
da1469x_lcdc_send_cmd_data(false, data_buf, len);
}
mipi_dbi_pm_put(dev);
k_sem_give(&data->device_sem);
return 0;
}
static int mipi_dbi_smartbond_write_display(const struct device *dev,
const struct mipi_dbi_config *dbi_config,
const uint8_t *framebuf,
struct display_buffer_descriptor *desc,
enum display_pixel_format pixfmt)
{
struct mipi_dbi_smartbond_data *data = dev->data;
const struct mipi_dbi_smartbond_config *config = dev->config;
lcdc_smartbond_layer_cfg *layer = &data->layer;
int ret = 0;
lcdc_smartbond_mipi_dbi_cfg mipi_dbi_cfg;
uint8_t layer_color = lcdc_smartbond_pixel_to_lcm(pixfmt);
if (desc->width * desc->height * (DISPLAY_BITS_PER_PIXEL(pixfmt) / 8) !=
desc->buf_size) {
LOG_ERR("Incorrect buffer size for given width and height");
return -EINVAL;
}
k_sem_take(&data->device_sem, K_FOREVER);
mipi_dbi_pm_get(dev);
/*
* Mainly check if the frame generator is busy with a pending frame update (might happen
* when two frame updates take place one after the other and the display interface is
* quite slow). VSYNC interrupt line should be asserted when the last line is being
* outputed.
*/
if (da1469x_lcdc_is_busy()) {
LOG_WRN("MIPI DBI host is busy");
ret = -EBUSY;
goto _mipi_dbi_write_exit;
}
lcdc_smartbond_mipi_dbi_translation(dbi_config, &mipi_dbi_cfg, pixfmt);
ret = da1469x_lcdc_mipi_dbi_interface_configure(&mipi_dbi_cfg);
if (ret < 0) {
goto _mipi_dbi_write_exit;
}
ret = da1469x_lcdc_timings_configure(desc->width, desc->height,
(lcdc_smartbond_timing_cfg *)&config->timing_cfg);
if (ret < 0) {
goto _mipi_dbi_write_exit;
}
LCDC_SMARTBOND_LAYER_CONFIG(layer, framebuf, 0, 0, desc->width, desc->height,
layer_color,
da1469x_lcdc_stride_calculation(layer_color, desc->width));
ret = da1469x_lcdc_layer_configure(layer);
if (ret < 0) {
goto _mipi_dbi_write_exit;
}
/* Trigger single frame update via the LCDC-DMA engine */
mipi_dbi_smartbond_send_single_frame(dev);
_mipi_dbi_write_exit:
mipi_dbi_pm_put(dev);
k_sem_give(&data->device_sem);
return ret;
}
static int mipi_dbi_smartbond_configure(const struct device *dev)
{
uint8_t clk_div =
LCDC_SMARTBOND_CLK_DIV(DT_PROP(DT_CHOSEN(zephyr_display), mipi_max_frequency));
const struct mipi_dbi_smartbond_config *config = dev->config;
/*
* First enable the controller so registers can be written. In serial interfaces
* clock divider is further divided by 2.
*/
da1469x_lcdc_set_status(true, MIPI_DBI_SMARTBOND_IS_PLL_REQUIRED,
(clk_div >= 2 ? clk_div / 2 : clk_div));
if (!da1469x_lcdc_check_id()) {
LOG_ERR("Mismatching LCDC ID");
da1469x_lcdc_set_status(false, 0, 0);
return -EINVAL;
}
da1469x_lcdc_te_set_status(false, DT_INST_PROP_OR(0, te_polarity, false));
da1469x_lcdc_bgcolor_configure((lcdc_smartbond_bgcolor_cfg *)&config->bgcolor_cfg);
LCDC_LAYER0_OFFSETX_REG_SET_FIELD(LCDC_L0_DMA_PREFETCH,
LCDC->LCDC_LAYER0_OFFSETX_REG, MIPI_DBI_SMARTBOND_IS_DMA_PREFETCH_ENABLED);
return 0;
}
static void smartbond_mipi_dbi_isr(const void *arg)
{
struct mipi_dbi_smartbond_data *data = ((const struct device *)arg)->data;
/*
* Underflow sticky bit will remain high until cleared by writing
* any value to LCDC_INTERRUPT_REG.
*/
data->underflow_flag = LCDC_STATUS_REG_GET_FIELD(LCDC_STICKY_UNDERFLOW);
/* Default interrupt mode is level triggering so interrupt should be cleared */
da1469x_lcdc_te_set_status(false, DT_INST_PROP_OR(0, te_polarity, false));
k_sem_give(&data->sync_sem);
}
static int mipi_dbi_smartbond_resume(const struct device *dev)
{
const struct mipi_dbi_smartbond_config *config = dev->config;
int ret;
/* Select default state */
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret < 0) {
LOG_ERR("Could not apply LCDC pins' default state (%d)", ret);
return -EIO;
}
#if MIPI_DBI_SMARTBOND_IS_PLL_REQUIRED
const struct device *clock_dev = DEVICE_DT_GET(DT_NODELABEL(osc));
if (!device_is_ready(clock_dev)) {
LOG_WRN("Clock device is not available; PLL cannot be used");
} else {
ret = z_smartbond_select_sys_clk(SMARTBOND_CLK_PLL96M);
if (ret < 0) {
LOG_WRN("Could not switch to PLL. Requested speed should not be achieved.");
}
}
#endif
return mipi_dbi_smartbond_configure(dev);
}
#ifdef CONFIG_PM_DEVICE
static int mipi_dbi_smartbond_suspend(const struct device *dev)
{
const struct mipi_dbi_smartbond_config *config = dev->config;
int ret;
/* Select sleep state; it's OK if settings fails for any reason. */
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
if (ret < 0) {
LOG_WRN("Could not apply MIPI DBI pins' sleep state");
}
/* Disable host controller to minimize power consumption. */
da1469x_lcdc_set_status(false, false, 0);
return 0;
}
static int mipi_dbi_smartbond_pm_action(const struct device *dev, enum pm_device_action action)
{
int ret = 0;
switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
(void)mipi_dbi_smartbond_suspend(dev);
#if CONFIG_PM_DEVICE_RUNTIME && CONFIG_PM
da1469x_pd_release_nowait(MCU_PD_DOMAIN_SYS);
#endif
break;
case PM_DEVICE_ACTION_RESUME:
ret = mipi_dbi_smartbond_resume(dev);
#if CONFIG_PM_DEVICE_RUNTIME && CONFIG_PM
/*
* If resume succeeded, prevent the system from entering the
* extended sleep state (Instead, use __WFI). If not, do not
* as users should not suspend the device and thus releasing
* PD_SYS.
*/
if (ret == 0) {
da1469x_pd_acquire_noconf(MCU_PD_DOMAIN_SYS);
}
#endif
break;
default:
return -ENOTSUP;
}
return ret;
}
#endif
static int mipi_dbi_smartbond_init(const struct device *dev)
{
const struct mipi_dbi_smartbond_config *config = dev->config;
struct mipi_dbi_smartbond_data *data = dev->data;
int ret;
/* Device should be ready to be acquired */
k_sem_init(&data->device_sem, 1, 1);
/* Event should be signaled by LCDC ISR */
k_sem_init(&data->sync_sem, 0, 1);
#if MIPI_DBI_SMARTBOND_IS_RESET_AVAILABLE
if (gpio_is_ready_dt(&config->reset)) {
ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Could not configure reset line (%d)", ret);
return -EIO;
}
}
#endif
IRQ_CONNECT(SMARTBOND_IRQN, SMARTBOND_IRQ_PRIO, smartbond_mipi_dbi_isr,
DEVICE_DT_INST_GET(0), 0);
#ifdef CONFIG_PM_DEVICE_RUNTIME
/* Make sure device state is marked as suspended */
pm_device_init_suspended(dev);
ret = pm_device_runtime_enable(dev);
if ((ret < 0) && (ret != -ENOSYS)) {
return ret;
}
#else
/* Resme if either PM is not used at all or if PM without runtime is used. */
ret = mipi_dbi_smartbond_resume(dev);
if (ret < 0) {
return ret;
}
#endif
return 0;
}
static struct mipi_dbi_driver_api mipi_dbi_smartbond_driver_api = {
#if MIPI_DBI_SMARTBOND_IS_RESET_AVAILABLE
.reset = mipi_dbi_smartbond_reset,
#endif
.command_write = mipi_dbi_smartbond_command_write,
.write_display = mipi_dbi_smartbond_write_display,
#if MIPI_DBI_SMARTBOND_IS_READ_SUPPORTED
.command_read = mipi_dbi_smartbond_command_read,
#endif
};
#define SMARTBOND_MIPI_DBI_INIT(inst) \
PINCTRL_DT_INST_DEFINE(inst); \
\
static const struct mipi_dbi_smartbond_config mipi_dbi_smartbond_config_## inst = { \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
.reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}), \
.timing_cfg = { 0 }, \
.bgcolor_cfg = { 0xFF, 0xFF, 0xFF, 0 }, \
}; \
\
static struct mipi_dbi_smartbond_data mipi_dbi_smartbond_data_## inst; \
\
PM_DEVICE_DT_INST_DEFINE(inst, mipi_dbi_smartbond_pm_action); \
\
DEVICE_DT_INST_DEFINE(inst, mipi_dbi_smartbond_init, \
PM_DEVICE_DT_INST_GET(inst), \
&mipi_dbi_smartbond_data_## inst, \
&mipi_dbi_smartbond_config_## inst, \
POST_KERNEL, \
CONFIG_MIPI_DBI_INIT_PRIORITY, \
&mipi_dbi_smartbond_driver_api);
SMARTBOND_MIPI_DBI_INIT(0);

View file

@ -0,0 +1,54 @@
# Copyright (c) 2023 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0
include: [mipi-dbi-controller.yaml, pinctrl-device.yaml]
description: Renesas Smartbond(tm) MIPI DBI Host
compatible: "renesas,smartbond-mipi-dbi"
properties:
reg:
required: true
interrupts:
required: true
reset-gpios:
type: phandle-array
description: |
Reset GPIO pin. Used to reset the display during initialization.
te-enable:
type: boolean
description: |
Boolean to indicate whether the tearing effect (TE) signal is available or not.
te-inversion:
type: boolean
description: |
Boolean to apply an inversion on the TE signal that triggers the MIPI DBI controller.
dma-prefetch:
type: string
enum:
- "no-prefetch"
- "prefetch-44-bytes"
- "prefetch-84-bytes"
- "prefetch-116-bytes"
- "prefetch-108-bytes"
description: |
Host controller will wait for at least the specified number of bytes before triggering
a single frame update. The prefetch mechanism should be enabled when frame buffer(s)
is stored into external storage mediums, e.g. PSRAM, that introduce comparable delays.
In such a case it might case that the controller runs into underrun conditions which
results in correpting the whole frame update. It's user's responsibility to ensure that
the selected value does not exceed frame's total size as otherwise the controller will
not be able to trigger the frame update.
spi-dev:
type: phandle
description: |
SPI bus to use for display read operations. When this property is present, MIPI DBI read
operations will be exhibited by the driver. This is because, the LCDC IP block does not
support read functionality, natively.