diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index b74c77f30b..1ef80d8f7c 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1952,6 +1952,16 @@ Release Notes: labels: - "area: Memory Management" +"Drivers: MIPI DBI": + status: maintained + maintainers: + - danieldegrasse + files: + - drivers/mipi_dbi/ + - dts/bindings/mipi-dbi/ + labels: + - "area: Display Controller" + "Drivers: Virtualization": status: maintained maintainers: diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 6310146bb3..f0236ef653 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -56,6 +56,7 @@ add_subdirectory_ifdef(CONFIG_MBOX mbox) add_subdirectory_ifdef(CONFIG_MDIO mdio) add_subdirectory_ifdef(CONFIG_MEMC memc) add_subdirectory_ifdef(CONFIG_MFD mfd) +add_subdirectory_ifdef(CONFIG_MIPI_DBI mipi_dbi) add_subdirectory_ifdef(CONFIG_MIPI_DSI mipi_dsi) add_subdirectory_ifdef(CONFIG_MM_DRV mm) add_subdirectory_ifdef(CONFIG_MODEM modem) diff --git a/drivers/Kconfig b/drivers/Kconfig index 45b03e4829..ac07add3c1 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -52,6 +52,7 @@ source "drivers/mbox/Kconfig" source "drivers/mdio/Kconfig" source "drivers/memc/Kconfig" source "drivers/mfd/Kconfig" +source "drivers/mipi_dbi/Kconfig" source "drivers/mipi_dsi/Kconfig" source "drivers/misc/Kconfig" source "drivers/mm/Kconfig" diff --git a/drivers/mipi_dbi/CMakeLists.txt b/drivers/mipi_dbi/CMakeLists.txt new file mode 100644 index 0000000000..3a04db6a9c --- /dev/null +++ b/drivers/mipi_dbi/CMakeLists.txt @@ -0,0 +1,3 @@ +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 diff --git a/drivers/mipi_dbi/Kconfig b/drivers/mipi_dbi/Kconfig new file mode 100644 index 0000000000..cc4e2344c6 --- /dev/null +++ b/drivers/mipi_dbi/Kconfig @@ -0,0 +1,24 @@ +# MIPI DBI controller options + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig MIPI_DBI + bool "MIPI-DBI Host Controller drivers [EXPERIMENTAL]" + select EXPERIMENTAL + help + Add support for MIPI-DBI compliant host controllers + +if MIPI_DBI + +module = MIPI_DBI +module-str = mipi_dbi +source "subsys/logging/Kconfig.template.log_config" + +config MIPI_DBI_INIT_PRIORITY + int "Initialization priority" + default 80 + help + MIPI-DBI Host Controllers initialization priority. + +endif diff --git a/dts/bindings/mipi-dbi/mipi-dbi-controller.yaml b/dts/bindings/mipi-dbi/mipi-dbi-controller.yaml new file mode 100644 index 0000000000..64425b5d91 --- /dev/null +++ b/dts/bindings/mipi-dbi/mipi-dbi-controller.yaml @@ -0,0 +1,20 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for MIPI-DBI controllers + +include: base.yaml + +bus: mipi-dbi + +properties: + clock-frequency: + type: int + description: | + Clock frequency of the SCL signal of the MBI-DBI peripheral, in Hz + "#address-cells": + required: true + const: 1 + "#size-cells": + required: true + const: 0 diff --git a/dts/bindings/mipi-dbi/mipi-dbi-device.yaml b/dts/bindings/mipi-dbi/mipi-dbi-device.yaml new file mode 100644 index 0000000000..a24ce07bb4 --- /dev/null +++ b/dts/bindings/mipi-dbi/mipi-dbi-device.yaml @@ -0,0 +1,13 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 +# +# Common fields for MIPI-DBI devices + +include: [base.yaml, power.yaml] + +on-bus: mipi-dbi + +properties: + mipi-max-frequency: + type: int + description: Maximum clock frequency of device's MIPI interface in Hz diff --git a/dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml b/dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml new file mode 100644 index 0000000000..2b8465a266 --- /dev/null +++ b/dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml @@ -0,0 +1,36 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 +# +# Common fields for MIPI DBI devices using Mode C (SPI) + +include: [mipi-dbi-device.yaml] + +properties: + duplex: + type: int + default: 0 + description: | + SPI Duplex mode, full or half. By default it's always full duplex thus 0 + as this is, by far, the most common mode. + Use the macros not the actual enum value, here is the concordance + list (see dt-bindings/spi/spi.h) + 0 SPI_FULL_DUPLEX + 2048 SPI_HALF_DUPLEX + mipi-cpol: + type: boolean + description: | + SPI clock polarity which indicates the clock idle state. + If it is used, the clock idle state is logic high; otherwise, low. + mipi-cpha: + type: boolean + description: | + SPI clock phase that indicates on which edge data is sampled. + If it is used, data is sampled on the second edge; otherwise, on the first edge. + mipi-hold-cs: + type: boolean + description: | + In some cases, it is necessary for the master to manage SPI chip select + under software control, so that multiple spi transactions can be performed + without releasing it. A typical use case is variable length SPI packets + where the first spi transaction reads the length and the second spi transaction + reads length bytes. diff --git a/include/zephyr/drivers/mipi_dbi.h b/include/zephyr/drivers/mipi_dbi.h new file mode 100644 index 0000000000..4cd69845bf --- /dev/null +++ b/include/zephyr/drivers/mipi_dbi.h @@ -0,0 +1,264 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public APIs for MIPI-DBI drivers + * + * MIPI-DBI defines the following 3 interfaces: + * Type A: Motorola 6800 type parallel bus + * Type B: Intel 8080 type parallel bus + * Type C: SPI Type (1 bit bus) with 3 options: + * 1. 9 write clocks per byte, final bit is command/data selection bit + * 2. Same as above, but 16 write clocks per byte + * 3. 8 write clocks per byte. Command/data selected via GPIO pin + * The current driver interface only supports type C modes 1 and 3 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ + +/** + * @brief MIPI-DBI driver APIs + * @defgroup mipi_dbi_interface MIPI-DBI driver APIs + * @ingroup io_interfaces + * @{ + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * SPI 3 wire (Type C1). Uses 9 write clocks to send a byte of data. + * The bit sent on the 9th clock indicates whether the byte is a + * command or data byte + * + * + * .---. .---. .---. .---. .---. .---. .---. .---. + * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- + * + * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + * DOUT |D/C| D7| D6| D5| D4| D3| D2| D1| D0|D/C| D7| D6| D5| D4|...| + * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' + * | Word 1 | Word n + * + * -. .-- + * CS '-----------------------------------------------------------' + */ +#define MIPI_DBI_MODE_SPI_3WIRE 0x1 +/** + * SPI 4 wire (Type C3). Uses 8 write clocks to send a byte of data. + * an additional C/D pin will be use to indicate whether the byte is a + * command or data byte + * + * .---. .---. .---. .---. .---. .---. .---. .---. + * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- + * + * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + * DOUT | D7| D6| D5| D4| D3| D2| D1| D0| D7| D6| D5| D4| D3| D2| D1| D0| + * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' + * | Word 1 | Word n + * + * -. .-- + * CS '---------------------------------------------------------------' + * + * -.-------------------------------.-------------------------------.- + * CD | D/C | D/C | + * -'-------------------------------'-------------------------------'- + */ +#define MIPI_DBI_MODE_SPI_4WIRE 0x2 + +/** + * @brief initialize a MIPI DBI SPI configuration struct from devicetree + * + * This helper allows drivers to initialize a MIPI DBI SPI configuration + * structure using devicetree. + * @param node_id Devicetree node identifier for the MIPI DBI device whose + * struct spi_config to create an initializer for + * @param operation_ the desired operation field in the struct spi_config + * @param delay_ the desired delay field in the struct spi_config's + * spi_cs_control, if there is one + */ +#define MIPI_DBI_SPI_CONFIG_DT(node_id, operation_, delay_) \ + { \ + .frequency = DT_PROP(node_id, mipi_max_frequency), \ + .operation = (operation_) | \ + DT_PROP(node_id, duplex), \ + COND_CODE_1(DT_PROP(node_id, mipi_cpol), SPI_MODE_CPOL, (0)) | \ + COND_CODE_1(DT_PROP(node_id, mipi_cpha), SPI_MODE_CPHA, (0)) | \ + COND_CODE_1(DT_PROP(node_id, mipi_hold_cs), SPI_HOLD_ON_CS, (0)), \ + .slave = DT_REG_ADDR(node_id), \ + .cs = { \ + .gpio = GPIO_DT_SPEC_GET_BY_IDX_OR(DT_PHANDLE(DT_PARENT(node_id), \ + spi_dev), cs_gpios, \ + DT_REG_ADDR(node_id), \ + {}), \ + .delay = (delay_), \ + }, \ + } + +/** + * @brief MIPI DBI controller configuration + * + * Configuration for MIPI DBI controller write + */ +struct mipi_dbi_config { + /** MIPI DBI mode (SPI 3 wire or 4 wire) */ + uint8_t mode; + /** SPI configuration */ + struct spi_config config; +}; + + +/** MIPI-DBI host driver API */ +__subsystem struct mipi_dbi_driver_api { + int (*command_write)(const struct device *dev, + const struct mipi_dbi_config *config, uint8_t cmd, + const uint8_t *data, size_t len); + int (*command_read)(const struct device *dev, + const struct mipi_dbi_config *config, uint8_t *cmds, + size_t num_cmds, uint8_t *response, size_t len); + int (*write_display)(const struct device *dev, + const struct mipi_dbi_config *config, + const uint8_t *framebuf, + struct display_buffer_descriptor *desc, + enum display_pixel_format pixfmt); + int (*reset)(const struct device *dev, uint32_t delay); +}; + +/** + * @brief Write a command to the display controller + * + * Writes a command, along with an optional data buffer to the display. + * If data buffer and buffer length are NULL and 0 respectively, then + * only a command will be sent. + * + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @param cmd command to write to display controller + * @param data optional data buffer to write after command + * @param len size of data buffer in bytes. Set to 0 to skip sending data. + * @retval 0 command write succeeded + * @retval -EIO I/O error + * @retval -ETIMEDOUT transfer timed out + * @retval -EBUSY controller is busy + * @retval -ENOSYS not implemented + */ +static inline int mipi_dbi_command_write(const struct device *dev, + const struct mipi_dbi_config *config, + uint8_t cmd, const uint8_t *data, + size_t len) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->command_write == NULL) { + return -ENOSYS; + } + return api->command_write(dev, config, cmd, data, len); +} + +/** + * @brief Read a command response from the display controller + * + * Reads a command response from the display controller. + * + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @param cmds array of one byte commands to send to display controller + * @param num_cmd number of commands to write to display controller + * @param response response buffer, filled with display controller response + * @param len size of response buffer in bytes. + * @retval 0 command read succeeded + * @retval -EIO I/O error + * @retval -ETIMEDOUT transfer timed out + * @retval -EBUSY controller is busy + * @retval -ENOSYS not implemented + */ +static inline int mipi_dbi_command_read(const struct device *dev, + const struct mipi_dbi_config *config, + uint8_t *cmds, size_t num_cmd, + uint8_t *response, size_t len) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->command_read == NULL) { + return -ENOSYS; + } + return api->command_read(dev, config, cmds, num_cmd, response, len); +} + +/** + * @brief Write a display buffer to the display controller. + * + * Writes a display buffer to the controller. If the controller requires + * a "Write memory" command before writing display data, this should be + * sent with @ref mipi_dbi_command_write + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @param framebuf: framebuffer to write to display + * @param desc: descriptor of framebuffer to write. Note that the pitch must + * be equal to width. + * @param pixfmt: pixel format of framebuffer data + * @retval 0 buffer write succeeded. + * @retval -EIO I/O error + * @retval -ETIMEDOUT transfer timed out + * @retval -EBUSY controller is busy + * @retval -ENOSYS not implemented + */ +static inline int mipi_dbi_write_display(const struct device *dev, + const struct mipi_dbi_config *config, + const uint8_t *framebuf, + struct display_buffer_descriptor *desc, + enum display_pixel_format pixfmt) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->write_display == NULL) { + return -ENOSYS; + } + return api->write_display(dev, config, framebuf, desc, pixfmt); +} + +/** + * @brief Resets attached display controller + * + * Resets the attached display controller. + * @param dev mipi dbi controller + * @param delay duration to set reset signal for, in milliseconds + * @retval 0 reset succeeded + * @retval -EIO I/O error + * @retval -ENOSYS not implemented + * @retval -ENOTSUP not supported + */ +static inline int mipi_dbi_reset(const struct device *dev, uint32_t delay) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->reset == NULL) { + return -ENOSYS; + } + return api->reset(dev, delay); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ */