From 320978d73a54fe7d1bf6e890e76d72682138f016 Mon Sep 17 00:00:00 2001 From: Ruoshan Shi Date: Mon, 14 Jul 2025 20:08:30 +0900 Subject: [PATCH 1/4] drivers: mipi dsi: Add dsi dwc driver support Added mipi dsi dwc driver support Signed-off-by: Ruoshan Shi --- drivers/mipi_dsi/CMakeLists.txt | 1 + drivers/mipi_dsi/Kconfig.mcux | 7 + drivers/mipi_dsi/dsi_dwc.c | 202 ++++++++++++++++++ dts/bindings/mipi-dsi/nxp,mipi-dsi-dwc.yaml | 54 +++++ .../mcux/mcux-sdk-ng/drivers/drivers.cmake | 1 + 5 files changed, 265 insertions(+) create mode 100644 drivers/mipi_dsi/dsi_dwc.c create mode 100644 dts/bindings/mipi-dsi/nxp,mipi-dsi-dwc.yaml diff --git a/drivers/mipi_dsi/CMakeLists.txt b/drivers/mipi_dsi/CMakeLists.txt index eb28fb952c08a..e9de65f376d45 100644 --- a/drivers/mipi_dsi/CMakeLists.txt +++ b/drivers/mipi_dsi/CMakeLists.txt @@ -1,6 +1,7 @@ zephyr_sources_ifdef(CONFIG_MIPI_DSI mipi_dsi.c) zephyr_sources_ifdef(CONFIG_MIPI_DSI_MCUX dsi_mcux.c) zephyr_sources_ifdef(CONFIG_MIPI_DSI_MCUX_2L dsi_mcux_2l.c) +zephyr_sources_ifdef(CONFIG_MIPI_DSI_DWC dsi_dwc.c) zephyr_sources_ifdef(CONFIG_MIPI_DSI_STM32 dsi_stm32.c) zephyr_sources_ifdef(CONFIG_MIPI_DSI_TEST dsi_test.c) zephyr_sources_ifdef(CONFIG_MIPI_DSI_RENESAS_RA dsi_renesas_ra.c) diff --git a/drivers/mipi_dsi/Kconfig.mcux b/drivers/mipi_dsi/Kconfig.mcux index af624e6ac108a..013bb2b5d125a 100644 --- a/drivers/mipi_dsi/Kconfig.mcux +++ b/drivers/mipi_dsi/Kconfig.mcux @@ -43,3 +43,10 @@ config MIPI_DSI_MCUX_2L_SWAP16 endif # MIPI_DSI_MCUX_2L + +config MIPI_DSI_DWC + bool "NXP DWC MIPI-DSI Host Controller" + default y + depends on DT_HAS_NXP_MIPI_DSI_DWC_ENABLED + help + NXP MIPI DSI DWC controller driver diff --git a/drivers/mipi_dsi/dsi_dwc.c b/drivers/mipi_dsi/dsi_dwc.c new file mode 100644 index 0000000000000..112862eeab946 --- /dev/null +++ b/drivers/mipi_dsi/dsi_dwc.c @@ -0,0 +1,202 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_mipi_dsi_dwc + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(dsi_dwc, CONFIG_MIPI_DSI_LOG_LEVEL); + +struct dwc_mipi_dsi_config { + MIPI_DSI_Type *base; + dsi_dpi_config_t dpi_config; + bool noncontinuous_hs_clk; + dsi_config_t dsi_config; + uint32_t dphy_ref_frequency; + uint32_t data_rate_clock; + const struct device *dev; +}; + +struct dwc_mipi_dsi_data { + uint16_t flags; + uint8_t lane_mask; +}; + +static int dsi_dwc_attach(const struct device *dev, uint8_t channel, + const struct mipi_dsi_device *mdev) +{ + const struct dwc_mipi_dsi_config *config = dev->config; + dsi_dphy_config_t dphy_config; + dsi_config_t dsi_config; + uint32_t phy_hsfreqrange; + + DSI_GetDefaultConfig(&dsi_config); + dphy_config.numLanes = mdev->data_lanes; + dsi_config.enableNoncontinuousClk = config->noncontinuous_hs_clk; + + /* Init the DSI module. */ + DSI_Init(config->base, &dsi_config); + + DSI_SetDpiConfig(config->base, &config->dpi_config, mdev->data_lanes); + + /* Calculate data rate per line */ + DSI_GetDefaultDphyConfig(&dphy_config, config->data_rate_clock * mdev->data_lanes / 8, + mdev->data_lanes); + DSI_InitDphy(config->base, &dphy_config); + phy_hsfreqrange = Pll_Set_Hs_Freqrange(config->data_rate_clock); +#if CONFIG_SOC_MIMX9596_M7 + CAMERA__DSI_OR_CSI_PHY_CSR->COMBO_PHY_FREQ_CONTROL = + CAMERA_DSI_OR_CSI_PHY_CSR_COMBO_PHY_FREQ_CONTROL_Phy_hsfreqrange(phy_hsfreqrange) | + CAMERA_DSI_OR_CSI_PHY_CSR_COMBO_PHY_FREQ_CONTROL_Phy_cfgclkfreqrange(0x1CU); + CAMERA__DSI_MASTER_CSR->DSI_PIXEL_LINK_CONTROL = + CAMERA_DSI_MASTER_CSR_DSI_PIXEL_LINK_CONTROL_Pixel_link_sel(0x0); + DISPLAY__BLK_CTRL_DISPLAYMIX->PIXEL_LINK_CTRL = + (DISPLAY_BLK_CTRL_DISPLAYMIX_PIXEL_LINK_CTRL_PL0_enable(0x1) | + DISPLAY_BLK_CTRL_DISPLAYMIX_PIXEL_LINK_CTRL_PL0_valid(0x1)); + CAMERA__DSI_OR_CSI_PHY_CSR->COMBO_PHY_MODE_CONTROL = 0x3U; +#endif + DSI_ConfigDphy(config->base, config->dphy_ref_frequency, config->data_rate_clock); + status_t result = DSI_PowerUp(config->base); + + if (result != 0U) { + LOG_ERR("DSI PHY init failed.\r\n"); + } + + return 0; +} + +static ssize_t dsi_dwc_transfer(const struct device *dev, uint8_t channel, struct mipi_dsi_msg *msg) +{ + const struct dwc_mipi_dsi_config *config = dev->config; + dsi_transfer_t dsi_xfer = {0}; + status_t status; + + dsi_xfer.virtualChannel = channel; + dsi_xfer.txDataSize = msg->tx_len; + dsi_xfer.txData = msg->tx_buf; + dsi_xfer.rxDataSize = msg->rx_len; + dsi_xfer.rxData = msg->rx_buf; + switch (msg->type) { + case MIPI_DSI_DCS_READ: + LOG_ERR("DCS Read not yet implemented or used"); + return -ENOTSUP; + case MIPI_DSI_DCS_SHORT_WRITE: + dsi_xfer.sendDscCmd = true; + dsi_xfer.dscCmd = msg->cmd; + dsi_xfer.txDataType = kDSI_TxDataDcsShortWrNoParam; + break; + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + dsi_xfer.sendDscCmd = true; + dsi_xfer.dscCmd = msg->cmd; + dsi_xfer.txDataType = kDSI_TxDataDcsShortWrOneParam; + break; + + case MIPI_DSI_DCS_LONG_WRITE: + dsi_xfer.sendDscCmd = true; + dsi_xfer.dscCmd = msg->cmd; + dsi_xfer.txDataType = kDSI_TxDataDcsLongWr; + break; + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + dsi_xfer.txDataType = kDSI_TxDataGenShortWrNoParam; + break; + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + dsi_xfer.txDataType = kDSI_TxDataGenShortWrOneParam; + break; + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + dsi_xfer.txDataType = kDSI_TxDataGenShortWrTwoParam; + break; + case MIPI_DSI_GENERIC_LONG_WRITE: + dsi_xfer.txDataType = kDSI_TxDataGenLongWr; + break; + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + __fallthrough; + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + __fallthrough; + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + LOG_ERR("Generic Read not yet implemented or used"); + return -ENOTSUP; + default: + LOG_ERR("Unsupported message type (%d)", msg->type); + return -ENOTSUP; + } + + status = DSI_TransferBlocking(config->base, &dsi_xfer); + + if (status != kStatus_Success) { + LOG_ERR("Transmission failed"); + return -EIO; + } + + if (msg->rx_len != 0) { + /* Return rx_len on a read */ + return dsi_xfer.rxDataSize; + } + + /* Return tx_len on a write */ + return dsi_xfer.txDataSize; +} + +static int dsi_dwc_detach(const struct device *dev, uint8_t channel, + const struct mipi_dsi_device *mdev) +{ + const struct dwc_mipi_dsi_config *config = dev->config; + + DSI_EnableCommandMode(config->base, false); + + return 0; +} + +static DEVICE_API(mipi_dsi, dsi_dwc_api) = { + .attach = dsi_dwc_attach, + .transfer = dsi_dwc_transfer, + .detach = dsi_dwc_detach, +}; + +static int dwc_mipi_dsi_init(const struct device *dev) +{ + return 0; +} + +#define DWC_DSI_DPI_CONFIG(id) \ + IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(id), nxp_dc), \ + (.dpi_config = { \ + .virtualChannel = 0U, \ + .colorCoding = DT_INST_ENUM_IDX(id, dpi_color_coding), \ + .videoMode = DT_INST_ENUM_IDX(id, dpi_video_mode), \ + .pixelPayloadSize = DT_INST_PROP_BY_PHANDLE(id, nxp_dc, width), \ + .panelHeight = DT_INST_PROP_BY_PHANDLE(id, nxp_dc, height), \ + .enableAck = false, \ + .enablelpSwitch = true, \ + .pattern = kDSI_PatternDisable, \ + .polarityFlags = (kDSI_DpiVsyncActiveLow | kDSI_DpiHsyncActiveLow), \ + .hfp = DT_INST_PROP_BY_PHANDLE(id, nxp_dc, hfp), \ + .hbp = DT_INST_PROP_BY_PHANDLE(id, nxp_dc, hbp), \ + .hsw = DT_INST_PROP_BY_PHANDLE(id, nxp_dc, hsw), \ + .vfp = DT_INST_PROP_BY_PHANDLE(id, nxp_dc, vfp), \ + .vbp = DT_INST_PROP_BY_PHANDLE(id, nxp_dc, vbp), \ + .vsw = DT_INST_PROP_BY_PHANDLE(id, nxp_dc, vsw), \ + })) + +#define DWC_MIPI_DSI_DEVICE(id) \ + static const struct dwc_mipi_dsi_config mipi_dsi_config_##id = { \ + .base = (MIPI_DSI_Type *)DT_INST_REG_ADDR(id), \ + .data_rate_clock = DT_INST_PROP(id, data_rate_clock), \ + .dphy_ref_frequency = DT_INST_PROP(id, dphy_ref_frequency), \ + DWC_DSI_DPI_CONFIG(id), \ + }; \ + \ + static struct dwc_mipi_dsi_data mipi_dsi_data_##id; \ + DEVICE_DT_INST_DEFINE(id, &dwc_mipi_dsi_init, NULL, &mipi_dsi_data_##id, \ + &mipi_dsi_config_##id, POST_KERNEL, CONFIG_MIPI_DSI_INIT_PRIORITY, \ + &dsi_dwc_api); + +DT_INST_FOREACH_STATUS_OKAY(DWC_MIPI_DSI_DEVICE) diff --git a/dts/bindings/mipi-dsi/nxp,mipi-dsi-dwc.yaml b/dts/bindings/mipi-dsi/nxp,mipi-dsi-dwc.yaml new file mode 100644 index 0000000000000..f2c81f2e7e897 --- /dev/null +++ b/dts/bindings/mipi-dsi/nxp,mipi-dsi-dwc.yaml @@ -0,0 +1,54 @@ +# +# Copyright 2025, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# +description: NXP MCUX MIPI DSI DWC + +compatible: "nxp,mipi-dsi-dwc" + +include: [mipi-dsi-host.yaml, display-controller.yaml] + +properties: + interrupts: + required: true + + nxp,dc: + type: phandle + description: + Instance of the display controller peripheral. Only required when using the MIPI + in video mode + + dpi-color-coding: + type: string + enum: + - "16-bit-config-1" + - "16-bit-config-2" + - "16-bit-config-3" + - "18-bit-config-1" + - "18-bit-config-2" + - "24-bit" + description: + MIPI DPI interface color coding. Sets the distribution of RGB bits within + the 24-bit d bus, as specified by the DPI specification. + + dpi-video-mode: + type: string + enum: + - "non-burst-sync-pulse" + - "non-burst-sync-event" + - "burst" + description: + DPI video mode. + + dphy-ref-frequency: + type: int + required: true + description: + Maximum clock speed supported by the device, in Hz. + + data-rate-clock: + type: int + description: + MIPI data rate clock frequency. Should be set to ensure clock frequency is equal to + (pixel clock * bits per pixel) / number of mipi data lanes diff --git a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake index b794013ca972c..81cbcaaf9d34e 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -116,6 +116,7 @@ set_variable_ifdef(CONFIG_COUNTER_MCUX_LPTMR CONFIG_MCUX_COMPONENT_driver.lpt set_variable_ifdef(CONFIG_IMX_USDHC CONFIG_MCUX_COMPONENT_driver.usdhc) set_variable_ifdef(CONFIG_MIPI_DSI_MCUX CONFIG_MCUX_COMPONENT_driver.mipi_dsi_split) set_variable_ifdef(CONFIG_MIPI_DSI_MCUX_2L CONFIG_MCUX_COMPONENT_driver.mipi_dsi) +set_variable_ifdef(CONFIG_MIPI_DSI_DWC CONFIG_MCUX_COMPONENT_driver.mipi_dsi_imx) set_variable_ifdef(CONFIG_MCUX_SDIF CONFIG_MCUX_COMPONENT_driver.sdif) set_variable_ifdef(CONFIG_ADC_MCUX_ETC CONFIG_MCUX_COMPONENT_driver.adc_etc) set_variable_ifdef(CONFIG_MCUX_XBARA CONFIG_MCUX_COMPONENT_driver.xbara) From 19fe63c37e21af3873a4db02081a8c96cf1fb42c Mon Sep 17 00:00:00 2001 From: Ruoshan Shi Date: Tue, 15 Jul 2025 14:50:12 +0900 Subject: [PATCH 2/4] drivers: panel: Add rm692c9 mipi dsi panel support Added rm692c9 mipi dsi panel Signed-off-by: Ruoshan Shi --- drivers/display/CMakeLists.txt | 1 + drivers/display/Kconfig | 1 + drivers/display/Kconfig.rm692c9 | 10 ++ drivers/display/display_rm692c9.c | 188 ++++++++++++++++++++++ dts/bindings/display/raydium,rm692c9.yaml | 24 +++ 5 files changed, 224 insertions(+) create mode 100644 drivers/display/Kconfig.rm692c9 create mode 100644 drivers/display/display_rm692c9.c create mode 100644 dts/bindings/display/raydium,rm692c9.yaml diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index 60f7bc7b5f808..fac552b05f8eb 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -33,6 +33,7 @@ zephyr_library_sources_ifdef(CONFIG_ST7796S display_st7796s.c) zephyr_library_sources_ifdef(CONFIG_STM32_LTDC display_stm32_ltdc.c) zephyr_library_sources_ifdef(CONFIG_RM68200 display_rm68200.c) zephyr_library_sources_ifdef(CONFIG_RM67162 display_rm67162.c) +zephyr_library_sources_ifdef(CONFIG_RM692C9 display_rm692c9.c) zephyr_library_sources_ifdef(CONFIG_HX8394 display_hx8394.c) zephyr_library_sources_ifdef(CONFIG_GC9X01X display_gc9x01x.c) zephyr_library_sources_ifdef(CONFIG_LED_STRIP_MATRIX display_led_strip_matrix.c) diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index b47f3bc7d477d..b39af82cf4515 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -46,6 +46,7 @@ source "drivers/display/Kconfig.dummy" source "drivers/display/Kconfig.ls0xx" source "drivers/display/Kconfig.rm67162" source "drivers/display/Kconfig.rm68200" +source "drivers/display/Kconfig.rm692c9" source "drivers/display/Kconfig.max7219" source "drivers/display/Kconfig.intel_multibootfb" source "drivers/display/Kconfig.mcux_dcnano_lcdif" diff --git a/drivers/display/Kconfig.rm692c9 b/drivers/display/Kconfig.rm692c9 new file mode 100644 index 0000000000000..040b8ea86321c --- /dev/null +++ b/drivers/display/Kconfig.rm692c9 @@ -0,0 +1,10 @@ +# Copyright 2025, NXP +# SPDX-License-Identifier: Apache-2.0 + +config RM692C9 + bool "RM692C9 display driver" + default y + select MIPI_DSI + depends on DT_HAS_RAYDIUM_RM692C9_ENABLED + help + Enable driver for RM692C9 display driver. diff --git a/drivers/display/display_rm692c9.c b/drivers/display/display_rm692c9.c new file mode 100644 index 0000000000000..54ccded6b0339 --- /dev/null +++ b/drivers/display/display_rm692c9.c @@ -0,0 +1,188 @@ +/* + * Copyright 2025, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT raydium_rm692c9 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(rm692c9, CONFIG_DISPLAY_LOG_LEVEL); + +#define MIPI_DCS_SET_DSI_MODE 0xC2 +/* + * These commands are taken from NXP's MCUXpresso SDK. + * Additional documentation is added where possible, but the + * Manufacture command set pages are not described in the datasheet + */ +static const struct { + uint8_t cmd; + uint8_t param; +} rm692c9_init_1080x2340[] = { + /* CMD Mode switch, select manufacture command set page 0 */ + {.cmd = 0xFE, .param = 0x00}, + {.cmd = 0xC2, .param = 0x08}, + {.cmd = 0x35, .param = 0x00}, +}; + +struct rm692c9_config { + const struct device *mipi_dsi; + uint8_t channel; + uint8_t num_of_lanes; + uint8_t pixel_format; + const struct gpio_dt_spec reset_gpio; + const struct gpio_dt_spec bl_gpio; + uint16_t panel_width; + uint16_t panel_height; +}; + +static int rm692c9_init(const struct device *dev) +{ + const struct rm692c9_config *config = dev->config; + struct mipi_dsi_device mdev = {0}; + int ret; + uint32_t i; + uint8_t cmd, param; + + /* Attach to MIPI DSI host */ + mdev.data_lanes = config->num_of_lanes; + + ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); + if (ret < 0) { + LOG_ERR("Could not attach to MIPI-DSI host"); + return ret; + } + + if (config->reset_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure reset GPIO (%d)", ret); + return ret; + } + + /* + * Power to the display has been enabled via the regulator fixed api during + * regulator init. Per datasheet, we must wait at least 10ms before + * starting reset sequence after power on. + */ + k_sleep(K_MSEC(10)); + /* Start reset sequence */ + ret = gpio_pin_set_dt(&config->reset_gpio, 0); + if (ret < 0) { + LOG_ERR("Could not pull reset low (%d)", ret); + return ret; + } + /* Per datasheet, reset low pulse width should be at least 10usec */ + k_sleep(K_USEC(30)); + gpio_pin_set_dt(&config->reset_gpio, 1); + if (ret < 0) { + LOG_ERR("Could not pull reset high (%d)", ret); + return ret; + } + /* + * It is necessary to wait at least 120msec after releasing reset, + * before sending additional commands. This delay can be 5msec + * if we are certain the display module is in SLEEP IN state, + * but this is not guaranteed (for example, with a warm reset) + */ + k_sleep(K_MSEC(150)); + } + if (config->bl_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&config->bl_gpio, GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure bl GPIO (%d)", ret); + return ret; + } + } + + /* Now, write initialization settings for display, running at */ + for (i = 0; i < ARRAY_SIZE(rm692c9_init_1080x2340); i++) { + cmd = rm692c9_init_1080x2340[i].cmd; + param = rm692c9_init_1080x2340[i].param; + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, cmd, ¶m, 1); + if (ret < 0) { + return ret; + } + } + k_sleep(K_MSEC(80)); + + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SOFT_RESET, NULL, 0); + if (ret < 0) { + return ret; + } + + /* Delay 80 ms before enter DSI mode */ + k_sleep(K_MSEC(80)); + + /* need to set DSI MODE and brightness */ + param = 0x0B; + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_DSI_MODE, ¶m, + 1); + if (ret < 0) { + return ret; + } + + param = 0xFF; + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, + ¶m, 1); + if (ret < 0) { + return ret; + } + + /* Delay 50 ms before exiting sleep mode */ + k_sleep(K_MSEC(50)); + + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_EXIT_SLEEP_MODE, NULL, + 0); + if (ret < 0) { + return ret; + } + /* + * We must wait 5 ms after exiting sleep mode before sending additional + * commands. If we intend to enter sleep mode, we must delay + * 120 ms before sending that command. To be safe, delay 150ms + */ + k_sleep(K_MSEC(150)); + + /* Now, enable display */ + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_DISPLAY_ON, NULL, + 0); + if (ret < 0) { + return ret; + } + + k_sleep(K_MSEC(100)); + + ret = mipi_dsi_detach(config->mipi_dsi, config->channel, &mdev); + if (ret < 0) { + LOG_ERR("Could not detach to MIPI-DSI host"); + return ret; + } + + return 0; +} + +#define RM692C9_PANEL(id) \ + static const struct rm692c9_config rm692c9_config_##id = { \ + .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(id)), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(id, reset_gpios, {0}), \ + .bl_gpio = GPIO_DT_SPEC_INST_GET_OR(id, bl_gpios, {0}), \ + .channel = DT_INST_REG_ADDR(id), \ + .panel_width = DT_INST_PROP(id, width), \ + .pixel_format = DT_INST_PROP(id, pixel_format), \ + .panel_height = DT_INST_PROP(id, height), \ + .num_of_lanes = DT_INST_PROP_BY_IDX(id, data_lanes, 0), \ + }; \ + DEVICE_DT_INST_DEFINE(id, &rm692c9_init, NULL, NULL, &rm692c9_config_##id, POST_KERNEL, \ + CONFIG_APPLICATION_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(RM692C9_PANEL) diff --git a/dts/bindings/display/raydium,rm692c9.yaml b/dts/bindings/display/raydium,rm692c9.yaml new file mode 100644 index 0000000000000..8b9ee8b13b6d2 --- /dev/null +++ b/dts/bindings/display/raydium,rm692c9.yaml @@ -0,0 +1,24 @@ +# +# Copyright 2025, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Raydium RM692C9 Panel + +compatible: "raydium,rm692c9" + +include: [mipi-dsi-device.yaml, display-controller.yaml] + +properties: + reset-gpios: + type: phandle-array + description: | + The RESETn pin is asserted to disable the sensor causing a hard + reset. The sensor receives this as an active-low signal. + + bl-gpios: + type: phandle-array + description: | + The BLn pin is asserted to control the backlight of the panel. + The sensor receives this as an active-high signal. From 3a23e225b4533d22982ccfc8d4c9b007f7445dd4 Mon Sep 17 00:00:00 2001 From: Ruoshan Shi Date: Tue, 15 Jul 2025 15:15:53 +0900 Subject: [PATCH 3/4] boards: nxp: enable mipi dsi support on imx95 Enable rm692c9 mipi dsi panel Signed-off-by: Ruoshan Shi --- boards/nxp/imx95_evk/imx95_evk-pinctrl.dtsi | 11 ++++ .../nxp/imx95_evk/imx95_evk_mimx9596_m7.dts | 56 ++++++++++++++++++- dts/arm/nxp/nxp_imx95_m7.dtsi | 35 ++++++++++++ dts/bindings/display/nxp,dpu.yaml | 36 ++++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/display/nxp,dpu.yaml diff --git a/boards/nxp/imx95_evk/imx95_evk-pinctrl.dtsi b/boards/nxp/imx95_evk/imx95_evk-pinctrl.dtsi index 9bdda182eb22b..319c82d2d1c10 100644 --- a/boards/nxp/imx95_evk/imx95_evk-pinctrl.dtsi +++ b/boards/nxp/imx95_evk/imx95_evk-pinctrl.dtsi @@ -62,6 +62,17 @@ }; }; + lpi2c2_default: lpi2c2_default { + group0 { + pinmux = <&iomuxc_i2c2_scl_lpi2c_scl_lpi2c2_scl>, + <&iomuxc_i2c2_sda_lpi2c_sda_lpi2c2_sda>; + drive-open-drain; + slew-rate = "slightly_fast"; + drive-strength = "x4"; + input-enable; + }; + }; + lpi2c5_default: lpi2c5_default { group0 { pinmux = <&iomuxc_gpio_io23_lpi2c_scl_lpi2c5_scl>, diff --git a/boards/nxp/imx95_evk/imx95_evk_mimx9596_m7.dts b/boards/nxp/imx95_evk/imx95_evk_mimx9596_m7.dts index 8b661db7a8aff..0e9f3d715d660 100644 --- a/boards/nxp/imx95_evk/imx95_evk_mimx9596_m7.dts +++ b/boards/nxp/imx95_evk/imx95_evk_mimx9596_m7.dts @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -90,6 +90,25 @@ }; }; +&lpi2c2 { + pinctrl-0 = <&lpi2c2_default>; + pinctrl-names = "default"; + status = "okay"; + mfd0:adp5585@34 { + compatible = "adi,adp5585"; + reg = <0x34>; + status = "okay"; + gpio_exp0: adp5585_gpio { + compatible = "adi,adp5585-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <13>; + gpio-reserved-ranges = <5 3>; + status = "okay"; + }; + }; +}; + &lpi2c5 { pinctrl-0 = <&lpi2c5_default>; pinctrl-names = "default"; @@ -140,3 +159,38 @@ &edma2 { status = "okay"; }; + +&dpu { + status = "okay"; + width = <1080>; + height = <2340>; + hsw = <4>; + hfp = <12>; + hbp = <8>; + vsw = <4>; + vfp = <10>; + vbp = <10>; +}; + +&mipi_dsi { + status = "okay"; + compatible = "nxp,mipi-dsi-dwc"; + dpi-color-coding = "24-bit"; + dpi-video-mode = "non-burst-sync-pulse"; + dphy-ref-frequency = <24000000>; + data-rate-clock = <890666664>; + nxp,dc = <&dpu>; + width = <1080>; + height = <2340>; + rm692c9@0 { + status = "okay"; + compatible = "raydium,rm692c9"; + reg = <0x0>; + width = <1080>; + height = <2340>; + reset-gpios = <&gpio_exp0 8 GPIO_ACTIVE_HIGH>; + bl-gpios = <&gpio_exp0 4 GPIO_ACTIVE_HIGH>; + data-lanes = <4>; + pixel-format = <0>; + }; +}; diff --git a/dts/arm/nxp/nxp_imx95_m7.dtsi b/dts/arm/nxp/nxp_imx95_m7.dtsi index 1751f15014eb3..31265519cf280 100644 --- a/dts/arm/nxp/nxp_imx95_m7.dtsi +++ b/dts/arm/nxp/nxp_imx95_m7.dtsi @@ -106,6 +106,7 @@ gpio-controller; #gpio-cells = <2>; ngpios = <16>; + status = "disabled"; }; gpio2: gpio@43810000 { @@ -526,6 +527,40 @@ }; }; + dpu_irqsteer: interrupt-controller@4b0b0000 { + compatible = "nxp,irqsteer-intc"; + reg = <0x4b0b0000 DT_SIZE_K(64)>; + + #size-cells = <0>; + #address-cells = <1>; + + dpu_irqsteer_master0: dpu_interrupt-controller@0 { + compatible = "nxp,irqsteer-master"; + reg = <0>; + interrupt-controller; + #interrupt-cells = <1>; + interrupts-extended = <&nvic 214 0>; + }; + }; + + dpu: dpu@4b400000 { + compatible = "nxp,dpu"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4b400000 0x1000>; + status = "disabled"; + }; + + mipi_dsi: mipi-dsi@4acf0000 { + compatible = "nxp,mipi-dsi-dwc"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4acf0000 0x1000>; + interrupt-parent = <&dpu_irqsteer_master0>; + interrupts = <48 0 0>; + status = "disabled"; + }; + netc: ethernet@4ca00000 { reg = <0x4ca00000 0x1000000>; interrupt-parent = <&irqsteer_master0>; diff --git a/dts/bindings/display/nxp,dpu.yaml b/dts/bindings/display/nxp,dpu.yaml new file mode 100644 index 0000000000000..b984ee242e136 --- /dev/null +++ b/dts/bindings/display/nxp,dpu.yaml @@ -0,0 +1,36 @@ +# Copyright (c) 2025, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP i.MX DPU controller + +compatible: "nxp,dpu" + +include: [base.yaml, display-controller.yaml] + +properties: + reg: + required: true + + hsw: + type: int + description: HSYNC pulse width in display clock cycles + + hfp: + type: int + description: Horizontal front porch in display clock cycles + + hbp: + type: int + description: Horizontal back porch in display clock cycles + + vsw: + type: int + description: VSYNC pulse width in display clock cycles + + vfp: + type: int + description: Vertical front porch in display clock cycles + + vbp: + type: int + description: Vertical back porch in display clock cycles From e300ee407c2fef52387dd903de28ad1a9855d8f6 Mon Sep 17 00:00:00 2001 From: Ruoshan Shi Date: Tue, 15 Jul 2025 15:23:19 +0900 Subject: [PATCH 4/4] soc: imx95: m7: Config power setting for mipi dsi Power on display and camera mix for mipi dsi Signed-off-by: Ruoshan Shi --- soc/nxp/imx/imx9/imx95/m7/soc.c | 38 +++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/soc/nxp/imx/imx9/imx95/m7/soc.c b/soc/nxp/imx/imx9/imx95/m7/soc.c index db60e45170eab..e02363489977f 100644 --- a/soc/nxp/imx/imx9/imx95/m7/soc.c +++ b/soc/nxp/imx/imx9/imx95/m7/soc.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -75,6 +75,41 @@ static int soc_init(void) } #endif +#if defined(CONFIG_MIPI_DSI_DWC) + struct scmi_power_state_config pwr_cfg = {0}; + uint32_t power_state = POWER_DOMAIN_STATE_OFF; + + /* Power up DISPLAYMIX */ + pwr_cfg.domain_id = IMX95_PD_DISPLAY; + pwr_cfg.power_state = POWER_DOMAIN_STATE_ON; + ret = scmi_power_state_set(&pwr_cfg); + if (ret) { + return ret; + } + + while (power_state != POWER_DOMAIN_STATE_ON) { + ret = scmi_power_state_get(IMX95_PD_DISPLAY, &power_state); + if (ret) { + return ret; + } + } + + /* Power up CAMERAMIX */ + pwr_cfg.domain_id = IMX95_PD_CAMERA; + pwr_cfg.power_state = POWER_DOMAIN_STATE_ON; + + ret = scmi_power_state_set(&pwr_cfg); + if (ret) { + return ret; + } + + while (power_state != POWER_DOMAIN_STATE_ON) { + ret = scmi_power_state_get(IMX95_PD_CAMERA, &power_state); + if (ret) { + return ret; + } + } +#endif #if defined(CONFIG_NXP_SCMI_CPU_DOMAIN_HELPERS) cpu_cfg.cpu_id = CPU_IDX_M7P; cpu_cfg.sleep_mode = CPU_SLEEP_MODE_RUN; @@ -84,7 +119,6 @@ static int soc_init(void) return ret; } #endif /* CONFIG_NXP_SCMI_CPU_DOMAIN_HELPERS */ - return ret; }