From d6a36eb74c33fa8723cbf7d727059014ac5278c8 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Tue, 7 Oct 2025 09:09:40 -0500 Subject: [PATCH 01/16] This is only a temp branch for working on ZC143 Display support The naming and architecture arangement is only temporary. Work on the driver should be first priority. This is a chance we split the driver into seperate MIPI_DSI; LCDIF; ZC143; I2C; and XSPI drivers. ZC143 header file still needed for constants and definitions. Signed-off-by: Emilio Benavente --- boards/nxp/mimxrt700_evk/board.c | 42 ++ .../mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi | 52 ++ .../mimxrt700_evk_mimxrt798s_cm33_cpu0.dts | 10 +- .../shields/zc143ac72mipi/Kconfig.defconfig | 20 + boards/shields/zc143ac72mipi/Kconfig.shield | 5 + boards/shields/zc143ac72mipi/doc/index.rst | 2 + boards/shields/zc143ac72mipi/shield.yml | 6 + .../zc143ac72mipi/zc143ac72mipi.overlay | 32 + drivers/display/CMakeLists.txt | 1 + drivers/display/Kconfig | 1 + drivers/display/Kconfig.zc143ac72mipi | 13 + drivers/display/display_zc143ac72mipi.c | 610 ++++++++++++++++++ dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi | 2 + dts/arm/nxp/nxp_rt7xx_common.dtsi | 16 + .../display/display,zc143ac72mipi.yaml | 8 + dts/bindings/display/mipi,zc143ac72.yml | 12 + .../mcux/mcux-sdk-ng/drivers/drivers.cmake | 2 + todo.txt | 268 ++++++++ 18 files changed, 1099 insertions(+), 3 deletions(-) create mode 100644 boards/shields/zc143ac72mipi/Kconfig.defconfig create mode 100644 boards/shields/zc143ac72mipi/Kconfig.shield create mode 100644 boards/shields/zc143ac72mipi/doc/index.rst create mode 100644 boards/shields/zc143ac72mipi/shield.yml create mode 100644 boards/shields/zc143ac72mipi/zc143ac72mipi.overlay create mode 100644 drivers/display/Kconfig.zc143ac72mipi create mode 100644 drivers/display/display_zc143ac72mipi.c create mode 100644 dts/bindings/display/display,zc143ac72mipi.yaml create mode 100644 dts/bindings/display/mipi,zc143ac72.yml create mode 100644 todo.txt diff --git a/boards/nxp/mimxrt700_evk/board.c b/boards/nxp/mimxrt700_evk/board.c index a4b75c20d55de..b871147d65da9 100644 --- a/boards/nxp/mimxrt700_evk/board.c +++ b/boards/nxp/mimxrt700_evk/board.c @@ -544,6 +544,48 @@ void board_early_init_hook(void) CLOCK_EnableClock(kCLOCK_Acmp0); RESET_ClearPeripheralReset(kACMP0_RST_SHIFT_RSTn); #endif + +//@HARDCODE @INCOMPLETE(Emilio): Force hardcode for testing +#if 1 +//@NOTE(Emilio): BOARD_InitMipiDsiClock + POWER_DisablePD(kPDRUNCFG_PPD_MIPIDSI); + POWER_DisablePD(kPDRUNCFG_APD_MIPIDSI); + POWER_DisablePD(kPDRUNCFG_PD_VDD2_MIPI); + POWER_ApplyPD(); + + /* Use PLL PFD1 as clock source, 396m. */ + CLOCK_AttachClk(kMAIN_PLL_PFD1_to_MIPI_DPHYESC_CLK); + /* RxClkEsc min 60MHz, TxClkEsc 12 to 20MHz. */ + /* RxClkEsc = 396MHz / 6 = 66MHz. */ + CLOCK_SetClkDiv(kCLOCK_DivDphyEscRxClk, 6); + /* TxClkEsc = 396MHz / 6 / 4 = 16.5MHz. */ + CLOCK_SetClkDiv(kCLOCK_DivDphyEscTxClk, 4); + + CLOCK_InitAudioPfd(kCLOCK_Pfd2, 30); + + CLOCK_AttachClk(kAUDIO_PLL_PFD2_to_MIPI_DSI_HOST_PHY); + + CLOCK_SetClkDiv(kCLOCK_DivDphyClk, 1); + + +//@NOTE(Emilio): BOARD_InitLcdifPowerReset + POWER_DisablePD(kPDRUNCFG_SHUT_MEDIA_MAINCLK); + POWER_DisablePD(kPDRUNCFG_APD_LCDIF); + POWER_DisablePD(kPDRUNCFG_PPD_LCDIF); + POWER_ApplyPD(); + + CLOCK_EnableClock(kCLOCK_Lcdif); + RESET_ClearPeripheralReset(kLCDIF_RST_SHIFT_RSTn); + + +//@NOTE(Emilio): Clock code in BOARD_InitLcdif + CLOCK_InitMainPfd(kCLOCK_Pfd2, 17); + CLOCK_SetClkDiv(kCLOCK_DivMediaMainClk, 2U); + CLOCK_AttachClk(kMAIN_PLL_PFD2_to_MEDIA_MAIN); + + +#endif + } static void GlikeyWriteEnable(GLIKEY_Type *base, uint8_t idx) diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi b/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi index 32afe95fe92ef..dd835386b7dec 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk-pinctrl.dtsi @@ -193,4 +193,56 @@ slew-rate = "normal"; }; }; + + pinmux_display: pinmux_display { + group0 { + pinmux = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + drive-strength = "normal"; + slew-rate = "normal"; + input-enable; + }; + + group1 { + pinmux = , + , + , + ; + drive-strength = "normal"; + slew-rate = "normal"; + }; + + /* + @INCOMPLETE(Emilio): Each mux takes different flags. + Place into seperate groups + group2 { + pinmux = , + , + , + ; + drive-strength = "normal"; + slew-rate = "normal"; + }; + */ + + }; }; diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts index d35762b53e52f..3a6959c33b484 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts @@ -34,7 +34,7 @@ zephyr,sram = &sram0; zephyr,console = &flexcomm0_lpuart0; zephyr,shell-uart = &flexcomm0_lpuart0; - zephyr,display = &lcdif; +// zephyr,display = &lcdif; }; leds { @@ -269,9 +269,9 @@ nxp_mipi_i2c: &flexcomm8_lpi2c8 {}; -zephyr_mipi_dsi: &mipi_dsi {}; +//zephyr_mipi_dsi: &mipi_dsi {}; -zephyr_lcdif: &lcdif {}; +//zephyr_lcdif: &lcdif {}; &gpio0 { status = "okay"; @@ -424,3 +424,7 @@ p3t1755dp_ard_i2c_interface: &flexcomm8_lpi2c8 {}; &pca9422 { status = "okay"; }; + +&lcdif2 { + status = "okay"; +}; diff --git a/boards/shields/zc143ac72mipi/Kconfig.defconfig b/boards/shields/zc143ac72mipi/Kconfig.defconfig new file mode 100644 index 0000000000000..0cf0a996982a7 --- /dev/null +++ b/boards/shields/zc143ac72mipi/Kconfig.defconfig @@ -0,0 +1,20 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_ZC143AC72MIPI +if LVGL + +# Enable double buffering +# config LV_Z_DOUBLE_VDB +# default y + +# config LV_Z_BITS_PER_PIXEL +# default 16 + +endif # LVGL + +if INPUT +# config --- +endif # INPUT + +endif # SHIELD_ZC143AC72MIPI diff --git a/boards/shields/zc143ac72mipi/Kconfig.shield b/boards/shields/zc143ac72mipi/Kconfig.shield new file mode 100644 index 0000000000000..d83668dfd2021 --- /dev/null +++ b/boards/shields/zc143ac72mipi/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_ZC143AC72MIPI + def_bool $(shields_list_contains,zc143ac72mipi) diff --git a/boards/shields/zc143ac72mipi/doc/index.rst b/boards/shields/zc143ac72mipi/doc/index.rst new file mode 100644 index 0000000000000..f3e9686e838f9 --- /dev/null +++ b/boards/shields/zc143ac72mipi/doc/index.rst @@ -0,0 +1,2 @@ +#EMPTY DOC FOR NOW + diff --git a/boards/shields/zc143ac72mipi/shield.yml b/boards/shields/zc143ac72mipi/shield.yml new file mode 100644 index 0000000000000..29ed8fb821fe6 --- /dev/null +++ b/boards/shields/zc143ac72mipi/shield.yml @@ -0,0 +1,6 @@ +shields: + - name: zc143ac72mipi + full_name: --- ZC143AC72 MIPI LCD Module + vendor: --- + supported_features: + - display diff --git a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay new file mode 100644 index 0000000000000..9714d1535c573 --- /dev/null +++ b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay @@ -0,0 +1,32 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* #include */ + +/ { + chosen { + zephyr,display = &zc143ac72mipi; + }; +}; + +&lcdif_target { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + zc143ac72mipi: zc143ac72mipi@0 { + compatible = "display,zc143ac72mipi"; + reg = <0>; + status = "okay"; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio3 { + status = "okay"; +}; diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index 32e8bc190b9a2..82b738d840e55 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -43,6 +43,7 @@ zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_GLCDC display_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_ILI9806E_DSI display_ili9806e_dsi.c) zephyr_library_sources_ifdef(CONFIG_ST7701 display_st7701.c) zephyr_library_sources_ifdef(CONFIG_LPM013M126 display_lpm013m126.c) +zephyr_library_sources_ifdef(CONFIG_DISPLAY_ZC143AC72MIPI display_zc143ac72mipi.c) zephyr_library_sources_ifdef(CONFIG_MICROBIT_DISPLAY mb_display.c diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index 7d4ada3bd6ab0..83e3906134fc6 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -60,5 +60,6 @@ source "drivers/display/Kconfig.renesas_ra" source "drivers/display/Kconfig.ili9806e_dsi" source "drivers/display/Kconfig.st7701" source "drivers/display/Kconfig.lpm013m126" +source "drivers/display/Kconfig.zc143ac72mipi" endif # DISPLAY diff --git a/drivers/display/Kconfig.zc143ac72mipi b/drivers/display/Kconfig.zc143ac72mipi new file mode 100644 index 0000000000000..a0bc41134fde7 --- /dev/null +++ b/drivers/display/Kconfig.zc143ac72mipi @@ -0,0 +1,13 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + + +menuconfig DISPLAY_ZC143AC72MIPI + bool "MCUX ---" + default y + help + --- + + +if DISPLAY_ZC143AC72MIPI +endif # DISPLAY_ZC143AC72MIPI diff --git a/drivers/display/display_zc143ac72mipi.c b/drivers/display/display_zc143ac72mipi.c new file mode 100644 index 0000000000000..e7c54dd15e79c --- /dev/null +++ b/drivers/display/display_zc143ac72mipi.c @@ -0,0 +1,610 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +//@IMPORTANT @INCOMPLETE(Emilio): None of the function are checking for errors at the moment! + +#define DT_DRV_COMPAT display_zc143ac72mipi + +#include +//LOG_MODULE_REGISTER(zc143ac72mipi, CONFIG_DISPLAY_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include + +#include +#include + +//#include "zc143ac72mipi_regs.h" + +static struct display_cmds { + uint8_t *cmd_code; + uint8_t size; +}; + +struct zc143ac72mipi_config { + LCDIF_Type *lcdif_base; + MIPI_DSI_HOST_Type *mipi_base; + enum display_pixel_format initial_pixel_format; + const struct gpio_dt_spec reset_gpio; + const struct gpio_dt_spec power_gpio; + const struct gpio_dt_spec mipi_te_gpio; +}; + +struct zc143ac72mipi_data { + int Placeholder; +}; + + +//@IMPORTANT(Emilio): We may need to be more particular on how to choose the txDataType, there seems +// to be many definitions. +static int zc143ac72mipi_write_cmd_codes(const struct device *dev, + const struct display_cmds *cmds) +{ + const struct zc143ac72mipi_config *config = dev->config; + MIPI_DSI_HOST_Type *mipi_base = config->mipi_base; + dsi_transfer_t transfer_config = {}; + + for (int iter = 0; iter < ARRAY_SIZE(cmds); iter++) + { + switch(cmds[iter]->size) + { + case 0: + { + //@TODO(Emilio): Error case. + + } break; + + case 1: + { + transfer_config.txDataType = kDSI_TxDataDcsShortWrNoParam; + } break; + + case 2: + { + transfer_config.txDataType = kDSI_TxDataDcsShortWrOneParam; + + } break; + + default + { + transfer_config.txDataType = kDSI_TxDataDcsLongWr; + } + } + + transfer_config.txData = cmds[iter]->cmd_code; + transfer_config.txSize = cmds[iter]->size; + DSI_TransferBlocking(mipi_base, &transfer_config); + } +} + +static int zc143ac72mipi_blanking_on(const struct device *dev) +{ + +} + +static int zc143ac72mipi_blanking_off(const struct device *dev) +{ + +} + +static int zc143ac72mipi_write(const struct device *dev, + const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, + const void *buf) +{ + const struct zc143ac72mipi_config *config = dev->config; + LCDIF_Type *lcdif_base = config->lcdif_base; + MIPI_DSI_HOST_Type *mipi_base = config->mipi_base; + enum display_pixel_format pixel_format = config->initial_pixel_format; + + +#if 0 + uint8_t cmd = (uint8_t)command; + dbi_lcdif_prv_data_t *prvData = (dbi_lcdif_prv_data_t *)dbiIface->prvData; + uint16_t height = prvData->height; + uint32_t stride; + + if (isInterleave) + { + stride = stride_byte; + } + else + { + stride = (uint32_t)prvData->width * (uint32_t)prvData->bytePerPixel; + } + + /* For RGB888 the stride shall be calculated as 4 bytes per pixel. */ + if (prvData->bytePerPixel == 3U) + { + LCDIF_SetFrameBufferStride(lcdif, 0, stride / 3U * 4U); + } + else + { + LCDIF_SetFrameBufferStride(lcdif, 0, stride); + } +#if DBI_USE_MIPI_PANEL + MIPI_DSI_HOST_Type *dsi = prvData->dsi; + uint8_t payloadBytePerPixel; + + if (dsi != NULL) + { + prvData->stride = (uint16_t)stride; + + /* 1 pixel sent in 1 cycle. */ + if (prvData->dsiFormat == kDSI_DbiRGB565) + { + payloadBytePerPixel = 2U; + } + /* 2 pixel sent in 1 cycle. */ + else if (prvData->dsiFormat == kDSI_DbiRGB332) + { + payloadBytePerPixel = 1U; + } + /* 2 pixels sent in 3 cycles. kDSI_DbiRGB888, kDSI_DbiRGB444 and kDSI_DbiRGB666 */ + else + { + payloadBytePerPixel = 3U; + } + + /* If the whole update payload exceeds the DSI max payload size, send the payload in multiple times. */ + if ((prvData->width * prvData->height * payloadBytePerPixel) > MIPI_DSI_MAX_PAYLOAD_SIZE) + { + /* Calculate how may lines to send each time. Make sure each time the buffer address meets the align + * requirement. */ + height = MIPI_DSI_MAX_PAYLOAD_SIZE / prvData->width / (uint16_t)payloadBytePerPixel; + while (((height * prvData->stride) & (LCDIF_FB_ALIGN - 1U)) != 0U) + { + height--; + } + prvData->heightEachWrite = height; + + /* Point the data to the next piece. */ + prvData->data = (uint8_t *)((uint32_t)data + (height * prvData->stride)); + } + + /* Set payload size. */ + DSI_SetDbiPixelPayloadSize(dsi, (height * prvData->width * (uint16_t)payloadBytePerPixel) >> 1U); + } + + /* Update height info. */ + prvData->heightSent = height; +#endif + prvData->height -= height; + + /* Configure buffer position, address and area. */ + LCDIF_SetFrameBufferPosition(lcdif, 0U, 0U, 0U, prvData->width, height); + LCDIF_DbiSelectArea(lcdif, 0, 0, 0, prvData->width - 1U, height - 1U, false); + LCDIF_SetFrameBufferAddr(lcdif, 0, (uint32_t)data); + + /* Send command. */ + LCDIF_DbiSendCommand(lcdif, 0, cmd); + + /* Start memory transfer. */ + LCDIF_DbiWriteMem(lcdif, 0); +#endif + +} + +static int zc143ac72mipi_read(const struct device *dev, + const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, void *buf) +{ + +} + +static int zc143ac72mipi_clear(const struct device *dev) +{ + +} + +static void *zc143ac72mipi_get_framebuffer(const struct device *dev) +{ + +} + +static int zc143ac72mipi_set_brightness(const struct device *dev, uint8_t) +{ + +} + +static int zc143ac72mipi_set_contrast(const struct device *dev, uint8_t contrast) +{ + +} + +static void zc143ac72mipi_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + capabilities->x_resolution = 256; + capabilities->y_resolution = 466; + //@TODO(Emilio): capabilities->pixel_formats = PIXEL_FORMAT_*** | *** | ***; +// capabilities->pixel_formats = PIXEL_FORMAT_RGB_565; + //@TODO(Emilio): capabilities->screen_info = SCREEN_INFO_MONO*** | *** | ***; + //@TODO(Emilio): Find the screen info here. +// capabilities->current_pixel_format = PXIEL_FORMAT_RGB_565; +// capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; +} + +static int zc143ac72mipi_set_pixel_format(const struct device *dev, + const enum display_pixel_format pixel_format) +{ + //@NOTE(Emilio): The following is how you set the pixel format for the MIPI_DSI + // base->CFG_DBI_PIXEL_FIFO_SEND_LEVEL = (u32)sendLevel; //@NOTE(Emilio): Found in + // drivers/mipi_dsi/fsl_mipi_dsi.h + // also + // base->CFG_DBI_PIXEL_FORMAT + // LCDIF_SetFrameBufferConfig(***); + +} + +static int zc143ac72mipi_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ + +} + +static int zc143ac72mipi_init(const struct device *dev) +{ + const struct zc143ac72mipi_config *config = dev->config; + LCDIF_Type *lcdif_base = config->lcdif_base; + MIPI_DSI_HOST_Type *mipi_base = config->mipi_base; + enum display_pixel_format pixel_format = config->initial_pixel_format; + + //@HARDCODE @INCOMPLETE(Emilio): All the values here are hardcoded from display_support.c + //@NOTE(Emilio): Enable MIPI + dsi_config_t dsiConfig; + DSI_GetDefaultConfig(&dsiConfig); + dsiConfig.numLanes = 1; + dsiConfig.autoInsertEoTp = true; + DSI_Init(mipi_base, &dsiConfig); + + uint32_t mipiDsiDphyBitClkFreq_Hz = CLOCK_GetMipiDphyClkFreq(); + uint32_t mipiDsiTxEscClkFreq_Hz = CLOCK_GetMipiDphyEscTxClkFreq(); + + dsi_dphy_config_t dphyConfig; + DSI_GetDphyDefaultConfig(&dphyConfig, mipiDsiDphyBitClkFreq_Hz, mipiDsiTxEscClkFreq_Hz); + DSI_InitDphy(mipi_base, &dphyConfig, 0); + + //@HARDCODE(Emilio): Not sure what 64 does here. + DSI_SetDbiPixelFifoSendLevel(mipi_base, 64U); + DSI_SetDbiPixelFormat(mipi_base, kDSI_DbiRGB565); + + + + //@NOTE(Emilio): Enable LCDIF + + /* DBI configurations. */ + lcdif_dbi_config_t dbi_config; + LCDIF_DbiModeGetDefaultConfig(&dbi_config); + dbi_config.acTimeUnit = 0; + dbi_config.writeWRPeriod = 14U; + + /* With 279.53MHz source and 16bpp format, a 14 cycle period requires a 279.53MHz / 14 * 16 = 319.46Mhz DPHY clk + * source. */ + if (pixel_format == PIXEL_FORMAT_RGB_565) + { + dbi_config.format = kLCDIF_DbiOutD16RGB565; + } + else + { + dbi_config.format = kLCDIF_DbiOutD16RGB888Option1; + } + dbi_config.type = kLCDIF_DbiTypeB; + dbi_config.writeCSAssert = 1; + dbi_config.writeCSDeassert = 4; + dbi_config.writeWRAssert = (dbi_config.writeWRPeriod - 1U) / 2U; /* Asset at the middle. */ + dbi_config.writeWRDeassert = (dbi_config.writeWRPeriod - 1U); /* Deassert at the end */ + + LCDIF_Init(lcdif_base); + LCDIF_DbiModeSetConfig(lcdif_base, 0, &dbi_config); + + lcdif_panel_config_t lcdif_config; + LCDIF_PanelGetDefaultConfig(&lcdif_config); + if (pixel_format == PIXEL_FORMAT_RGB_565) + { + lcdif_config.endian = kLCDIF_HalfWordSwap; + } + + LCDIF_SetPanelConfig(lcdif_base, 0, &lcdif_config); + + //@TODO(Emilio): Add irq_config func here. + + + //@NOTE(Emilio): Init LCDIF Controller + LCDIF_EnableInterrupts(lcdif_base, kLCDIF_Display0FrameDoneInterrupt | kLCDIF_PanelUnderflowInterrupt); + + + //@NOTE(Emilio): Init LCDIF Panel + + //@IMPORTANT @INCOMPLETE(Emilio): Check that we configure these gpio correctly, polarity + gpio_pin_configure_dt(&config->power_gpio, GPIO_OUTPUT_LOW); + //@SPEED @HARDCODE(Emilio): Hardcode GPIO to HIGH to bypass sdk steps. + gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_HIGH); + gpio_pin_configure_dt(&config->mipi_te_gpio, GPIO_OUTPUT_LOW); + +#if 0 + //@IMPORTANT(Emilio): Check to see if these interrupts get set. + GPIO_SetPinInterruptConfig(BOARD_MIPI_TE_GPIO, BOARD_MIPI_TE_PIN, kGPIO_InterruptRisingEdge); + GPIO_SetPinInterruptChannel(BOARD_MIPI_TE_GPIO, BOARD_MIPI_TE_PIN, kGPIO_InterruptOutput0); +#endif + + //@IMPORTANT @INCOMPLETE(Emilio): Ensure These GPIOs NVICs are enabled correctly. + + + + //@NOTE(Emilio): Init LCDIF Panel +#if 0 + //@INCOMPLETE @NOTE(Emilio): This Should be done at compile time in DEVICE_INIT + handle->height = FSL_VIDEO_EXTRACT_HEIGHT(config->resolution); + handle->width = FSL_VIDEO_EXTRACT_WIDTH(config->resolution); + handle->pixelFormat = config->pixelFormat; + + @TODO(Emilio): Why does SDK have this sequence of gpio toggles?? + @NOTE(Emilio): BTW -> gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_HIGH); + /* Power on. */ + resource->pullPowerPin(true); + co5300_DelayMs(100); + + /* Perform reset. */ + resource->pullResetPin(false); + co5300_DelayMs(1); + resource->pullResetPin(true); + co5300_DelayMs(150); +#endif + + //@NOTE(Emilio): Set LCM Init Settings + + //@HARDCODE(Emilio): Comes straight from components/video/display/c05300/fsl_co5300.c + const display_cmds lcm_init_settings[] = { + {{0xFE, 0x20}, 2}, {{0xF4, 0x5A}, 2}, + {{0xF5, 0x59}, 2}, {{0xFE, 0x40}, 2}, + {{0x96, 0x00}, 2}, {{0xC9, 0x00}, 2}, + {{0xFE, 0x00}, 2}, {{0x35, 0x00}, 2}, + {{0x53, 0x20}, 2}, {{0x51, 0xFF}, 2}, + {{0x63, 0xFF}, 2}, {{0x2A, 0x00, 0x06, 0x01, 0xD7}, 5}, + {{0x2B, 0x00, 0x00, 0x01, 0xD1}, 5} + }; + zc143ac72mipi_write_cmd_codes(dev, lcm_init_settings); + + + display_cmds pixel_setting_cmd = {{0x36, 0x0}, 2}; + if (config->pixelFormat != kVIDEO_PixelFormatRGB565) + { + pixel_setting_cmd.cmd_code[1] = 0x8; + } + zc143ac72mipi_write_cmd_codes(dev, pixel_setting_cmd); + + + + /* Set pixel format. */ + //@HARDCODE @NOTE(Emilio): Eventually we will make defines in a header file + // the Most sig bits are for the dpi pixel_format the Least sig bits + // are for the dbi pixel format, just the abi for the command code. + // The two valid pixel formats are 0x77 or 0x75 hints the |= 2. + char pixel_format_cmd = (7 << 4) | 5; + if ((kVIDEO_PixelFormatXRGB8888 == config->pixelFormat) || (kVIDEO_PixelFormatRGB888 == config->pixelFormat)) + { + dbi_pixel_format |= 2; + } + display_cmds pixel_foramt_cmd = {{0x3A, pixel_format_cmd}, 2}; + zc143ac72mipi_write_cmd_codes(dev, pixel_setting_cmd); + + + //@TODO(Emilio): Again, unsure why we attempt a sleep in SDK. +// co5300_DelayMs(50); + + + //@TODO(Emilio): Part of the definitions. + // Entering sleep CMD is 0x10 + // Exiting sleep CMD is 0x11 + display_cmds exit_sleep_cmd = {{0x11}, 1}; + zc143ac72mipi_write_cmd_codes(dev, exit_sleep_cmd); + + //@TODO(Emilio): Again, unsure why we attempt a sleep in SDK. +// co5300_DelayMs(150); + + + //@NOTE(Emilio): Turn on Display. + display_cmds exit_sleep_cmd = {{0x29}, 1}; + zc143ac72mipi_write_cmd_codes(dev, exit_sleep_cmd); + + + //@NOTE(Emilio): SDK Setups a callback at this point for FrameDoneCallback + //@NOTE(Emilio): The SDK also has a helper function to get size in bits based on + // Pixel Format, might be a good idea. + + + //@NOTE(Emilio): More set Pixel Format but for LCDIF +#if 0 + lcdif_fb_config_t fbConfig; + dbi_lcdif_prv_data_t *prvData = (dbi_lcdif_prv_data_t *)dbiIface->prvData; + lcdif_layer_input_order_t componentOrder; + lcdif_fb_format_t pixelFormat; + + status = DBI_LCDIF_GetPixelFormat(format, &pixelFormat, &componentOrder); + //@NOTE(Emilio): The nested for loop is GetPixelFormat + for (int i = 0; i < ARRAY_SIZE(s_lcdifPixelFormatMap); i++) + { + if (s_lcdifPixelFormatMap[i].videoFormat == input) + { + *output = s_lcdifPixelFormatMap[i].lcdifFormat; + *order = s_lcdifPixelFormatMap[i].componentOrder; + return kStatus_Success; + } + } + + + LCDIF_FrameBufferGetDefaultConfig(&fbConfig); + fbConfig.format = pixelFormat; + fbConfig.inOrder = componentOrder; + LCDIF_SetFrameBufferConfig(lcdif, 0, &fbConfig); + + /* Set byte per pixel for stride calculation later. */ + //@NOTE(Emilio): VIDEO_** is the helper function mentioned above. + prvData->bytePerPixel = VIDEO_GetPixelSizeBits(format) / 8U; +#endif + + + //@NOTE(Emilio): SDK Then selects Area? +#if 0 + uint8_t data[4]; + status_t status; + + /*Column addresses*/ + data[0] = (startX >> 8) & 0xFF; + data[1] = startX & 0xFF; + data[2] = (endX >> 8) & 0xFF; + data[3] = endX & 0xFF; + + status = DBI_IFACE_WriteCmdData(dbiIface, kMIPI_DBI_SetColumnAddress, data, 4); + + if (status != kStatus_Success) + { + return status; + } + + /*Page addresses*/ + data[0] = (startY >> 8) & 0xFF; + data[1] = startY & 0xFF; + data[2] = (endY >> 8) & 0xFF; + data[3] = endY & 0xFF; + + status = DBI_IFACE_WriteCmdData(dbiIface, kMIPI_DBI_SetPageAddress, data, 4); + + //@NOTE(Emilio): DBI_IFACE_WriteCmdData + if ((len_byte != 0U) && (data == NULL)) + { + return kStatus_Fail; + } + + uint8_t cmd = (uint8_t)command; + uint8_t *pData = (uint8_t *)data; + dbi_lcdif_prv_data_t *prvData = (dbi_lcdif_prv_data_t *)dbiIface->prvData; + LCDIF_Type *lcdif = prvData->lcdif; + + /* If the command is set address, calculate the selected area size, since LCDIF needs these info for configuration. + */ + if ((cmd == (uint8_t)kMIPI_DBI_SetColumnAddress) || (cmd == (uint8_t)kMIPI_DBI_SetPageAddress)) + { + uint16_t lrValue = ((uint16_t)pData[2] << 8U) | (uint16_t)pData[3]; + uint16_t tpValue = ((uint16_t)pData[0] << 8U) | (uint16_t)pData[1]; + + if (lrValue < tpValue) + { + return kStatus_Fail; + } + + if (cmd == kMIPI_DBI_SetColumnAddress) + { + prvData->width = lrValue - tpValue + 1U; + } + else + { + prvData->height = lrValue - tpValue + 1U; + } + } + + LCDIF_DbiSendCommand(lcdif, 0U, cmd); + if (len_byte != 0U) + { + LCDIF_DbiSendData(lcdif, 0U, pData, len_byte); + } + +#endif + + //@NOTE(Emilio): At this point the SDK sets up a callback for BufferSwitchOff + // Creates a semaphore + // and clears an area of memory to use as the framebuffer. + + + + //@NOTE(Emilio): Turning on the LCDIF +#if 0 + uint8_t cmd = (on ? kMIPI_DBI_SetDisplayOn : kMIPI_DBI_SetDisplayOff); + dbiIface->xferOps->writeCommandData(dbiIface, cmd, NULL, 0); + + //@NOTE(Emilio): The following code is writeCommmandData + if ((len_byte != 0U) && (data == NULL)) + { + return kStatus_Fail; + } + + uint8_t cmd = (uint8_t)command; + uint8_t *pData = (uint8_t *)data; + dbi_lcdif_prv_data_t *prvData = (dbi_lcdif_prv_data_t *)dbiIface->prvData; + LCDIF_Type *lcdif = prvData->lcdif; + + /* If the command is set address, calculate the selected area size, since LCDIF needs these info for configuration. + */ + if ((cmd == (uint8_t)kMIPI_DBI_SetColumnAddress) || (cmd == (uint8_t)kMIPI_DBI_SetPageAddress)) + { + uint16_t lrValue = ((uint16_t)pData[2] << 8U) | (uint16_t)pData[3]; + uint16_t tpValue = ((uint16_t)pData[0] << 8U) | (uint16_t)pData[1]; + + if (lrValue < tpValue) + { + return kStatus_Fail; + } + + if (cmd == kMIPI_DBI_SetColumnAddress) + { + prvData->width = lrValue - tpValue + 1U; + } + else + { + prvData->height = lrValue - tpValue + 1U; + } + } + + LCDIF_DbiSendCommand(lcdif, 0U, cmd); + + if (len_byte != 0U) + { + LCDIF_DbiSendData(lcdif, 0U, pData, len_byte); + } +#endif + + + + + //@NOTE(Emilio): The SDK Now starts to init VGLite, probably not needed on our side. + //@NOTE(Emilio): The SDK Then enables the touchscreen via I2C. + + //@NOTE(Emilio): Finally done! + return 0; +} + +static DEVICE_API(display, zc143ac72mipi_driver_api) = { + .blanking_on = zc143ac72mipi_blanking_on, + .blanking_off = zc143ac72mipi_blanking_off, + .write = zc143ac72mipi_write, + .read = zc143ac72mipi_read, + .clear = zc143ac72mipi_clear, + .get_framebuffer = zc143ac72mipi_get_framebuffer, + .set_brightness = zc143ac72mipi_set_brightness, + .set_contrast = zc143ac72mipi_set_contrast, + .get_capabilities = zc143ac72mipi_get_capabilities, + .set_pixel_format = zc143ac72mipi_set_pixel_format, + .set_orientation = zc143ac72mipi_set_orientation, +}; + +#define ZC143AC72MIPI_DEVICE_INIT(node_id) \ + static struct zc143ac72mipi_data data##node_id; \ + static const struct zc143ac72mipi_config config##node_id = { \ + .lcdif_base = (LCDIF_Type*)DT_REG_ADDR_BY_IDX(DT_INST_GPARENT(node_id), 0), \ + .mipi_base = (MIPI_DSI_HOST_Type*)DT_REG_ADDR_BY_IDX(DT_INST_GPARENT(node_id), 1), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET(n, reset_gpios), \ + .power_gpio = GPIO_DT_SPEC_INST_GET(n, power_gpios), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(node_id, zc143ac72mipi_init, NULL, &data##node_id, &config##node_id, \ + POST_KERNEL, CONFIG_DISPLAY_INIT_PRIORITY, &zc143ac72mipi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(ZC143AC72MIPI_DEVICE_INIT) diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi index 451491ce28f24..874c9c2256ed9 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi @@ -1078,6 +1078,7 @@ #pwm-cells = <3>; }; + /* lcdif: lcd-controller@480000 { compatible = "nxp,mipi-dbi-dcnano-lcdif"; reg = <0x480000 0x1000>; @@ -1098,6 +1099,7 @@ ulps-control; status = "disabled"; }; + */ acmp: comparator@20b000 { compatible = "nxp,kinetis-acmp"; diff --git a/dts/arm/nxp/nxp_rt7xx_common.dtsi b/dts/arm/nxp/nxp_rt7xx_common.dtsi index e766fc5545114..c9e6970d76a59 100644 --- a/dts/arm/nxp/nxp_rt7xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_common.dtsi @@ -196,6 +196,22 @@ reg = <0xa5000 0x1000>; status = "okay"; }; + + lcdif2: lcdif2@480000 { + compatible = "display-controller"; + reg = <0x480000 0x1f8>, + <0x417000 0x330>; + interrupts = <56 0>, <58 1>; + interrupt-names = "LCDIF-INT", "MIPI-INT"; + status = "disabled"; + + lcdif_target: lcdif_target { + compatible = "display-controller"; + status = "disabled"; + }; + }; + + }; &systick { diff --git a/dts/bindings/display/display,zc143ac72mipi.yaml b/dts/bindings/display/display,zc143ac72mipi.yaml new file mode 100644 index 0000000000000..a3ade8ea8a55e --- /dev/null +++ b/dts/bindings/display/display,zc143ac72mipi.yaml @@ -0,0 +1,8 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP --- + +compatible: "display,zc143ac72mipi" + + diff --git a/dts/bindings/display/mipi,zc143ac72.yml b/dts/bindings/display/mipi,zc143ac72.yml new file mode 100644 index 0000000000000..989079fd6f23f --- /dev/null +++ b/dts/bindings/display/mipi,zc143ac72.yml @@ -0,0 +1,12 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +include: display-controller.yaml + +#properties: +# +# +# +# +# +# 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 e1ecc7c2bcb4a..d05aa875bd4ff 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -148,6 +148,8 @@ set_variable_ifdef(CONFIG_ETH_NXP_IMX_NETC CONFIG_MCUX_COMPONENT_driver set_variable_ifdef(CONFIG_NXP_TMPSNS CONFIG_MCUX_COMPONENT_driver.tempsensor) set_variable_ifdef(CONFIG_OPAMP_MCUX_OPAMP CONFIG_MCUX_COMPONENT_driver.opamp) set_variable_ifdef(CONFIG_OPAMP_MCUX_OPAMP_FAST CONFIG_MCUX_COMPONENT_driver.opamp_fast) +set_variable_ifdef(CONFIG_DISPLAY_ZC143AC72MIPI CONFIG_MCUX_COMPONENT_driver.lcdif) +set_variable_ifdef(CONFIG_DISPLAY_ZC143AC72MIPI CONFIG_MCUX_COMPONENT_driver.mipi_dsi) if(NOT CONFIG_SOC_MIMX9596) set_variable_ifdef(CONFIG_ETH_NXP_IMX_NETC CONFIG_MCUX_COMPONENT_driver.netc_switch) diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000000000..afd6ea1fec263 --- /dev/null +++ b/todo.txt @@ -0,0 +1,268 @@ +/*****************************/ +@NOTE(Emilio): The following presuambly does not need to be copied over + since we can see this in the Hello World example, + thus we can assume these implementations are + already supported in Zephyr + BOARD_ConfigMPU(); + BOARD_InitPins(); + BOARD_BootClockRUN(); + BOARD_InitDebugConsole(); + + Thus, what we actually need to look at in terms of code init is these + functions. + + BOARD_InitAHBSC(); + BOARD_InitPsRamPins_Xspi2(); + BOARD_Init16bitsPsRam(XSPI2); + BOARD_InitMipiPanelPins(); + BOARD_InitMipiTouchPanelPins(); + +@IMPORTANT @TODO(Emilio): I2C is going to be needed for the Touch pins to + work. +@SPEED(Emilio): Until we have the actual display working we will not + worry about I2C. + BOARD_MIPIPanelTouch_I2C_Init(); + +/*****************************/ +@TODO(Emilio): The following are the pins needed for PsRam XSpi2 +@SPEED @INCOMPLETE(Emilio): At the moment we are combining all of the pinctrl + in one pinctrl node. We need to split this into seperate components + based on peripheral. psRam XSPI; LCDIF; MIPI; GPIO; FLEXCOMM; + RESET_ClearPeripheralReset(kIOPCTL2_RST_SHIFT_RSTn); + + //@NOTE(Emilio): 0x41 + const uint32_t psram_config = ( + IOPCTL_PIO_FUNC1 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Disable input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Normal drive */ + IOPCTL_PIO_DRIVE_100OHM | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); + + IOPCTL_PinMuxSet(4U, 0U, psram_config); + IOPCTL_PinMuxSet(4U, 1U, psram_config); + IOPCTL_PinMuxSet(4U, 2U, psram_config); + IOPCTL_PinMuxSet(4U, 3U, psram_config); + IOPCTL_PinMuxSet(4U, 4U, psram_config); + IOPCTL_PinMuxSet(4U, 5U, psram_config); + IOPCTL_PinMuxSet(4U, 6U, psram_config); + IOPCTL_PinMuxSet(4U, 7U, psram_config); + IOPCTL_PinMuxSet(4U, 8U, psram_config); + IOPCTL_PinMuxSet(4U, 9U, psram_config); + IOPCTL_PinMuxSet(4U, 10U, psram_config); + IOPCTL_PinMuxSet(4U, 11U, psram_config); + IOPCTL_PinMuxSet(4U, 12U, psram_config); + IOPCTL_PinMuxSet(4U, 13U, psram_config); + IOPCTL_PinMuxSet(4U, 14U, psram_config); + IOPCTL_PinMuxSet(4U, 15U, psram_config); + IOPCTL_PinMuxSet(4U, 16U, psram_config); + IOPCTL_PinMuxSet(4U, 17U, psram_config); + IOPCTL_PinMuxSet(4U, 18U, psram_config); + IOPCTL_PinMuxSet(4U, 19U, psram_config); + IOPCTL_PinMuxSet(4U, 20U, psram_config); + + +/*****************************/ +@TODO(Emilio): In order to program the custom LUT inside the PSRam code we + should look into +@IMPORTANT @TODO(Emilio): According to above, you might need to enable + XSPI2 which is the third instance of xspi + + C:\NXP\mcuxsdk-core\mcuxpresso-sdk\mcusdk\examples\_boards\mimxrt700evk\board.c:495 func -> BOARD_Init16bitsPsRam + +/*****************************/ +@TODO(Emilio): The following is the pins doing the IO to the display. + They are GPIO pins + + //@NOTE(Emilio): 0x0 + const uint32_t display_config_0 = (/* Pin is configured as GPIO1_IO10 */ + IOPCTL_PIO_FUNC0 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Disable input buffer function */ + IOPCTL_PIO_INBUF_DI | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Normal drive */ + IOPCTL_PIO_FULLDRIVE_DI | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); + /* PORT1 PIN10 (coords: T2) is configured as GPIO1_IO10 */ + IOPCTL_PinMuxSet(1U, 10U, display_config_0); + IOPCTL_PinMuxSet(1U, 14U, port1_pin14_config); + IOPCTL_PinMuxSet(3U, 4U, port3_pin4_config); + + //@NOTE(Emilio): 0x40 + const uint32_t display_config_1 = (/* Pin is configured as GPIO3_IO5 */ + IOPCTL_PIO_FUNC0 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enable input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Normal drive */ + IOPCTL_PIO_FULLDRIVE_DI | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); + IOPCTL_PinMuxSet(3U, 5U, display_config_1); + + +//@COMPLETE +@NOTE(Emilio): At the bottom do not forget to enable the clock during start + up code. + CLOCK_EnableClock(kCLOCK_Gpio1); + CLOCK_EnableClock(kCLOCK_Gpio3); + RESET_PeripheralReset(kGPIO1_RST_SHIFT_RSTn); + RESET_PeripheralReset(kGPIO3_RST_SHIFT_RSTn); + + +/*****************************/ +@TODO(Emilio): The following is what will be needed to enable the touch pins + seems to be a combo of flexcomm pins and GPIO pins. + + //@NOTE(Emilio): 0x475 + const uint32_t port0_pin6_config = (/* Pin is configured as LP_FLEXCOMM8_P0 */ + IOPCTL_PIO_FUNC5 | + /* Enable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_EN | + /* Enable pull-up function */ + IOPCTL_PIO_PULLUP_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Normal drive */ + IOPCTL_PIO_FULLDRIVE_DI | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is enabled */ + IOPCTL_PIO_PSEDRAIN_EN | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); + /* PORT0 PIN6 (coords: J5) is configured as LP_FLEXCOMM8_P0 */ + IOPCTL_PinMuxSet(0U, 6U, port0_pin6_config); + + //@NOTE(Emilio): 0x455 + const uint32_t port0_pin7_config = (/* Pin is configured as LP_FLEXCOMM8_P1 */ + IOPCTL_PIO_FUNC5 | + /* Enable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_EN | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Normal drive */ + IOPCTL_PIO_FULLDRIVE_DI | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is enabled */ + IOPCTL_PIO_PSEDRAIN_EN | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); + /* PORT0 PIN7 (coords: K5) is configured as LP_FLEXCOMM8_P1 */ + IOPCTL_PinMuxSet(0U, 7U, port0_pin7_config); + + //@NOTE(Emilio): 0x70 + const uint32_t port1_pin13_config = (/* Pin is configured as GPIO. */ + IOPCTL_PIO_FUNC0 | + /* Enable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_EN | + /* Enable pull-up function */ + IOPCTL_PIO_PULLUP_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Normal drive */ + IOPCTL_PIO_FULLDRIVE_DI | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); + /* PORT0 PIN7 (coords: K5) is configured as GPIO. */ + IOPCTL_PinMuxSet(1U, 13U, port1_pin13_config); + + //@NOTE(Emilio): 0x30 + const uint32_t port3_pin8_config = (/* Pin is configured as GPIO. */ + IOPCTL_PIO_FUNC0 | + /* Enable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_EN | + /* Enable pull-down function */ + IOPCTL_PIO_PULLUP_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_DI | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Normal drive */ + IOPCTL_PIO_FULLDRIVE_DI | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); + /* PORT0 PIN7 (coords: K5) is configured as GPIO. */ + IOPCTL_PinMuxSet(3U, 8U, port3_pin8_config); +} + +/*****************************/ +@IMPORTANT @NOTE(Emilio): We are currently skipping lv_init, since we think + it is mostly init for middleware code and nothing to deal with + the actual display, may need to look at this again. + + +/*****************************/ +/* Put frame buffer in PSRAM */ +#define DEMO_BUFFER0_ADDR 0x60000000U +#define DEMO_BUFFER1_ADDR 0x60200000U +#define DEMO_PANEL_WIDTH 800U // 480 +#define DEMO_PANEL_HEIGHT 480U // 466 +#define DEMO_BUFFER_BYTE_PER_PIXEL 2 +//@NOTE(Emilio): According to doc, square because of circular screen +#define DEMO_FB_WIDTH (DEMO_PANEL_WIDTH) // 466 +#define DEMO_FB_HEIGHT (DEMO_PANEL_HEIGHT) // 466 +// 960 +#define DEMO_BUFFER_STRIDE_BYTE DEMO_FB_WIDTH * DEMO_BUFFER_BYTE_PER_PIXEL +// 447360 +#define DEMO_FB_SIZE (DEMO_BUFFER_STRIDE_BYTE * DEMO_FB_HEIGHT) + + +/*****************************/ +@TODO(Emilio): See if initially we need vglite support, since it + is GPU acceleration...I think, see if we need to enable + VGLITE support before enabling the display support. + + +/*****************************/ +@IMPORTANT @NOTE(Emilio): It seems that majority of the display init support + is located in examples\_boards\mimxrt700evk\display_support.c + in func BOARD_PrepareDisplayController() + From 581c3ec11f9c460fa1036ea8921c0d084e22f5a5 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 8 Oct 2025 15:07:24 -0500 Subject: [PATCH 02/16] Finally got to a building staged after fighting devicetree and bindings. --- .../mimxrt700_evk_mimxrt798s_cm33_cpu0.dts | 10 +- .../mimxrt700_evk_mimxrt798s_cm33_cpu0.conf | 2 + ...mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay | 18 + .../zc143ac72mipi/zc143ac72mipi.overlay | 62 +++- drivers/display/CMakeLists.txt | 2 +- drivers/display/Kconfig | 2 +- .../{Kconfig.zc143ac72mipi => Kconfig.co5300} | 8 +- ...splay_zc143ac72mipi.c => display_co5300.c} | 315 ++++++++++++++---- dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi | 2 - dts/arm/nxp/nxp_rt7xx_common.dtsi | 16 - dts/bindings/display/chipone,co5300.yaml | 36 ++ .../display/display,zc143ac72mipi.yaml | 8 - .../mcux/mcux-sdk-ng/drivers/drivers.cmake | 3 +- 13 files changed, 372 insertions(+), 112 deletions(-) create mode 100644 boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf create mode 100644 boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay rename drivers/display/{Kconfig.zc143ac72mipi => Kconfig.co5300} (51%) rename drivers/display/{display_zc143ac72mipi.c => display_co5300.c} (64%) create mode 100644 dts/bindings/display/chipone,co5300.yaml delete mode 100644 dts/bindings/display/display,zc143ac72mipi.yaml diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts index 3a6959c33b484..d35762b53e52f 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts @@ -34,7 +34,7 @@ zephyr,sram = &sram0; zephyr,console = &flexcomm0_lpuart0; zephyr,shell-uart = &flexcomm0_lpuart0; -// zephyr,display = &lcdif; + zephyr,display = &lcdif; }; leds { @@ -269,9 +269,9 @@ nxp_mipi_i2c: &flexcomm8_lpi2c8 {}; -//zephyr_mipi_dsi: &mipi_dsi {}; +zephyr_mipi_dsi: &mipi_dsi {}; -//zephyr_lcdif: &lcdif {}; +zephyr_lcdif: &lcdif {}; &gpio0 { status = "okay"; @@ -424,7 +424,3 @@ p3t1755dp_ard_i2c_interface: &flexcomm8_lpi2c8 {}; &pca9422 { status = "okay"; }; - -&lcdif2 { - status = "okay"; -}; diff --git a/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf b/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf new file mode 100644 index 0000000000000..768bb57bef212 --- /dev/null +++ b/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf @@ -0,0 +1,2 @@ +CONFIG_REGULATOR=y +CONFIG_DCACHE=n diff --git a/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay b/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay new file mode 100644 index 0000000000000..e4a3ddd27205c --- /dev/null +++ b/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay @@ -0,0 +1,18 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&zephyr_lcdif { + status = "okay"; + clock-frequency = <279000000>; + wr-period = <14>; + wr-assert = <6>; + wr-deassert = <13>; + cs-assert = <1>; + cs-deassert = <4>; +}; diff --git a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay index 9714d1535c573..ca294346790ef 100644 --- a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay +++ b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay @@ -4,22 +4,66 @@ * SPDX-License-Identifier: Apache-2.0 */ -/* #include */ - / { chosen { - zephyr,display = &zc143ac72mipi; + zephyr,display = &co5300_zc143ac72mipi; +/* zephyr,touch = &ft3267_g1120b0mipi;*/ + }; + + /* + en_mipi_display_g1120b0mipi: enable-mipi-display { + compatible = "regulator-fixed"; + regulator-name = "en_mipi_display"; + enable-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; + */ + + /* + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&ft3267_g1120b0mipi>; + display = <&rm67162_g1120b0mipi>; + invert-y; + }; + */ +}; + +/* +&nxp_mipi_i2c { + status = "okay"; + + ft3267_g1120b0mipi: ft3267@38 { + /* + * Note- the actual controller present on this IC is a FT3267, + * but the FT35336 driver in Zephyr supports this IC. + */ + /* + compatible = "focaltech,ft5336"; + reg = <0x38>; + int-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; + reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_LOW>; }; }; +*/ -&lcdif_target { +&zephyr_mipi_dsi { status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - zc143ac72mipi: zc143ac72mipi@0 { - compatible = "display,zc143ac72mipi"; - reg = <0>; + autoinsert-eotp; + phy-clock = <316800000>; + + co5300_zc143ac72mipi: co5300@0 { status = "okay"; + compatible = "chipone,co5300"; + reg = <0x0>; + reset-gpios = <&nxp_mipi_connector 21 GPIO_ACTIVE_HIGH>; + backlight-gpios = <&nxp_mipi_connector 0 GPIO_ACTIVE_HIGH>; + tear-effect-gpios = <&nxp_mipi_connector 22 GPIO_ACTIVE_HIGH>; + power-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; + data-lanes = <1>; + width = <466>; + height = <466>; + pixel-format = ; }; }; diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index 82b738d840e55..5c10decc943a8 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -43,7 +43,7 @@ zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_GLCDC display_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_ILI9806E_DSI display_ili9806e_dsi.c) zephyr_library_sources_ifdef(CONFIG_ST7701 display_st7701.c) zephyr_library_sources_ifdef(CONFIG_LPM013M126 display_lpm013m126.c) -zephyr_library_sources_ifdef(CONFIG_DISPLAY_ZC143AC72MIPI display_zc143ac72mipi.c) +zephyr_library_sources_ifdef(CONFIG_CO5300 display_co5300.c) zephyr_library_sources_ifdef(CONFIG_MICROBIT_DISPLAY mb_display.c diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index 83e3906134fc6..fa4c0623b2a03 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -60,6 +60,6 @@ source "drivers/display/Kconfig.renesas_ra" source "drivers/display/Kconfig.ili9806e_dsi" source "drivers/display/Kconfig.st7701" source "drivers/display/Kconfig.lpm013m126" -source "drivers/display/Kconfig.zc143ac72mipi" +source "drivers/display/Kconfig.co5300" endif # DISPLAY diff --git a/drivers/display/Kconfig.zc143ac72mipi b/drivers/display/Kconfig.co5300 similarity index 51% rename from drivers/display/Kconfig.zc143ac72mipi rename to drivers/display/Kconfig.co5300 index a0bc41134fde7..09859813a540b 100644 --- a/drivers/display/Kconfig.zc143ac72mipi +++ b/drivers/display/Kconfig.co5300 @@ -2,12 +2,14 @@ # SPDX-License-Identifier: Apache-2.0 -menuconfig DISPLAY_ZC143AC72MIPI +config CO5300 bool "MCUX ---" default y + select MIPI_DSI + depends on DT_HAS_CHIPONE_CO5300_ENABLED help --- -if DISPLAY_ZC143AC72MIPI -endif # DISPLAY_ZC143AC72MIPI +if CO5300 +endif # CO5300 diff --git a/drivers/display/display_zc143ac72mipi.c b/drivers/display/display_co5300.c similarity index 64% rename from drivers/display/display_zc143ac72mipi.c rename to drivers/display/display_co5300.c index e7c54dd15e79c..eb323f5611f96 100644 --- a/drivers/display/display_zc143ac72mipi.c +++ b/drivers/display/display_co5300.c @@ -6,29 +6,44 @@ //@IMPORTANT @INCOMPLETE(Emilio): None of the function are checking for errors at the moment! -#define DT_DRV_COMPAT display_zc143ac72mipi +#define DT_DRV_COMPAT chipone_co5300 #include -//LOG_MODULE_REGISTER(zc143ac72mipi, CONFIG_DISPLAY_LOG_LEVEL); +//LOG_MODULE_REGISTER(co5300, CONFIG_DISPLAY_LOG_LEVEL); #include #include #include +#include +#include #include #include -#include #include #include -//#include "zc143ac72mipi_regs.h" +/******TEMP CODE********/ +#include +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int32_t b32; +/******END OF TEMP CODE********/ + +//#include "co5300_regs.h" + +/******OLD CODE********/ static struct display_cmds { uint8_t *cmd_code; uint8_t size; }; -struct zc143ac72mipi_config { +#if 0 +struct co5300_config { LCDIF_Type *lcdif_base; MIPI_DSI_HOST_Type *mipi_base; enum display_pixel_format initial_pixel_format; @@ -37,18 +52,51 @@ struct zc143ac72mipi_config { const struct gpio_dt_spec mipi_te_gpio; }; -struct zc143ac72mipi_data { +struct co5300_data { int Placeholder; }; +#endif + +/******END OF OLD CODE********/ + + +static struct co5300_config { + const struct device *mipi_dsi; + const struct gpio_dt_spec reset_gpio; + const struct gpio_dt_spec backlight_gpio; + const struct gpio_dt_spec tear_effect_gpio; + const struct gpio_dt_spec power_gpio; + uint16_t panel_width; + uint16_t panel_height; + uint16_t channel; + uint16_t num_of_lanes; +}; +static struct co5300_data { + enum display_pixel_format pixel_format; + uint8_t bytes_per_pixel; + struct gpio_callback te_gpio_cb; + struct k_sem te_sem; +}; + +const struct display_cmds lcm_init_settings[] = { + {{0xFE, 0x20}, 2}, {{0xF4, 0x5A}, 2}, + {{0xF5, 0x59}, 2}, {{0xFE, 0x40}, 2}, + {{0x96, 0x00}, 2}, {{0xC9, 0x00}, 2}, + {{0xFE, 0x00}, 2}, {{0x35, 0x00}, 2}, + {{0x53, 0x20}, 2}, {{0x51, 0xFF}, 2}, + {{0x63, 0xFF}, 2}, {{0x2A, 0x00, 0x06, 0x01, 0xD7}, 5}, + {{0x2B, 0x00, 0x00, 0x01, 0xD1}, 5} +}; //@IMPORTANT(Emilio): We may need to be more particular on how to choose the txDataType, there seems // to be many definitions. -static int zc143ac72mipi_write_cmd_codes(const struct device *dev, +static int co5300_write_cmd_codes(const struct device *dev, const struct display_cmds *cmds) { - const struct zc143ac72mipi_config *config = dev->config; - MIPI_DSI_HOST_Type *mipi_base = config->mipi_base; +#if 0 + const struct co5300_config *config = dev->config; + MIPI_DSI_HOST_Type *mipi_base = config->mipi_dsi; dsi_transfer_t transfer_config = {}; for (int iter = 0; iter < ARRAY_SIZE(cmds); iter++) @@ -82,27 +130,44 @@ static int zc143ac72mipi_write_cmd_codes(const struct device *dev, transfer_config.txSize = cmds[iter]->size; DSI_TransferBlocking(mipi_base, &transfer_config); } +#endif } -static int zc143ac72mipi_blanking_on(const struct device *dev) +static int co5300_blanking_on(const struct device *dev) { } -static int zc143ac72mipi_blanking_off(const struct device *dev) +static int co5300_blanking_off(const struct device *dev) { } -static int zc143ac72mipi_write(const struct device *dev, +static int co5300_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, const void *buf) { - const struct zc143ac72mipi_config *config = dev->config; - LCDIF_Type *lcdif_base = config->lcdif_base; - MIPI_DSI_HOST_Type *mipi_base = config->mipi_base; - enum display_pixel_format pixel_format = config->initial_pixel_format; + + const struct co5300_config *config = dev->config; + struct co5300_data *data = dev->data; + struct device *mipi_base = config->mipi_dsi; + enum display_pixel_format pixel_format = data->pixel_format; + + 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; + mdev.pixfmt = data->pixel_format; + + 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 0 @@ -192,34 +257,34 @@ static int zc143ac72mipi_write(const struct device *dev, } -static int zc143ac72mipi_read(const struct device *dev, +static int co5300_read(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, void *buf) { } -static int zc143ac72mipi_clear(const struct device *dev) +static int co5300_clear(const struct device *dev) { } -static void *zc143ac72mipi_get_framebuffer(const struct device *dev) +static void *co5300_get_framebuffer(const struct device *dev) { } -static int zc143ac72mipi_set_brightness(const struct device *dev, uint8_t) +static int co5300_set_brightness(const struct device *dev, uint8_t) { } -static int zc143ac72mipi_set_contrast(const struct device *dev, uint8_t contrast) +static int co5300_set_contrast(const struct device *dev, uint8_t contrast) { } -static void zc143ac72mipi_get_capabilities(const struct device *dev, +static void co5300_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { capabilities->x_resolution = 256; @@ -232,7 +297,7 @@ static void zc143ac72mipi_get_capabilities(const struct device *dev, // capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; } -static int zc143ac72mipi_set_pixel_format(const struct device *dev, +static int co5300_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { //@NOTE(Emilio): The following is how you set the pixel format for the MIPI_DSI @@ -244,15 +309,17 @@ static int zc143ac72mipi_set_pixel_format(const struct device *dev, } -static int zc143ac72mipi_set_orientation(const struct device *dev, +static int co5300_set_orientation(const struct device *dev, const enum display_orientation orientation) { } -static int zc143ac72mipi_init(const struct device *dev) +static int co5300_init(const struct device *dev) { - const struct zc143ac72mipi_config *config = dev->config; +/******OLD CODE********/ +#if 0 + const struct co5300_config *config = dev->config; LCDIF_Type *lcdif_base = config->lcdif_base; MIPI_DSI_HOST_Type *mipi_base = config->mipi_base; enum display_pixel_format pixel_format = config->initial_pixel_format; @@ -362,16 +429,7 @@ static int zc143ac72mipi_init(const struct device *dev) //@NOTE(Emilio): Set LCM Init Settings //@HARDCODE(Emilio): Comes straight from components/video/display/c05300/fsl_co5300.c - const display_cmds lcm_init_settings[] = { - {{0xFE, 0x20}, 2}, {{0xF4, 0x5A}, 2}, - {{0xF5, 0x59}, 2}, {{0xFE, 0x40}, 2}, - {{0x96, 0x00}, 2}, {{0xC9, 0x00}, 2}, - {{0xFE, 0x00}, 2}, {{0x35, 0x00}, 2}, - {{0x53, 0x20}, 2}, {{0x51, 0xFF}, 2}, - {{0x63, 0xFF}, 2}, {{0x2A, 0x00, 0x06, 0x01, 0xD7}, 5}, - {{0x2B, 0x00, 0x00, 0x01, 0xD1}, 5} - }; - zc143ac72mipi_write_cmd_codes(dev, lcm_init_settings); + co5300_write_cmd_codes(dev, lcm_init_settings); display_cmds pixel_setting_cmd = {{0x36, 0x0}, 2}; @@ -379,7 +437,7 @@ static int zc143ac72mipi_init(const struct device *dev) { pixel_setting_cmd.cmd_code[1] = 0x8; } - zc143ac72mipi_write_cmd_codes(dev, pixel_setting_cmd); + co5300_write_cmd_codes(dev, pixel_setting_cmd); @@ -394,7 +452,7 @@ static int zc143ac72mipi_init(const struct device *dev) dbi_pixel_format |= 2; } display_cmds pixel_foramt_cmd = {{0x3A, pixel_format_cmd}, 2}; - zc143ac72mipi_write_cmd_codes(dev, pixel_setting_cmd); + co5300_write_cmd_codes(dev, pixel_setting_cmd); //@TODO(Emilio): Again, unsure why we attempt a sleep in SDK. @@ -405,7 +463,7 @@ static int zc143ac72mipi_init(const struct device *dev) // Entering sleep CMD is 0x10 // Exiting sleep CMD is 0x11 display_cmds exit_sleep_cmd = {{0x11}, 1}; - zc143ac72mipi_write_cmd_codes(dev, exit_sleep_cmd); + co5300_write_cmd_codes(dev, exit_sleep_cmd); //@TODO(Emilio): Again, unsure why we attempt a sleep in SDK. // co5300_DelayMs(150); @@ -413,7 +471,7 @@ static int zc143ac72mipi_init(const struct device *dev) //@NOTE(Emilio): Turn on Display. display_cmds exit_sleep_cmd = {{0x29}, 1}; - zc143ac72mipi_write_cmd_codes(dev, exit_sleep_cmd); + co5300_write_cmd_codes(dev, exit_sleep_cmd); //@NOTE(Emilio): SDK Setups a callback at this point for FrameDoneCallback @@ -579,32 +637,163 @@ static int zc143ac72mipi_init(const struct device *dev) //@NOTE(Emilio): Finally done! return 0; +#endif +/******END OF OLD CODE********/ + struct co5300_config *config = dev->config; + struct co5300_data *data = dev->data; + u32 iter; + u32 Result = 1; + enum display_pixel_format zephyr_pixel_format; + const struct mipi_device *mipi_device = config->mipi_dsi; + +#if 0 + //@TODO(Emilio): Coming from display_rm67162 unsure if + // api requires this dual attachment paradigm. + ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); + if (ret < 0) { + LOG_ERR("Could not attach to MIPI-DSI host"); + return ret; + } +#endif + if (config->power_gpio.port != NULL) { + int ret = gpio_pin_configure_dt(&config->power_gpio, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + // LOG_ERR("Could not configure power GPIO (%d)", ret); + return ret; + } + + //@NOTE(Emilio): Power On Sequence + ret = gpio_pin_set_dt(&config->power_gpio, 1); + if (ret < 0) { + // LOG_ERR("Could not pull power high (%d)", ret); + return ret; + } + + k_sleep(K_MSEC(100)); + + 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; + } + + ret = gpio_pin_set_dt(&config->reset_gpio, 0); + if (ret < 0) { + // LOG_ERR("Could not pull reset low (%d)", ret); + return ret; + } + + k_sleep(K_MSEC(1)); + gpio_pin_set_dt(&config->reset_gpio, 1); + if (ret < 0) { + // LOG_ERR("Could not pull reset high (%d)", ret); + return ret; + } + k_sleep(K_MSEC(150)); + } + } + + int cmd = 0; + int param = 0; + /* Set the LCM init settings. */ + for (int i = 0; i < ARRAY_SIZE(lcm_init_settings); i++) { + //@TODO(Emilio): rename and make correct cmds + cmd = lcm_init_settings[i].cmd_code; + param = lcm_init_settings[i].size; + int ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + cmd, ¶m, 1); + if (ret < 0) { + return ret; + } + } + + /* Set pixel format */ + if (data->pixel_format == MIPI_DSI_PIXFMT_RGB888) { + param = MIPI_DCS_PIXEL_FORMAT_24BIT; + data->bytes_per_pixel = 3; + } else if (data->pixel_format == MIPI_DSI_PIXFMT_RGB565) { + param = MIPI_DCS_PIXEL_FORMAT_16BIT; + data->bytes_per_pixel = 2; + } else { + /* Unsupported pixel format */ +// LOG_ERR("Pixel format not supported"); + return -ENOTSUP; + } + int ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PIXEL_FORMAT, ¶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)); } -static DEVICE_API(display, zc143ac72mipi_driver_api) = { - .blanking_on = zc143ac72mipi_blanking_on, - .blanking_off = zc143ac72mipi_blanking_off, - .write = zc143ac72mipi_write, - .read = zc143ac72mipi_read, - .clear = zc143ac72mipi_clear, - .get_framebuffer = zc143ac72mipi_get_framebuffer, - .set_brightness = zc143ac72mipi_set_brightness, - .set_contrast = zc143ac72mipi_set_contrast, - .get_capabilities = zc143ac72mipi_get_capabilities, - .set_pixel_format = zc143ac72mipi_set_pixel_format, - .set_orientation = zc143ac72mipi_set_orientation, +static DEVICE_API(display, co5300_api) = { + .blanking_on = co5300_blanking_on, + .blanking_off = co5300_blanking_off, + .write = co5300_write, + .read = co5300_read, + .clear = co5300_clear, + .get_framebuffer = co5300_get_framebuffer, + .set_brightness = co5300_set_brightness, + .set_contrast = co5300_set_contrast, + .get_capabilities = co5300_get_capabilities, + .set_pixel_format = co5300_set_pixel_format, + .set_orientation = co5300_set_orientation, }; -#define ZC143AC72MIPI_DEVICE_INIT(node_id) \ - static struct zc143ac72mipi_data data##node_id; \ - static const struct zc143ac72mipi_config config##node_id = { \ - .lcdif_base = (LCDIF_Type*)DT_REG_ADDR_BY_IDX(DT_INST_GPARENT(node_id), 0), \ - .mipi_base = (MIPI_DSI_HOST_Type*)DT_REG_ADDR_BY_IDX(DT_INST_GPARENT(node_id), 1), \ - .reset_gpio = GPIO_DT_SPEC_INST_GET(n, reset_gpios), \ - .power_gpio = GPIO_DT_SPEC_INST_GET(n, power_gpios), \ +/******OLD CODE********/ +#if 0 +#define CO5300_DEVICE_INIT(node_id) \ + static struct co5300_data co5300_data##node_id; \ + static const struct co5300_config co5300_config##node_id = { \ + .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(node_id)), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, reset_gpios, {0}), \ + .bl_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, bl_gpios, {0}), \ + .te_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, te_gpios, {0}), \ }; \ \ - DEVICE_DT_INST_DEFINE(node_id, zc143ac72mipi_init, NULL, &data##node_id, &config##node_id, \ - POST_KERNEL, CONFIG_DISPLAY_INIT_PRIORITY, &zc143ac72mipi_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(ZC143AC72MIPI_DEVICE_INIT) + DEVICE_DT_INST_DEFINE(node_id, co5300_init, NULL, \ + &co5300_data##node_id, &co5300_config##node_id, \ + POST_KERNEL, CONFIG_DISPLAY_INIT_PRIORITY, &co5300_driver_api); +#endif +/******END OF OLD CODE********/ + + +#define CO5300_DEVICE_INIT(node_id) \ + static const struct co5300_config co5300_config_##node_id = { \ + .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(node_id)), \ + .num_of_lanes = DT_INST_PROP_BY_IDX(node_id, data_lanes, 0), \ + .channel = DT_INST_REG_ADDR(node_id), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, reset_gpios, {0}), \ + .backlight_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, backlight_gpios, {0}), \ + .tear_effect_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, tear_effect_gpios, {0}), \ + .panel_width = DT_INST_PROP(node_id, width), \ + .panel_height = DT_INST_PROP(node_id, height), \ + }; \ + static struct co5300_data co5300_data_##node_id = { \ + }; \ + DEVICE_DT_INST_DEFINE(node_id, \ + &co5300_init, \ + 0, \ + &co5300_data_##node_id, \ + &co5300_config_##node_id, \ + POST_KERNEL, \ + CONFIG_APPLICATION_INIT_PRIORITY, \ + &co5300_api); + + +DT_INST_FOREACH_STATUS_OKAY(CO5300_DEVICE_INIT) diff --git a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi index 874c9c2256ed9..451491ce28f24 100644 --- a/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_cm33_cpu0.dtsi @@ -1078,7 +1078,6 @@ #pwm-cells = <3>; }; - /* lcdif: lcd-controller@480000 { compatible = "nxp,mipi-dbi-dcnano-lcdif"; reg = <0x480000 0x1000>; @@ -1099,7 +1098,6 @@ ulps-control; status = "disabled"; }; - */ acmp: comparator@20b000 { compatible = "nxp,kinetis-acmp"; diff --git a/dts/arm/nxp/nxp_rt7xx_common.dtsi b/dts/arm/nxp/nxp_rt7xx_common.dtsi index c9e6970d76a59..e766fc5545114 100644 --- a/dts/arm/nxp/nxp_rt7xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt7xx_common.dtsi @@ -196,22 +196,6 @@ reg = <0xa5000 0x1000>; status = "okay"; }; - - lcdif2: lcdif2@480000 { - compatible = "display-controller"; - reg = <0x480000 0x1f8>, - <0x417000 0x330>; - interrupts = <56 0>, <58 1>; - interrupt-names = "LCDIF-INT", "MIPI-INT"; - status = "disabled"; - - lcdif_target: lcdif_target { - compatible = "display-controller"; - status = "disabled"; - }; - }; - - }; &systick { diff --git a/dts/bindings/display/chipone,co5300.yaml b/dts/bindings/display/chipone,co5300.yaml new file mode 100644 index 0000000000000..6a4240d050c52 --- /dev/null +++ b/dts/bindings/display/chipone,co5300.yaml @@ -0,0 +1,36 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP --- + +compatible: "chipone,co5300" + +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. + + backlight-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. + + tear-effect-gpios: + type: phandle-array + description: | + The tearing effect pin is asserted by the controller at a display + VSYNC interval. This permits the controller to send new display + data during a VSYNC interval, removing tearing. + + power-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. + + diff --git a/dts/bindings/display/display,zc143ac72mipi.yaml b/dts/bindings/display/display,zc143ac72mipi.yaml deleted file mode 100644 index a3ade8ea8a55e..0000000000000 --- a/dts/bindings/display/display,zc143ac72mipi.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2025 NXP -# SPDX-License-Identifier: Apache-2.0 - -description: NXP --- - -compatible: "display,zc143ac72mipi" - - 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 d05aa875bd4ff..ec34aae753a07 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -141,6 +141,7 @@ set_variable_ifdef(CONFIG_INPUT_MCUX_KPP CONFIG_MCUX_COMPONENT_driver.kpp set_variable_ifdef(CONFIG_DMA_NXP_EDMA CONFIG_MCUX_COMPONENT_driver.edma_soc_rev2) set_variable_ifdef(CONFIG_COUNTER_MCUX_SNVS_SRTC CONFIG_MCUX_COMPONENT_driver.snvs_lp) set_variable_ifdef(CONFIG_DISPLAY_MCUX_DCNANO_LCDIF CONFIG_MCUX_COMPONENT_driver.lcdif) +set_variable_ifdef(CONFIG_DISPLAY_CO5300 CONFIG_MCUX_COMPONENT_driver.lcdif) set_variable_ifdef(CONFIG_MIPI_DBI_NXP_DCNANO_LCDIF CONFIG_MCUX_COMPONENT_driver.lcdif) set_variable_ifdef(CONFIG_MIPI_DBI_NXP_FLEXIO_LCDIF CONFIG_MCUX_COMPONENT_driver.flexio_mculcd) set_variable_ifdef(CONFIG_VIDEO_MCUX_MIPI_CSI2RX CONFIG_MCUX_COMPONENT_driver.mipi_csi2rx) @@ -148,8 +149,6 @@ set_variable_ifdef(CONFIG_ETH_NXP_IMX_NETC CONFIG_MCUX_COMPONENT_driver set_variable_ifdef(CONFIG_NXP_TMPSNS CONFIG_MCUX_COMPONENT_driver.tempsensor) set_variable_ifdef(CONFIG_OPAMP_MCUX_OPAMP CONFIG_MCUX_COMPONENT_driver.opamp) set_variable_ifdef(CONFIG_OPAMP_MCUX_OPAMP_FAST CONFIG_MCUX_COMPONENT_driver.opamp_fast) -set_variable_ifdef(CONFIG_DISPLAY_ZC143AC72MIPI CONFIG_MCUX_COMPONENT_driver.lcdif) -set_variable_ifdef(CONFIG_DISPLAY_ZC143AC72MIPI CONFIG_MCUX_COMPONENT_driver.mipi_dsi) if(NOT CONFIG_SOC_MIMX9596) set_variable_ifdef(CONFIG_ETH_NXP_IMX_NETC CONFIG_MCUX_COMPONENT_driver.netc_switch) From 10940c8ca5e43e8a1f27c87389532374dd496582 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Thu, 9 Oct 2025 11:18:17 -0500 Subject: [PATCH 03/16] adding reference for the rest of the api, also removed the old code reference from the init function Signed-off-by: Emilio Benavente --- drivers/display/display_co5300.c | 468 ++++++------------------------- 1 file changed, 79 insertions(+), 389 deletions(-) diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index eb323f5611f96..d6c535e9d6c59 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -9,7 +9,7 @@ #define DT_DRV_COMPAT chipone_co5300 #include -//LOG_MODULE_REGISTER(co5300, CONFIG_DISPLAY_LOG_LEVEL); +LOG_MODULE_REGISTER(co5300, CONFIG_DISPLAY_LOG_LEVEL); #include #include @@ -79,68 +79,30 @@ static struct co5300_data { struct k_sem te_sem; }; -const struct display_cmds lcm_init_settings[] = { - {{0xFE, 0x20}, 2}, {{0xF4, 0x5A}, 2}, - {{0xF5, 0x59}, 2}, {{0xFE, 0x40}, 2}, - {{0x96, 0x00}, 2}, {{0xC9, 0x00}, 2}, - {{0xFE, 0x00}, 2}, {{0x35, 0x00}, 2}, - {{0x53, 0x20}, 2}, {{0x51, 0xFF}, 2}, - {{0x63, 0xFF}, 2}, {{0x2A, 0x00, 0x06, 0x01, 0xD7}, 5}, - {{0x2B, 0x00, 0x00, 0x01, 0xD1}, 5} -}; - -//@IMPORTANT(Emilio): We may need to be more particular on how to choose the txDataType, there seems -// to be many definitions. -static int co5300_write_cmd_codes(const struct device *dev, - const struct display_cmds *cmds) -{ -#if 0 - const struct co5300_config *config = dev->config; - MIPI_DSI_HOST_Type *mipi_base = config->mipi_dsi; - dsi_transfer_t transfer_config = {}; - - for (int iter = 0; iter < ARRAY_SIZE(cmds); iter++) - { - switch(cmds[iter]->size) - { - case 0: - { - //@TODO(Emilio): Error case. - - } break; - - case 1: - { - transfer_config.txDataType = kDSI_TxDataDcsShortWrNoParam; - } break; - - case 2: - { - transfer_config.txDataType = kDSI_TxDataDcsShortWrOneParam; - - } break; - - default - { - transfer_config.txDataType = kDSI_TxDataDcsLongWr; - } - } +u8* lcm_init_cmds = 0xFE20F45AF559FE409600C900FE003500532051FF63FF2A000601D72B000001D1; +#define LCM_INIT_CMD_BYTE_COUNT 32 - transfer_config.txData = cmds[iter]->cmd_code; - transfer_config.txSize = cmds[iter]->size; - DSI_TransferBlocking(mipi_base, &transfer_config); - } -#endif -} static int co5300_blanking_on(const struct device *dev) { + const struct co5300_config *config = dev->config; + if (config->backlight_gpio.port != NULL) { + return gpio_pin_set_dt(&config->backlight_gpio, 0); + } else { + return -ENOTSUP; + } } static int co5300_blanking_off(const struct device *dev) { + const struct co5300_config *config = dev->config; + if (config->backlight_gpio.port != NULL) { + return gpio_pin_set_dt(&config->backlight_gpio, 1); + } else { + return -ENOTSUP; + } } static int co5300_write(const struct device *dev, @@ -287,6 +249,8 @@ static int co5300_set_contrast(const struct device *dev, uint8_t contrast) static void co5300_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { +#if 0 +/******OLD CODE********/ capabilities->x_resolution = 256; capabilities->y_resolution = 466; //@TODO(Emilio): capabilities->pixel_formats = PIXEL_FORMAT_*** | *** | ***; @@ -295,350 +259,72 @@ static void co5300_get_capabilities(const struct device *dev, //@TODO(Emilio): Find the screen info here. // capabilities->current_pixel_format = PXIEL_FORMAT_RGB_565; // capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; +/******END OF OLD CODE********/ +#endif + + const struct co5300_config *config = dev->config; + const struct co5300_data *data = dev->data; + + memset(capabilities, 0, sizeof(struct display_capabilities)); + capabilities->x_resolution = config->panel_width; + capabilities->y_resolution = config->panel_height; + capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | + PIXEL_FORMAT_RGB_888; + switch (data->pixel_format) { + case MIPI_DSI_PIXFMT_RGB565: + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_565; + break; + case MIPI_DSI_PIXFMT_RGB888: + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_888; + break; + default: + LOG_WRN("Unsupported display format"); + /* Other display formats not implemented */ + break; + } + capabilities->current_orientation = DISPLAY_ORIENTATION_ROTATED_90; + } static int co5300_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { - //@NOTE(Emilio): The following is how you set the pixel format for the MIPI_DSI - // base->CFG_DBI_PIXEL_FIFO_SEND_LEVEL = (u32)sendLevel; //@NOTE(Emilio): Found in - // drivers/mipi_dsi/fsl_mipi_dsi.h - // also - // base->CFG_DBI_PIXEL_FORMAT - // LCDIF_SetFrameBufferConfig(***); + const struct co5300_config *config = dev->config; + struct co5300_data *data = dev->data; + uint8_t param; + + switch (pixel_format) { + case PIXEL_FORMAT_RGB_565: + data->pixel_format = MIPI_DSI_PIXFMT_RGB565; + param = MIPI_DCS_PIXEL_FORMAT_16BIT; + data->bytes_per_pixel = 2; + break; + case PIXEL_FORMAT_RGB_888: + data->pixel_format = MIPI_DSI_PIXFMT_RGB888; + param = MIPI_DCS_PIXEL_FORMAT_24BIT; + data->bytes_per_pixel = 3; + break; + default: + /* Other display formats not implemented */ + return -ENOTSUP; + } + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); } static int co5300_set_orientation(const struct device *dev, const enum display_orientation orientation) { - + if (orientation == DISPLAY_ORIENTATION_NORMAL) { + return 0; + } + LOG_ERR("Changing display orientation not implemented"); + return -ENOTSUP; } static int co5300_init(const struct device *dev) { -/******OLD CODE********/ -#if 0 - const struct co5300_config *config = dev->config; - LCDIF_Type *lcdif_base = config->lcdif_base; - MIPI_DSI_HOST_Type *mipi_base = config->mipi_base; - enum display_pixel_format pixel_format = config->initial_pixel_format; - - //@HARDCODE @INCOMPLETE(Emilio): All the values here are hardcoded from display_support.c - //@NOTE(Emilio): Enable MIPI - dsi_config_t dsiConfig; - DSI_GetDefaultConfig(&dsiConfig); - dsiConfig.numLanes = 1; - dsiConfig.autoInsertEoTp = true; - DSI_Init(mipi_base, &dsiConfig); - - uint32_t mipiDsiDphyBitClkFreq_Hz = CLOCK_GetMipiDphyClkFreq(); - uint32_t mipiDsiTxEscClkFreq_Hz = CLOCK_GetMipiDphyEscTxClkFreq(); - - dsi_dphy_config_t dphyConfig; - DSI_GetDphyDefaultConfig(&dphyConfig, mipiDsiDphyBitClkFreq_Hz, mipiDsiTxEscClkFreq_Hz); - DSI_InitDphy(mipi_base, &dphyConfig, 0); - - //@HARDCODE(Emilio): Not sure what 64 does here. - DSI_SetDbiPixelFifoSendLevel(mipi_base, 64U); - DSI_SetDbiPixelFormat(mipi_base, kDSI_DbiRGB565); - - - - //@NOTE(Emilio): Enable LCDIF - - /* DBI configurations. */ - lcdif_dbi_config_t dbi_config; - LCDIF_DbiModeGetDefaultConfig(&dbi_config); - dbi_config.acTimeUnit = 0; - dbi_config.writeWRPeriod = 14U; - - /* With 279.53MHz source and 16bpp format, a 14 cycle period requires a 279.53MHz / 14 * 16 = 319.46Mhz DPHY clk - * source. */ - if (pixel_format == PIXEL_FORMAT_RGB_565) - { - dbi_config.format = kLCDIF_DbiOutD16RGB565; - } - else - { - dbi_config.format = kLCDIF_DbiOutD16RGB888Option1; - } - dbi_config.type = kLCDIF_DbiTypeB; - dbi_config.writeCSAssert = 1; - dbi_config.writeCSDeassert = 4; - dbi_config.writeWRAssert = (dbi_config.writeWRPeriod - 1U) / 2U; /* Asset at the middle. */ - dbi_config.writeWRDeassert = (dbi_config.writeWRPeriod - 1U); /* Deassert at the end */ - - LCDIF_Init(lcdif_base); - LCDIF_DbiModeSetConfig(lcdif_base, 0, &dbi_config); - - lcdif_panel_config_t lcdif_config; - LCDIF_PanelGetDefaultConfig(&lcdif_config); - if (pixel_format == PIXEL_FORMAT_RGB_565) - { - lcdif_config.endian = kLCDIF_HalfWordSwap; - } - - LCDIF_SetPanelConfig(lcdif_base, 0, &lcdif_config); - - //@TODO(Emilio): Add irq_config func here. - - - //@NOTE(Emilio): Init LCDIF Controller - LCDIF_EnableInterrupts(lcdif_base, kLCDIF_Display0FrameDoneInterrupt | kLCDIF_PanelUnderflowInterrupt); - - - //@NOTE(Emilio): Init LCDIF Panel - - //@IMPORTANT @INCOMPLETE(Emilio): Check that we configure these gpio correctly, polarity - gpio_pin_configure_dt(&config->power_gpio, GPIO_OUTPUT_LOW); - //@SPEED @HARDCODE(Emilio): Hardcode GPIO to HIGH to bypass sdk steps. - gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_HIGH); - gpio_pin_configure_dt(&config->mipi_te_gpio, GPIO_OUTPUT_LOW); - -#if 0 - //@IMPORTANT(Emilio): Check to see if these interrupts get set. - GPIO_SetPinInterruptConfig(BOARD_MIPI_TE_GPIO, BOARD_MIPI_TE_PIN, kGPIO_InterruptRisingEdge); - GPIO_SetPinInterruptChannel(BOARD_MIPI_TE_GPIO, BOARD_MIPI_TE_PIN, kGPIO_InterruptOutput0); -#endif - - //@IMPORTANT @INCOMPLETE(Emilio): Ensure These GPIOs NVICs are enabled correctly. - - - - //@NOTE(Emilio): Init LCDIF Panel -#if 0 - //@INCOMPLETE @NOTE(Emilio): This Should be done at compile time in DEVICE_INIT - handle->height = FSL_VIDEO_EXTRACT_HEIGHT(config->resolution); - handle->width = FSL_VIDEO_EXTRACT_WIDTH(config->resolution); - handle->pixelFormat = config->pixelFormat; - - @TODO(Emilio): Why does SDK have this sequence of gpio toggles?? - @NOTE(Emilio): BTW -> gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_HIGH); - /* Power on. */ - resource->pullPowerPin(true); - co5300_DelayMs(100); - - /* Perform reset. */ - resource->pullResetPin(false); - co5300_DelayMs(1); - resource->pullResetPin(true); - co5300_DelayMs(150); -#endif - - //@NOTE(Emilio): Set LCM Init Settings - - //@HARDCODE(Emilio): Comes straight from components/video/display/c05300/fsl_co5300.c - co5300_write_cmd_codes(dev, lcm_init_settings); - - - display_cmds pixel_setting_cmd = {{0x36, 0x0}, 2}; - if (config->pixelFormat != kVIDEO_PixelFormatRGB565) - { - pixel_setting_cmd.cmd_code[1] = 0x8; - } - co5300_write_cmd_codes(dev, pixel_setting_cmd); - - - - /* Set pixel format. */ - //@HARDCODE @NOTE(Emilio): Eventually we will make defines in a header file - // the Most sig bits are for the dpi pixel_format the Least sig bits - // are for the dbi pixel format, just the abi for the command code. - // The two valid pixel formats are 0x77 or 0x75 hints the |= 2. - char pixel_format_cmd = (7 << 4) | 5; - if ((kVIDEO_PixelFormatXRGB8888 == config->pixelFormat) || (kVIDEO_PixelFormatRGB888 == config->pixelFormat)) - { - dbi_pixel_format |= 2; - } - display_cmds pixel_foramt_cmd = {{0x3A, pixel_format_cmd}, 2}; - co5300_write_cmd_codes(dev, pixel_setting_cmd); - - - //@TODO(Emilio): Again, unsure why we attempt a sleep in SDK. -// co5300_DelayMs(50); - - - //@TODO(Emilio): Part of the definitions. - // Entering sleep CMD is 0x10 - // Exiting sleep CMD is 0x11 - display_cmds exit_sleep_cmd = {{0x11}, 1}; - co5300_write_cmd_codes(dev, exit_sleep_cmd); - - //@TODO(Emilio): Again, unsure why we attempt a sleep in SDK. -// co5300_DelayMs(150); - - - //@NOTE(Emilio): Turn on Display. - display_cmds exit_sleep_cmd = {{0x29}, 1}; - co5300_write_cmd_codes(dev, exit_sleep_cmd); - - - //@NOTE(Emilio): SDK Setups a callback at this point for FrameDoneCallback - //@NOTE(Emilio): The SDK also has a helper function to get size in bits based on - // Pixel Format, might be a good idea. - - - //@NOTE(Emilio): More set Pixel Format but for LCDIF -#if 0 - lcdif_fb_config_t fbConfig; - dbi_lcdif_prv_data_t *prvData = (dbi_lcdif_prv_data_t *)dbiIface->prvData; - lcdif_layer_input_order_t componentOrder; - lcdif_fb_format_t pixelFormat; - - status = DBI_LCDIF_GetPixelFormat(format, &pixelFormat, &componentOrder); - //@NOTE(Emilio): The nested for loop is GetPixelFormat - for (int i = 0; i < ARRAY_SIZE(s_lcdifPixelFormatMap); i++) - { - if (s_lcdifPixelFormatMap[i].videoFormat == input) - { - *output = s_lcdifPixelFormatMap[i].lcdifFormat; - *order = s_lcdifPixelFormatMap[i].componentOrder; - return kStatus_Success; - } - } - - - LCDIF_FrameBufferGetDefaultConfig(&fbConfig); - fbConfig.format = pixelFormat; - fbConfig.inOrder = componentOrder; - LCDIF_SetFrameBufferConfig(lcdif, 0, &fbConfig); - - /* Set byte per pixel for stride calculation later. */ - //@NOTE(Emilio): VIDEO_** is the helper function mentioned above. - prvData->bytePerPixel = VIDEO_GetPixelSizeBits(format) / 8U; -#endif - - - //@NOTE(Emilio): SDK Then selects Area? -#if 0 - uint8_t data[4]; - status_t status; - - /*Column addresses*/ - data[0] = (startX >> 8) & 0xFF; - data[1] = startX & 0xFF; - data[2] = (endX >> 8) & 0xFF; - data[3] = endX & 0xFF; - - status = DBI_IFACE_WriteCmdData(dbiIface, kMIPI_DBI_SetColumnAddress, data, 4); - - if (status != kStatus_Success) - { - return status; - } - - /*Page addresses*/ - data[0] = (startY >> 8) & 0xFF; - data[1] = startY & 0xFF; - data[2] = (endY >> 8) & 0xFF; - data[3] = endY & 0xFF; - - status = DBI_IFACE_WriteCmdData(dbiIface, kMIPI_DBI_SetPageAddress, data, 4); - - //@NOTE(Emilio): DBI_IFACE_WriteCmdData - if ((len_byte != 0U) && (data == NULL)) - { - return kStatus_Fail; - } - - uint8_t cmd = (uint8_t)command; - uint8_t *pData = (uint8_t *)data; - dbi_lcdif_prv_data_t *prvData = (dbi_lcdif_prv_data_t *)dbiIface->prvData; - LCDIF_Type *lcdif = prvData->lcdif; - - /* If the command is set address, calculate the selected area size, since LCDIF needs these info for configuration. - */ - if ((cmd == (uint8_t)kMIPI_DBI_SetColumnAddress) || (cmd == (uint8_t)kMIPI_DBI_SetPageAddress)) - { - uint16_t lrValue = ((uint16_t)pData[2] << 8U) | (uint16_t)pData[3]; - uint16_t tpValue = ((uint16_t)pData[0] << 8U) | (uint16_t)pData[1]; - - if (lrValue < tpValue) - { - return kStatus_Fail; - } - - if (cmd == kMIPI_DBI_SetColumnAddress) - { - prvData->width = lrValue - tpValue + 1U; - } - else - { - prvData->height = lrValue - tpValue + 1U; - } - } - - LCDIF_DbiSendCommand(lcdif, 0U, cmd); - if (len_byte != 0U) - { - LCDIF_DbiSendData(lcdif, 0U, pData, len_byte); - } - -#endif - - //@NOTE(Emilio): At this point the SDK sets up a callback for BufferSwitchOff - // Creates a semaphore - // and clears an area of memory to use as the framebuffer. - - - - //@NOTE(Emilio): Turning on the LCDIF -#if 0 - uint8_t cmd = (on ? kMIPI_DBI_SetDisplayOn : kMIPI_DBI_SetDisplayOff); - dbiIface->xferOps->writeCommandData(dbiIface, cmd, NULL, 0); - - //@NOTE(Emilio): The following code is writeCommmandData - if ((len_byte != 0U) && (data == NULL)) - { - return kStatus_Fail; - } - - uint8_t cmd = (uint8_t)command; - uint8_t *pData = (uint8_t *)data; - dbi_lcdif_prv_data_t *prvData = (dbi_lcdif_prv_data_t *)dbiIface->prvData; - LCDIF_Type *lcdif = prvData->lcdif; - - /* If the command is set address, calculate the selected area size, since LCDIF needs these info for configuration. - */ - if ((cmd == (uint8_t)kMIPI_DBI_SetColumnAddress) || (cmd == (uint8_t)kMIPI_DBI_SetPageAddress)) - { - uint16_t lrValue = ((uint16_t)pData[2] << 8U) | (uint16_t)pData[3]; - uint16_t tpValue = ((uint16_t)pData[0] << 8U) | (uint16_t)pData[1]; - - if (lrValue < tpValue) - { - return kStatus_Fail; - } - - if (cmd == kMIPI_DBI_SetColumnAddress) - { - prvData->width = lrValue - tpValue + 1U; - } - else - { - prvData->height = lrValue - tpValue + 1U; - } - } - - LCDIF_DbiSendCommand(lcdif, 0U, cmd); - - if (len_byte != 0U) - { - LCDIF_DbiSendData(lcdif, 0U, pData, len_byte); - } -#endif - - - - - //@NOTE(Emilio): The SDK Now starts to init VGLite, probably not needed on our side. - //@NOTE(Emilio): The SDK Then enables the touchscreen via I2C. - - //@NOTE(Emilio): Finally done! - return 0; -#endif -/******END OF OLD CODE********/ struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; u32 iter; @@ -647,7 +333,7 @@ static int co5300_init(const struct device *dev) const struct mipi_device *mipi_device = config->mipi_dsi; #if 0 - //@TODO(Emilio): Coming from display_rm67162 unsure if + //@TODO(Emilio): Coming from display_co5300 unsure if // api requires this dual attachment paradigm. ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); if (ret < 0) { @@ -694,21 +380,25 @@ static int co5300_init(const struct device *dev) } } - int cmd = 0; - int param = 0; + int ret = 0; + struct display_cmds lcm_init_settings= {}; + lcm_init_settings.cmd_code = lcm_init_cmds; + lcm_init_settings.size = LCM_INIT_CMD_BYTE_COUNT; /* Set the LCM init settings. */ - for (int i = 0; i < ARRAY_SIZE(lcm_init_settings); i++) { + //for (int i = 0; i < ARRAY_SIZE(lcm_init_settings); i++) { + for (int i = 0; i < 10; i++) { //@TODO(Emilio): rename and make correct cmds - cmd = lcm_init_settings[i].cmd_code; - param = lcm_init_settings[i].size; + /* int ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, cmd, ¶m, 1); + */ if (ret < 0) { return ret; } } /* Set pixel format */ + int param = 0; if (data->pixel_format == MIPI_DSI_PIXFMT_RGB888) { param = MIPI_DCS_PIXEL_FORMAT_24BIT; data->bytes_per_pixel = 3; @@ -720,7 +410,7 @@ static int co5300_init(const struct device *dev) // LOG_ERR("Pixel format not supported"); return -ENOTSUP; } - int ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); if (ret < 0) { return ret; From b459556e24d0334926d80c105a830597873d66d9 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Thu, 9 Oct 2025 11:58:49 -0500 Subject: [PATCH 04/16] Added some changes to remove warning and make a clean build Signed-off-by: Emilio Benavente --- drivers/display/display_co5300.c | 85 +++++++++++++++++--------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index d6c535e9d6c59..faba2a6e118f5 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -36,31 +36,12 @@ typedef int32_t b32; //#include "co5300_regs.h" -/******OLD CODE********/ -static struct display_cmds { +struct display_cmds { uint8_t *cmd_code; uint8_t size; }; -#if 0 struct co5300_config { - LCDIF_Type *lcdif_base; - MIPI_DSI_HOST_Type *mipi_base; - enum display_pixel_format initial_pixel_format; - const struct gpio_dt_spec reset_gpio; - const struct gpio_dt_spec power_gpio; - const struct gpio_dt_spec mipi_te_gpio; -}; - -struct co5300_data { - int Placeholder; -}; -#endif - -/******END OF OLD CODE********/ - - -static struct co5300_config { const struct device *mipi_dsi; const struct gpio_dt_spec reset_gpio; const struct gpio_dt_spec backlight_gpio; @@ -72,14 +53,17 @@ static struct co5300_config { uint16_t num_of_lanes; }; -static struct co5300_data { +struct co5300_data { enum display_pixel_format pixel_format; uint8_t bytes_per_pixel; struct gpio_callback te_gpio_cb; struct k_sem te_sem; }; -u8* lcm_init_cmds = 0xFE20F45AF559FE409600C900FE003500532051FF63FF2A000601D72B000001D1; +u8 lcm_init_cmds[] = {0xFE, 0x20, 0xF4, 0x5A, 0xF5, 0x59, 0xFE, 0x40, 0x96, + 0x00, 0xC9, 0x00, 0xFE, 0x00, 0x35, 0x00, 0x53, 0x20, 0x51, + 0xFF, 0x63, 0xFF, 0x2A, 0x00, 0x06, 0x01, 0xD7, + 0x2B, 0x00, 0x00, 0x01, 0xD1}; #define LCM_INIT_CMD_BYTE_COUNT 32 @@ -113,24 +97,25 @@ static int co5300_write(const struct device *dev, const struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; - struct device *mipi_base = config->mipi_dsi; - enum display_pixel_format pixel_format = data->pixel_format; +// const struct device *mipi_base = config->mipi_dsi; +// enum display_pixel_format pixel_format = data->pixel_format; struct mipi_dsi_device mdev = {0}; - int ret; - uint32_t i; - uint8_t cmd, param; + int ret = 0; /* Attach to MIPI DSI host */ mdev.data_lanes = config->num_of_lanes; mdev.pixfmt = data->pixel_format; + /* ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); + */ if (ret < 0) { //LOG_ERR("Could not attach to MIPI-DSI host"); return ret; } + return 0; #if 0 uint8_t cmd = (uint8_t)command; @@ -223,27 +208,27 @@ static int co5300_read(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, void *buf) { - + return 0; } static int co5300_clear(const struct device *dev) { - + return 0; } static void *co5300_get_framebuffer(const struct device *dev) { - + return 0; } static int co5300_set_brightness(const struct device *dev, uint8_t) { - + return 0; } static int co5300_set_contrast(const struct device *dev, uint8_t contrast) { - + return 0; } static void co5300_get_capabilities(const struct device *dev, @@ -263,14 +248,16 @@ static void co5300_get_capabilities(const struct device *dev, #endif const struct co5300_config *config = dev->config; - const struct co5300_data *data = dev->data; +// const struct co5300_data *data = dev->data; memset(capabilities, 0, sizeof(struct display_capabilities)); capabilities->x_resolution = config->panel_width; capabilities->y_resolution = config->panel_height; capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | PIXEL_FORMAT_RGB_888; - switch (data->pixel_format) { +// switch (data->pixel_format) { + //@INCOMPLETE @HARDCODE(Emilio): Fix this later. + switch (MIPI_DSI_PIXFMT_RGB565) { case MIPI_DSI_PIXFMT_RGB565: capabilities->current_pixel_format = PIXEL_FORMAT_RGB_565; break; @@ -289,7 +276,7 @@ static void co5300_get_capabilities(const struct device *dev, static int co5300_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { - const struct co5300_config *config = dev->config; +// const struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; uint8_t param; @@ -308,8 +295,11 @@ static int co5300_set_pixel_format(const struct device *dev, /* Other display formats not implemented */ return -ENOTSUP; } + /* return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); + */ + return 0; } @@ -325,12 +315,12 @@ static int co5300_set_orientation(const struct device *dev, static int co5300_init(const struct device *dev) { - struct co5300_config *config = dev->config; + const struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; - u32 iter; - u32 Result = 1; - enum display_pixel_format zephyr_pixel_format; - const struct mipi_device *mipi_device = config->mipi_dsi; +// u32 iter; +// u32 Result = 1; +// enum display_pixel_format zephyr_pixel_format; +// const struct mipi_device *mipi_device = config->mipi_dsi; #if 0 //@TODO(Emilio): Coming from display_co5300 unsure if @@ -386,8 +376,14 @@ static int co5300_init(const struct device *dev) lcm_init_settings.size = LCM_INIT_CMD_BYTE_COUNT; /* Set the LCM init settings. */ //for (int i = 0; i < ARRAY_SIZE(lcm_init_settings); i++) { - for (int i = 0; i < 10; i++) { + u8* curr_cmd = lcm_init_settings.cmd_code; + for (int i = 0; i < lcm_init_settings.size;) { //@TODO(Emilio): rename and make correct cmds + u8 cmd_code = *curr_cmd++; + i++; + u8 param = *curr_cmd++; + i++; + param++; cmd_code++; /* int ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, cmd, ¶m, 1); @@ -410,16 +406,21 @@ static int co5300_init(const struct device *dev) // LOG_ERR("Pixel format not supported"); return -ENOTSUP; } + /* ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_PIXEL_FORMAT, ¶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; } @@ -429,6 +430,8 @@ static int co5300_init(const struct device *dev) * 120 ms before sending that command. To be safe, delay 150ms */ k_sleep(K_MSEC(150)); + + return 0; } static DEVICE_API(display, co5300_api) = { From 2d33cb86ab64c75f3d3d68dcfc42e736bd320046 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Fri, 10 Oct 2025 06:21:50 -0500 Subject: [PATCH 05/16] removed my confortable version of type definitions and cleared some ci flags --- drivers/display/display_co5300.c | 428 ++++++++++++++++--------------- 1 file changed, 218 insertions(+), 210 deletions(-) diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index faba2a6e118f5..7050144de4ddb 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -//@IMPORTANT @INCOMPLETE(Emilio): None of the function are checking for errors at the moment! - #define DT_DRV_COMPAT chipone_co5300 #include @@ -17,25 +15,12 @@ LOG_MODULE_REGISTER(co5300, CONFIG_DISPLAY_LOG_LEVEL); #include #include #include +#include #include #include #include -/******TEMP CODE********/ -#include -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int32_t b32; -/******END OF TEMP CODE********/ - -//#include "co5300_regs.h" - struct display_cmds { uint8_t *cmd_code; uint8_t size; @@ -54,17 +39,34 @@ struct co5300_config { }; struct co5300_data { - enum display_pixel_format pixel_format; + uint8_t pixel_format; uint8_t bytes_per_pixel; - struct gpio_callback te_gpio_cb; - struct k_sem te_sem; + struct gpio_callback tear_effect_gpio_cb; + struct k_sem tear_effect_sem; }; -u8 lcm_init_cmds[] = {0xFE, 0x20, 0xF4, 0x5A, 0xF5, 0x59, 0xFE, 0x40, 0x96, - 0x00, 0xC9, 0x00, 0xFE, 0x00, 0x35, 0x00, 0x53, 0x20, 0x51, - 0xFF, 0x63, 0xFF, 0x2A, 0x00, 0x06, 0x01, 0xD7, - 0x2B, 0x00, 0x00, 0x01, 0xD1}; -#define LCM_INIT_CMD_BYTE_COUNT 32 +/* Organized in MIPI_CMD | SIZE OF MIPI PARAM | MIPI PARAM */ +uint8_t lcm_init_cmds[] = { 0xFE, 0x1, 0x20, + 0xF4, 0x1, 0x5A, + 0xF5, 0x1, 0x59, + 0xFE, 0x1, 0x40, + 0x96, 0x1, 0x00, + 0xC9, 0x1, 0x00, + 0xFE, 0x1, 0x00, + 0x35, 0x1, 0x00, + 0x53, 0x1, 0x20, + 0x51, 0x1, 0xFF, + 0x63, 0x1, 0xFF, + 0x2A, 0x4, 0x00, 0x06, 0x01, 0xD7, + 0x2B, 0x4, 0x00, 0x00, 0x01, 0xD1}; + +static void co5300_tear_effect_isr_handler(const struct device* gpio_dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct co5300_data *data = CONTAINER_OF(cb, struct co5300_data, tear_effect_gpio_cb); + + k_sem_give(&data->tear_effect_sem); +} static int co5300_blanking_on(const struct device *dev) @@ -89,118 +91,120 @@ static int co5300_blanking_off(const struct device *dev) } } +/* Helper to write framebuffer data to co5300 via MIPI interface. */ +static int co5300_write_fb(const struct device *dev, bool first_write, + const uint8_t *src, const struct display_buffer_descriptor *desc) +{ + const struct co5300_config *config = dev->config; + struct co5300_data *data = dev->data; + ssize_t wlen; + struct mipi_dsi_msg msg = {0}; + uint8_t *local_src = (uint8_t *)src; + uint32_t len = desc->height * desc->width * data->bytes_per_pixel; + uint32_t len_sent = 0U; + + /* Note- we need to set custom flags on the DCS message, + * so we bypass the mipi_dsi_dcs_write API + */ + if (first_write) { + msg.cmd = MIPI_DCS_WRITE_MEMORY_START; + } else { + msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; + } + msg.type = MIPI_DSI_DCS_LONG_WRITE; + msg.flags = MCUX_DSI_2L_FB_DATA; + msg.user_data = (void *)desc; + + while (len > 0) { + msg.tx_len = len; + msg.tx_buf = local_src; + wlen = mipi_dsi_transfer(config->mipi_dsi, config->channel, &msg); + if (wlen < 0) { + return (int)wlen; + } + /* Advance source pointer and decrement remaining */ + if (desc->pitch > desc->width) { + len_sent += wlen; + local_src += wlen + len_sent / (desc->width * data->bytes_per_pixel) * + ((desc->pitch - desc->width) * data->bytes_per_pixel); + } else { + local_src += wlen; + } + len -= wlen; + /* All future commands should use WRITE_MEMORY_CONTINUE */ + msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; + } + return wlen; +} + + + static int co5300_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, const void *buf) { - const struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; -// const struct device *mipi_base = config->mipi_dsi; -// enum display_pixel_format pixel_format = data->pixel_format; + int ret; + uint16_t start, end; + const uint8_t *src; + bool first_cmd; + uint8_t param[4]; - struct mipi_dsi_device mdev = {0}; - int ret = 0; - - /* Attach to MIPI DSI host */ - mdev.data_lanes = config->num_of_lanes; - mdev.pixfmt = data->pixel_format; + LOG_DBG("W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); /* - ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); - */ + * CO5300 runs in MIPI DBI mode. This means we can use command mode + * to write to the video memory buffer on the CO5300 control IC, + * and the IC will update the display automatically. + */ + + /* Set column address of target area */ + /* First two bytes are starting X coordinate */ + start = x; + end = x + desc->width - 1; + sys_put_be16(start, ¶m[0]); + /* Second two bytes are ending X coordinate */ + sys_put_be16(end, ¶m[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_COLUMN_ADDRESS, param, + sizeof(param)); if (ret < 0) { - //LOG_ERR("Could not attach to MIPI-DSI host"); return ret; } - return 0; - -#if 0 - uint8_t cmd = (uint8_t)command; - dbi_lcdif_prv_data_t *prvData = (dbi_lcdif_prv_data_t *)dbiIface->prvData; - uint16_t height = prvData->height; - uint32_t stride; - - if (isInterleave) - { - stride = stride_byte; - } - else - { - stride = (uint32_t)prvData->width * (uint32_t)prvData->bytePerPixel; + /* Set page address of target area */ + /* First two bytes are starting Y coordinate */ + start = y; + end = y + desc->height - 1; + sys_put_be16(start, ¶m[0]); + /* Second two bytes are ending X coordinate */ + sys_put_be16(end, ¶m[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PAGE_ADDRESS, param, + sizeof(param)); + if (ret < 0) { + return ret; } - /* For RGB888 the stride shall be calculated as 4 bytes per pixel. */ - if (prvData->bytePerPixel == 3U) - { - LCDIF_SetFrameBufferStride(lcdif, 0, stride / 3U * 4U); - } - else - { - LCDIF_SetFrameBufferStride(lcdif, 0, stride); - } -#if DBI_USE_MIPI_PANEL - MIPI_DSI_HOST_Type *dsi = prvData->dsi; - uint8_t payloadBytePerPixel; - - if (dsi != NULL) - { - prvData->stride = (uint16_t)stride; - - /* 1 pixel sent in 1 cycle. */ - if (prvData->dsiFormat == kDSI_DbiRGB565) - { - payloadBytePerPixel = 2U; - } - /* 2 pixel sent in 1 cycle. */ - else if (prvData->dsiFormat == kDSI_DbiRGB332) - { - payloadBytePerPixel = 1U; - } - /* 2 pixels sent in 3 cycles. kDSI_DbiRGB888, kDSI_DbiRGB444 and kDSI_DbiRGB666 */ - else - { - payloadBytePerPixel = 3U; - } - - /* If the whole update payload exceeds the DSI max payload size, send the payload in multiple times. */ - if ((prvData->width * prvData->height * payloadBytePerPixel) > MIPI_DSI_MAX_PAYLOAD_SIZE) - { - /* Calculate how may lines to send each time. Make sure each time the buffer address meets the align - * requirement. */ - height = MIPI_DSI_MAX_PAYLOAD_SIZE / prvData->width / (uint16_t)payloadBytePerPixel; - while (((height * prvData->stride) & (LCDIF_FB_ALIGN - 1U)) != 0U) - { - height--; - } - prvData->heightEachWrite = height; - - /* Point the data to the next piece. */ - prvData->data = (uint8_t *)((uint32_t)data + (height * prvData->stride)); - } - - /* Set payload size. */ - DSI_SetDbiPixelPayloadSize(dsi, (height * prvData->width * (uint16_t)payloadBytePerPixel) >> 1U); + /* + * Now, write the framebuffer. If the tearing effect GPIO is present, + * wait until the display controller issues an interrupt (which will + * give to the TE semaphore) before sending the frame + */ + if (config->tear_effect_gpio.port != NULL) { + /* Block sleep state until next TE interrupt so we can send + * frame during that interval + */ + k_sem_take(&data->tear_effect_sem, K_FOREVER); } + src = buf; + first_cmd = true; - /* Update height info. */ - prvData->heightSent = height; -#endif - prvData->height -= height; - - /* Configure buffer position, address and area. */ - LCDIF_SetFrameBufferPosition(lcdif, 0U, 0U, 0U, prvData->width, height); - LCDIF_DbiSelectArea(lcdif, 0, 0, 0, prvData->width - 1U, height - 1U, false); - LCDIF_SetFrameBufferAddr(lcdif, 0, (uint32_t)data); - - /* Send command. */ - LCDIF_DbiSendCommand(lcdif, 0, cmd); + co5300_write_fb(dev, first_cmd, src, desc); - /* Start memory transfer. */ - LCDIF_DbiWriteMem(lcdif, 0); -#endif + return 0; } @@ -234,30 +238,16 @@ static int co5300_set_contrast(const struct device *dev, uint8_t contrast) static void co5300_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { -#if 0 -/******OLD CODE********/ - capabilities->x_resolution = 256; - capabilities->y_resolution = 466; - //@TODO(Emilio): capabilities->pixel_formats = PIXEL_FORMAT_*** | *** | ***; -// capabilities->pixel_formats = PIXEL_FORMAT_RGB_565; - //@TODO(Emilio): capabilities->screen_info = SCREEN_INFO_MONO*** | *** | ***; - //@TODO(Emilio): Find the screen info here. -// capabilities->current_pixel_format = PXIEL_FORMAT_RGB_565; -// capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; -/******END OF OLD CODE********/ -#endif - const struct co5300_config *config = dev->config; -// const struct co5300_data *data = dev->data; + const struct co5300_data *data = dev->data; memset(capabilities, 0, sizeof(struct display_capabilities)); capabilities->x_resolution = config->panel_width; capabilities->y_resolution = config->panel_height; capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | PIXEL_FORMAT_RGB_888; -// switch (data->pixel_format) { - //@INCOMPLETE @HARDCODE(Emilio): Fix this later. - switch (MIPI_DSI_PIXFMT_RGB565) { + + switch (data->pixel_format) { case MIPI_DSI_PIXFMT_RGB565: capabilities->current_pixel_format = PIXEL_FORMAT_RGB_565; break; @@ -270,17 +260,16 @@ static void co5300_get_capabilities(const struct device *dev, break; } capabilities->current_orientation = DISPLAY_ORIENTATION_ROTATED_90; - } static int co5300_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { -// const struct co5300_config *config = dev->config; + const struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; uint8_t param; - switch (pixel_format) { + switch (data->pixel_format) { case PIXEL_FORMAT_RGB_565: data->pixel_format = MIPI_DSI_PIXFMT_RGB565; param = MIPI_DCS_PIXEL_FORMAT_16BIT; @@ -295,10 +284,10 @@ static int co5300_set_pixel_format(const struct device *dev, /* Other display formats not implemented */ return -ENOTSUP; } - /* + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); - */ + return 0; } @@ -317,31 +306,29 @@ static int co5300_init(const struct device *dev) { const struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; -// u32 iter; -// u32 Result = 1; -// enum display_pixel_format zephyr_pixel_format; -// const struct mipi_device *mipi_device = config->mipi_dsi; - -#if 0 - //@TODO(Emilio): Coming from display_co5300 unsure if - // api requires this dual attachment paradigm. - ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); + struct mipi_dsi_device mdev = {0}; + + /* Attach to MIPI DSI host */ + mdev.data_lanes = config->num_of_lanes; + mdev.pixfmt = data->pixel_format; + + int ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); if (ret < 0) { LOG_ERR("Could not attach to MIPI-DSI host"); return ret; } -#endif + + /* Perform GPIO Reset */ if (config->power_gpio.port != NULL) { - int ret = gpio_pin_configure_dt(&config->power_gpio, GPIO_OUTPUT_INACTIVE); + ret = gpio_pin_configure_dt(&config->power_gpio, GPIO_OUTPUT_INACTIVE); if (ret < 0) { - // LOG_ERR("Could not configure power GPIO (%d)", ret); + LOG_ERR("Could not configure power GPIO (%d)", ret); return ret; } - //@NOTE(Emilio): Power On Sequence ret = gpio_pin_set_dt(&config->power_gpio, 1); if (ret < 0) { - // LOG_ERR("Could not pull power high (%d)", ret); + LOG_ERR("Could not pull power high (%d)", ret); return ret; } @@ -350,44 +337,45 @@ static int co5300_init(const struct device *dev) 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); + LOG_ERR("Could not configure reset GPIO (%d)", ret); return ret; } ret = gpio_pin_set_dt(&config->reset_gpio, 0); if (ret < 0) { - // LOG_ERR("Could not pull reset low (%d)", ret); + LOG_ERR("Could not pull reset low (%d)", ret); return ret; } k_sleep(K_MSEC(1)); gpio_pin_set_dt(&config->reset_gpio, 1); if (ret < 0) { - // LOG_ERR("Could not pull reset high (%d)", ret); + LOG_ERR("Could not pull reset high (%d)", ret); return ret; } k_sleep(K_MSEC(150)); } } - int ret = 0; - struct display_cmds lcm_init_settings= {}; - lcm_init_settings.cmd_code = lcm_init_cmds; - lcm_init_settings.size = LCM_INIT_CMD_BYTE_COUNT; /* Set the LCM init settings. */ - //for (int i = 0; i < ARRAY_SIZE(lcm_init_settings); i++) { - u8* curr_cmd = lcm_init_settings.cmd_code; - for (int i = 0; i < lcm_init_settings.size;) { - //@TODO(Emilio): rename and make correct cmds - u8 cmd_code = *curr_cmd++; - i++; - u8 param = *curr_cmd++; - i++; - param++; cmd_code++; - /* - int ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - cmd, ¶m, 1); - */ + struct display_cmds lcm_init_settings = {}; + lcm_init_settings.cmd_code = lcm_init_cmds; + lcm_init_settings.size = ARRAY_SIZE(lcm_init_cmds); + uint8_t* curr_cmd = lcm_init_settings.cmd_code; + + while (curr_cmd != (lcm_init_settings.cmd_code + lcm_init_settings.size)) { + if (curr_cmd > (lcm_init_settings.cmd_code + lcm_init_settings.size)) { + LOG_ERR("Logical error when sending mipi command code."); + return -EILSEQ; + } + + uint32_t cmd_code = (uint32_t)*curr_cmd++; + uint32_t param_size = *curr_cmd++; + uint32_t param = *curr_cmd; + curr_cmd += param_size; + + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + cmd_code, ¶m, param_size); if (ret < 0) { return ret; } @@ -403,13 +391,12 @@ static int co5300_init(const struct device *dev) data->bytes_per_pixel = 2; } else { /* Unsupported pixel format */ -// LOG_ERR("Pixel format not supported"); + LOG_ERR("Pixel format not supported"); return -ENOTSUP; } - /* ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); - */ + if (ret < 0) { return ret; } @@ -417,10 +404,9 @@ static int co5300_init(const struct device *dev) /* 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; } @@ -431,7 +417,46 @@ static int co5300_init(const struct device *dev) */ k_sleep(K_MSEC(150)); - return 0; + /* Setup backlight */ + if (config->backlight_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&config->backlight_gpio, GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure bl GPIO (%d)", ret); + return ret; + } + } + + if (config->tear_effect_gpio.port != NULL) { + /* Setup tear effect pin */ + ret = gpio_pin_configure_dt(&config->tear_effect_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure TE GPIO (%d)", ret); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&config->tear_effect_gpio, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure TE interrupt (%d)", ret); + return ret; + } + + /* Init and install GPIO callback */ + gpio_init_callback(&data->tear_effect_gpio_cb, co5300_tear_effect_isr_handler, + BIT(config->tear_effect_gpio.pin)); + ret = gpio_add_callback(config->tear_effect_gpio.port, &data->tear_effect_gpio_cb); + if (ret < 0) { + LOG_ERR("Could not add TE gpio callback"); + return ret; + } + + /* Setup tear effect pin semaphore */ + k_sem_init(&data->tear_effect_sem, 0, 1); + } + + /* Enable display */ + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_DISPLAY_ON, NULL, 0); } static DEVICE_API(display, co5300_api) = { @@ -448,44 +473,27 @@ static DEVICE_API(display, co5300_api) = { .set_orientation = co5300_set_orientation, }; -/******OLD CODE********/ -#if 0 #define CO5300_DEVICE_INIT(node_id) \ - static struct co5300_data co5300_data##node_id; \ - static const struct co5300_config co5300_config##node_id = { \ - .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(node_id)), \ - .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, reset_gpios, {0}), \ - .bl_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, bl_gpios, {0}), \ - .te_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, te_gpios, {0}), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(node_id, co5300_init, NULL, \ - &co5300_data##node_id, &co5300_config##node_id, \ - POST_KERNEL, CONFIG_DISPLAY_INIT_PRIORITY, &co5300_driver_api); -#endif -/******END OF OLD CODE********/ - - -#define CO5300_DEVICE_INIT(node_id) \ - static const struct co5300_config co5300_config_##node_id = { \ + static const struct co5300_config co5300_config_##node_id = { \ .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(node_id)), \ .num_of_lanes = DT_INST_PROP_BY_IDX(node_id, data_lanes, 0), \ - .channel = DT_INST_REG_ADDR(node_id), \ + .channel = DT_INST_REG_ADDR(node_id), \ .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, reset_gpios, {0}), \ - .backlight_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, backlight_gpios, {0}), \ - .tear_effect_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, tear_effect_gpios, {0}), \ + .backlight_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, backlight_gpios, {0}), \ + .tear_effect_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, tear_effect_gpios, {0}), \ .panel_width = DT_INST_PROP(node_id, width), \ - .panel_height = DT_INST_PROP(node_id, height), \ - }; \ + .panel_height = DT_INST_PROP(node_id, height), \ + }; \ static struct co5300_data co5300_data_##node_id = { \ - }; \ - DEVICE_DT_INST_DEFINE(node_id, \ - &co5300_init, \ - 0, \ + .pixel_format = DT_INST_PROP(node_id, pixel_format), \ + }; \ + DEVICE_DT_INST_DEFINE(node_id, \ + &co5300_init, \ + 0, \ &co5300_data_##node_id, \ - &co5300_config_##node_id, \ - POST_KERNEL, \ - CONFIG_APPLICATION_INIT_PRIORITY, \ + &co5300_config_##node_id, \ + POST_KERNEL, \ + CONFIG_APPLICATION_INIT_PRIORITY, \ &co5300_api); From baf3bee4d4f17ba73f6a02bae7bc16fa8b89f867 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Mon, 13 Oct 2025 00:32:23 -0500 Subject: [PATCH 06/16] Updated comments in code and added if else preproccessor commands prepared to change code. --- drivers/display/display_co5300.c | 238 +++++++++++++++++++++++++++---- 1 file changed, 213 insertions(+), 25 deletions(-) diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index 7050144de4ddb..490694f781b92 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -45,20 +45,20 @@ struct co5300_data { struct k_sem tear_effect_sem; }; -/* Organized in MIPI_CMD | SIZE OF MIPI PARAM | MIPI PARAM */ -uint8_t lcm_init_cmds[] = { 0xFE, 0x1, 0x20, - 0xF4, 0x1, 0x5A, - 0xF5, 0x1, 0x59, - 0xFE, 0x1, 0x40, - 0x96, 0x1, 0x00, - 0xC9, 0x1, 0x00, - 0xFE, 0x1, 0x00, - 0x35, 0x1, 0x00, - 0x53, 0x1, 0x20, - 0x51, 0x1, 0xFF, - 0x63, 0x1, 0xFF, - 0x2A, 0x4, 0x00, 0x06, 0x01, 0xD7, - 0x2B, 0x4, 0x00, 0x00, 0x01, 0xD1}; +/* Organized as MIPI_CMD | SIZE OF MIPI PARAM | MIPI PARAM */ +uint8_t lcm_init_cmds[] = { 0xFE, 0x1, 0x20, + 0xF4, 0x1, 0x5A, + 0xF5, 0x1, 0x59, + 0xFE, 0x1, 0x40, + 0x96, 0x1, 0x00, + 0xC9, 0x1, 0x00, + 0xFE, 0x1, 0x00, + 0x35, 0x1, 0x00, + 0x53, 0x1, 0x20, + 0x51, 0x1, 0xFF, + 0x63, 0x1, 0xFF, + 0x2A, 0x4, 0x00, 0x06, 0x01, 0xD7, + 0x2B, 0x4, 0x00, 0x00, 0x01, 0xD1}; static void co5300_tear_effect_isr_handler(const struct device* gpio_dev, struct gpio_callback *cb, uint32_t pins) @@ -91,7 +91,8 @@ static int co5300_blanking_off(const struct device *dev) } } -/* Helper to write framebuffer data to co5300 via MIPI interface. */ +#if 0 +/* Helper function to write framebuffer data to co5300 via MIPI interface. */ static int co5300_write_fb(const struct device *dev, bool first_write, const uint8_t *src, const struct display_buffer_descriptor *desc) { @@ -136,9 +137,126 @@ static int co5300_write_fb(const struct device *dev, bool first_write, } return wlen; } +#else +/* Helper function to write framebuffer data to co5300 via MIPI interface. */ +static int co5300_write_fb(const struct device *dev, bool first_write, + const uint8_t *src, const struct display_buffer_descriptor *desc) +{ + const struct co5300_config *config = dev->config; + struct co5300_data *data = dev->data; + ssize_t wlen; + struct mipi_dsi_msg msg = {0}; + uint8_t *local_src = (uint8_t *)src; + uint32_t len = desc->height * desc->width * data->bytes_per_pixel; + uint32_t len_sent = 0U; + + /* Note- we need to set custom flags on the DCS message, + * so we bypass the mipi_dsi_dcs_write API + */ + if (first_write) { + msg.cmd = MIPI_DCS_WRITE_MEMORY_START; + } else { + msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; + } + msg.type = MIPI_DSI_DCS_LONG_WRITE; + msg.flags = MCUX_DSI_2L_FB_DATA; + msg.user_data = (void *)desc; + + while (len > 0) { + msg.tx_len = len; + msg.tx_buf = local_src; + wlen = mipi_dsi_transfer(config->mipi_dsi, config->channel, &msg); + if (wlen < 0) { + return (int)wlen; + } + /* Advance source pointer and decrement remaining */ + if (desc->pitch > desc->width) { + len_sent += wlen; + local_src += wlen + len_sent / (desc->width * data->bytes_per_pixel) * + ((desc->pitch - desc->width) * data->bytes_per_pixel); + } else { + local_src += wlen; + } + len -= wlen; + /* All future commands should use WRITE_MEMORY_CONTINUE */ + msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; + } + return wlen; +} +#endif + + + +#if 0 +static int co5300_write(const struct device *dev, + const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, + const void *buf) +{ + const struct co5300_config *config = dev->config; + struct co5300_data *data = dev->data; + int ret; + uint16_t start, end; + const uint8_t *src; + bool first_cmd; + uint8_t param[4]; + + LOG_DBG("W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); + + /* + * CO5300 runs in MIPI DBI mode. This means we can use command mode + * to write to the video memory buffer on the CO5300 control IC, + * and the IC will update the display automatically. + */ + + /* Set column address of target area */ + /* First two bytes are starting X coordinate */ + start = x; + end = x + desc->width - 1; + sys_put_be16(start, ¶m[0]); + /* Second two bytes are ending X coordinate */ + sys_put_be16(end, ¶m[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_COLUMN_ADDRESS, param, + sizeof(param)); + if (ret < 0) { + return ret; + } + + /* Set page address of target area */ + /* First two bytes are starting Y coordinate */ + start = y; + end = y + desc->height - 1; + sys_put_be16(start, ¶m[0]); + /* Second two bytes are ending X coordinate */ + sys_put_be16(end, ¶m[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PAGE_ADDRESS, param, + sizeof(param)); + if (ret < 0) { + return ret; + } + /* + * Now, write the framebuffer. If the tearing effect GPIO is present, + * wait until the display controller issues an interrupt (which will + * give to the TE semaphore) before sending the frame + */ + if (config->tear_effect_gpio.port != NULL) { + /* Block sleep state until next TE interrupt so we can send + * frame during that interval + */ + k_sem_take(&data->tear_effect_sem, K_FOREVER); + } + src = buf; + first_cmd = true; + co5300_write_fb(dev, first_cmd, src, desc); + return 0; + +} +#else static int co5300_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, @@ -207,6 +325,7 @@ static int co5300_write(const struct device *dev, return 0; } +#endif static int co5300_read(const struct device *dev, const uint16_t x, const uint16_t y, @@ -235,6 +354,7 @@ static int co5300_set_contrast(const struct device *dev, uint8_t contrast) return 0; } +#if 0 static void co5300_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { @@ -261,7 +381,36 @@ static void co5300_get_capabilities(const struct device *dev, } capabilities->current_orientation = DISPLAY_ORIENTATION_ROTATED_90; } +#else +static void co5300_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + const struct co5300_config *config = dev->config; + const struct co5300_data *data = dev->data; + + memset(capabilities, 0, sizeof(struct display_capabilities)); + capabilities->x_resolution = config->panel_width; + capabilities->y_resolution = config->panel_height; + capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | + PIXEL_FORMAT_RGB_888; + switch (data->pixel_format) { + case MIPI_DSI_PIXFMT_RGB565: + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_565; + break; + case MIPI_DSI_PIXFMT_RGB888: + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_888; + break; + default: + LOG_WRN("Unsupported display format"); + /* Other display formats not implemented */ + break; + } + capabilities->current_orientation = DISPLAY_ORIENTATION_ROTATED_90; +} +#endif + +#if 0 static int co5300_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { @@ -291,7 +440,49 @@ static int co5300_set_pixel_format(const struct device *dev, return 0; } +#else +static int co5300_set_pixel_format(const struct device *dev, + const enum display_pixel_format pixel_format) +{ + const struct co5300_config *config = dev->config; + struct co5300_data *data = dev->data; + uint8_t param; + + switch (data->pixel_format) { + case PIXEL_FORMAT_RGB_565: + data->pixel_format = MIPI_DSI_PIXFMT_RGB565; + param = MIPI_DCS_PIXEL_FORMAT_16BIT; + data->bytes_per_pixel = 2; + break; + case PIXEL_FORMAT_RGB_888: + data->pixel_format = MIPI_DSI_PIXFMT_RGB888; + param = MIPI_DCS_PIXEL_FORMAT_24BIT; + data->bytes_per_pixel = 3; + break; + default: + /* Other display formats not implemented */ + return -ENOTSUP; + } + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); + + return 0; + +} +#endif + +#if 0 +static int co5300_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ + if (orientation == DISPLAY_ORIENTATION_NORMAL) { + return 0; + } + LOG_ERR("Changing display orientation not implemented"); + return -ENOTSUP; +} +#else static int co5300_set_orientation(const struct device *dev, const enum display_orientation orientation) { @@ -301,6 +492,7 @@ static int co5300_set_orientation(const struct device *dev, LOG_ERR("Changing display orientation not implemented"); return -ENOTSUP; } +#endif static int co5300_init(const struct device *dev) { @@ -401,20 +593,16 @@ static int co5300_init(const struct device *dev) return ret; } - /* Delay 50 ms before exiting sleep mode */ + /* Command the display to enter 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 - */ + + + /* Commands after the monitor is directed to go to sleep should be delayed 150ms */ k_sleep(K_MSEC(150)); /* Setup backlight */ @@ -426,8 +614,8 @@ static int co5300_init(const struct device *dev) } } + /* Setup tear effect pin */ if (config->tear_effect_gpio.port != NULL) { - /* Setup tear effect pin */ ret = gpio_pin_configure_dt(&config->tear_effect_gpio, GPIO_INPUT); if (ret < 0) { LOG_ERR("Could not configure TE GPIO (%d)", ret); @@ -450,7 +638,7 @@ static int co5300_init(const struct device *dev) return ret; } - /* Setup tear effect pin semaphore */ + /* Setup semaphore for using the tear effect pin */ k_sem_init(&data->tear_effect_sem, 0, 1); } From 378b23f227401a392bf184bb1655ef748d227dfd Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Mon, 13 Oct 2025 01:23:58 -0500 Subject: [PATCH 07/16] Init function done. --- drivers/display/display_co5300.c | 45 +++++++++++++++----------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index 490694f781b92..beece46c45413 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -21,6 +21,7 @@ LOG_MODULE_REGISTER(co5300, CONFIG_DISPLAY_LOG_LEVEL); #include #include +/* display command structure passed to mipi to control the display */ struct display_cmds { uint8_t *cmd_code; uint8_t size; @@ -499,11 +500,16 @@ static int co5300_init(const struct device *dev) const struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; struct mipi_dsi_device mdev = {0}; + struct display_cmds lcm_init_settings = {0}; + uint8_t* ptr_to_curr_cmd = 0; + uint8_t* ptr_to_last_cmd = 0; + uint8_t cmd_params = 0; + uint8_t cmd_param_size = 0; + uint8_t curr_cmd = 0; /* Attach to MIPI DSI host */ mdev.data_lanes = config->num_of_lanes; mdev.pixfmt = data->pixel_format; - int ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); if (ret < 0) { LOG_ERR("Could not attach to MIPI-DSI host"); @@ -550,36 +556,30 @@ static int co5300_init(const struct device *dev) } /* Set the LCM init settings. */ - struct display_cmds lcm_init_settings = {}; lcm_init_settings.cmd_code = lcm_init_cmds; lcm_init_settings.size = ARRAY_SIZE(lcm_init_cmds); - uint8_t* curr_cmd = lcm_init_settings.cmd_code; - - while (curr_cmd != (lcm_init_settings.cmd_code + lcm_init_settings.size)) { - if (curr_cmd > (lcm_init_settings.cmd_code + lcm_init_settings.size)) { - LOG_ERR("Logical error when sending mipi command code."); - return -EILSEQ; - } - - uint32_t cmd_code = (uint32_t)*curr_cmd++; - uint32_t param_size = *curr_cmd++; - uint32_t param = *curr_cmd; - curr_cmd += param_size; + ptr_to_curr_cmd = lcm_init_settings.cmd_code; + ptr_to_last_cmd = lcm_init_settings.cmd_code + lcm_init_settings.size; + while (ptr_to_curr_cmd < ptr_to_last_cmd) { + /* Walk through the display_cmds array, incrementing the ptr by the param size */ + curr_cmd = *ptr_to_curr_cmd++; + cmd_param_size = *ptr_to_curr_cmd++; + cmd_params = *ptr_to_curr_cmd; + ptr_to_curr_cmd += cmd_param_size; ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - cmd_code, ¶m, param_size); + curr_cmd, &cmd_params, cmd_param_size); if (ret < 0) { return ret; } } /* Set pixel format */ - int param = 0; if (data->pixel_format == MIPI_DSI_PIXFMT_RGB888) { - param = MIPI_DCS_PIXEL_FORMAT_24BIT; + cmd_params = (uint8_t)MIPI_DCS_PIXEL_FORMAT_24BIT; data->bytes_per_pixel = 3; } else if (data->pixel_format == MIPI_DSI_PIXFMT_RGB565) { - param = MIPI_DCS_PIXEL_FORMAT_16BIT; + cmd_params = (uint8_t)MIPI_DCS_PIXEL_FORMAT_16BIT; data->bytes_per_pixel = 2; } else { /* Unsupported pixel format */ @@ -587,8 +587,7 @@ static int co5300_init(const struct device *dev) return -ENOTSUP; } ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); - + MIPI_DCS_SET_PIXEL_FORMAT, &cmd_params, 1); if (ret < 0) { return ret; } @@ -601,8 +600,7 @@ static int co5300_init(const struct device *dev) return ret; } - - /* Commands after the monitor is directed to go to sleep should be delayed 150ms */ + /* After the monitor is directed to go to sleep, commands should be delayed 150ms */ k_sleep(K_MSEC(150)); /* Setup backlight */ @@ -614,7 +612,7 @@ static int co5300_init(const struct device *dev) } } - /* Setup tear effect pin */ + /* Setup tear effect pin and callback */ if (config->tear_effect_gpio.port != NULL) { ret = gpio_pin_configure_dt(&config->tear_effect_gpio, GPIO_INPUT); if (ret < 0) { @@ -629,7 +627,6 @@ static int co5300_init(const struct device *dev) return ret; } - /* Init and install GPIO callback */ gpio_init_callback(&data->tear_effect_gpio_cb, co5300_tear_effect_isr_handler, BIT(config->tear_effect_gpio.pin)); ret = gpio_add_callback(config->tear_effect_gpio.port, &data->tear_effect_gpio_cb); From c503713d0d51f6ad3927d66849c3f19b06feaa83 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Mon, 13 Oct 2025 07:23:22 -0500 Subject: [PATCH 08/16] filling out the rest of the api in display controller --- drivers/display/display_co5300.c | 402 +++++++++---------------------- 1 file changed, 119 insertions(+), 283 deletions(-) diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index beece46c45413..a6a1ddfe36055 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -92,103 +92,6 @@ static int co5300_blanking_off(const struct device *dev) } } -#if 0 -/* Helper function to write framebuffer data to co5300 via MIPI interface. */ -static int co5300_write_fb(const struct device *dev, bool first_write, - const uint8_t *src, const struct display_buffer_descriptor *desc) -{ - const struct co5300_config *config = dev->config; - struct co5300_data *data = dev->data; - ssize_t wlen; - struct mipi_dsi_msg msg = {0}; - uint8_t *local_src = (uint8_t *)src; - uint32_t len = desc->height * desc->width * data->bytes_per_pixel; - uint32_t len_sent = 0U; - - /* Note- we need to set custom flags on the DCS message, - * so we bypass the mipi_dsi_dcs_write API - */ - if (first_write) { - msg.cmd = MIPI_DCS_WRITE_MEMORY_START; - } else { - msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; - } - msg.type = MIPI_DSI_DCS_LONG_WRITE; - msg.flags = MCUX_DSI_2L_FB_DATA; - msg.user_data = (void *)desc; - - while (len > 0) { - msg.tx_len = len; - msg.tx_buf = local_src; - wlen = mipi_dsi_transfer(config->mipi_dsi, config->channel, &msg); - if (wlen < 0) { - return (int)wlen; - } - /* Advance source pointer and decrement remaining */ - if (desc->pitch > desc->width) { - len_sent += wlen; - local_src += wlen + len_sent / (desc->width * data->bytes_per_pixel) * - ((desc->pitch - desc->width) * data->bytes_per_pixel); - } else { - local_src += wlen; - } - len -= wlen; - /* All future commands should use WRITE_MEMORY_CONTINUE */ - msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; - } - return wlen; -} -#else -/* Helper function to write framebuffer data to co5300 via MIPI interface. */ -static int co5300_write_fb(const struct device *dev, bool first_write, - const uint8_t *src, const struct display_buffer_descriptor *desc) -{ - const struct co5300_config *config = dev->config; - struct co5300_data *data = dev->data; - ssize_t wlen; - struct mipi_dsi_msg msg = {0}; - uint8_t *local_src = (uint8_t *)src; - uint32_t len = desc->height * desc->width * data->bytes_per_pixel; - uint32_t len_sent = 0U; - - /* Note- we need to set custom flags on the DCS message, - * so we bypass the mipi_dsi_dcs_write API - */ - if (first_write) { - msg.cmd = MIPI_DCS_WRITE_MEMORY_START; - } else { - msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; - } - msg.type = MIPI_DSI_DCS_LONG_WRITE; - msg.flags = MCUX_DSI_2L_FB_DATA; - msg.user_data = (void *)desc; - - while (len > 0) { - msg.tx_len = len; - msg.tx_buf = local_src; - wlen = mipi_dsi_transfer(config->mipi_dsi, config->channel, &msg); - if (wlen < 0) { - return (int)wlen; - } - /* Advance source pointer and decrement remaining */ - if (desc->pitch > desc->width) { - len_sent += wlen; - local_src += wlen + len_sent / (desc->width * data->bytes_per_pixel) * - ((desc->pitch - desc->width) * data->bytes_per_pixel); - } else { - local_src += wlen; - } - len -= wlen; - /* All future commands should use WRITE_MEMORY_CONTINUE */ - msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; - } - return wlen; -} -#endif - - - -#if 0 static int co5300_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, @@ -197,136 +100,90 @@ static int co5300_write(const struct device *dev, const struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; int ret; - uint16_t start, end; - const uint8_t *src; - bool first_cmd; - uint8_t param[4]; + uint16_t start_xpos; + uint16_t end_xpos; + uint16_t start_ypos; + uint16_t end_ypos; + const uint8_t *framebuffer_addr; + uint8_t cmd_params[4]; + struct mipi_dsi_msg msg = {0}; + uint32_t total_bytes_sent = 0U; + uint32_t framebuffer_size = 0U; + int bytes_written = 0; LOG_DBG("W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); - /* - * CO5300 runs in MIPI DBI mode. This means we can use command mode - * to write to the video memory buffer on the CO5300 control IC, - * and the IC will update the display automatically. - */ - /* Set column address of target area */ /* First two bytes are starting X coordinate */ - start = x; - end = x + desc->width - 1; - sys_put_be16(start, ¶m[0]); + start_xpos = x; + sys_put_be16(start_xpos, &cmd_params[0]); + /* Second two bytes are ending X coordinate */ - sys_put_be16(end, ¶m[2]); + end_xpos = x + desc->width - 1; + sys_put_be16(end_xpos, &cmd_params[2]); ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - MIPI_DCS_SET_COLUMN_ADDRESS, param, - sizeof(param)); + MIPI_DCS_SET_COLUMN_ADDRESS, cmd_params, + sizeof(cmd_params)); if (ret < 0) { return ret; } /* Set page address of target area */ /* First two bytes are starting Y coordinate */ - start = y; - end = y + desc->height - 1; - sys_put_be16(start, ¶m[0]); + start_ypos = y; + sys_put_be16(start_ypos, &cmd_params[0]); + /* Second two bytes are ending X coordinate */ - sys_put_be16(end, ¶m[2]); + end_ypos = y + desc->height - 1; + sys_put_be16(end_ypos, &cmd_params[2]); ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - MIPI_DCS_SET_PAGE_ADDRESS, param, - sizeof(param)); + MIPI_DCS_SET_PAGE_ADDRESS, cmd_params, + sizeof(cmd_params)); if (ret < 0) { return ret; } /* - * Now, write the framebuffer. If the tearing effect GPIO is present, - * wait until the display controller issues an interrupt (which will - * give to the TE semaphore) before sending the frame + * When writing the to the framebuffer and the tearing effect GPIO is present, + * we need to wait for the tear_effect GPIO semaphore to be released. */ if (config->tear_effect_gpio.port != NULL) { - /* Block sleep state until next TE interrupt so we can send - * frame during that interval - */ k_sem_take(&data->tear_effect_sem, K_FOREVER); } - src = buf; - first_cmd = true; - co5300_write_fb(dev, first_cmd, src, desc); - return 0; + /* Start filling out the framebuffer */ + framebuffer_addr = buf; + framebuffer_size = desc->height * desc->width * data->bytes_per_pixel; -} -#else -static int co5300_write(const struct device *dev, - const uint16_t x, const uint16_t y, - const struct display_buffer_descriptor *desc, - const void *buf) -{ - const struct co5300_config *config = dev->config; - struct co5300_data *data = dev->data; - int ret; - uint16_t start, end; - const uint8_t *src; - bool first_cmd; - uint8_t param[4]; - - LOG_DBG("W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); - - /* - * CO5300 runs in MIPI DBI mode. This means we can use command mode - * to write to the video memory buffer on the CO5300 control IC, - * and the IC will update the display automatically. - */ - - /* Set column address of target area */ - /* First two bytes are starting X coordinate */ - start = x; - end = x + desc->width - 1; - sys_put_be16(start, ¶m[0]); - /* Second two bytes are ending X coordinate */ - sys_put_be16(end, ¶m[2]); - ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - MIPI_DCS_SET_COLUMN_ADDRESS, param, - sizeof(param)); - if (ret < 0) { - return ret; - } + msg.type = MIPI_DSI_DCS_LONG_WRITE; + msg.flags = MCUX_DSI_2L_FB_DATA; + msg.user_data = (void *)desc; + msg.cmd = MIPI_DCS_WRITE_MEMORY_START; + + while (framebuffer_size > 0) { + msg.tx_len = framebuffer_size; + msg.tx_buf = framebuffer_addr; + bytes_written = (int)mipi_dsi_transfer(config->mipi_dsi, config->channel, &msg); + if (bytes_written < 0) { + return bytes_written; + } - /* Set page address of target area */ - /* First two bytes are starting Y coordinate */ - start = y; - end = y + desc->height - 1; - sys_put_be16(start, ¶m[0]); - /* Second two bytes are ending X coordinate */ - sys_put_be16(end, ¶m[2]); - ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - MIPI_DCS_SET_PAGE_ADDRESS, param, - sizeof(param)); - if (ret < 0) { - return ret; - } + /* Advance source pointer and decrement remaining */ + if (desc->pitch > desc->width) { + total_bytes_sent += bytes_written; + framebuffer_addr += bytes_written + total_bytes_sent / (desc->width * data->bytes_per_pixel) * + ((desc->pitch - desc->width) * data->bytes_per_pixel); + } else { + framebuffer_addr += bytes_written; + } + framebuffer_size -= bytes_written; - /* - * Now, write the framebuffer. If the tearing effect GPIO is present, - * wait until the display controller issues an interrupt (which will - * give to the TE semaphore) before sending the frame - */ - if (config->tear_effect_gpio.port != NULL) { - /* Block sleep state until next TE interrupt so we can send - * frame during that interval - */ - k_sem_take(&data->tear_effect_sem, K_FOREVER); + /* All future commands should use WRITE_MEMORY_CONTINUE */ + msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; } - src = buf; - first_cmd = true; - - co5300_write_fb(dev, first_cmd, src, desc); - return 0; - } -#endif static int co5300_read(const struct device *dev, const uint16_t x, const uint16_t y, @@ -337,57 +194,82 @@ static int co5300_read(const struct device *dev, static int co5300_clear(const struct device *dev) { +#if 0 + const struct st7567_config *config = dev->config; + int ret = 0; + uint8_t buf = 0; + + uint8_t cmd_buf[] = { + ST7567_COLUMN_LSB, + ST7567_COLUMN_MSB, + ST7567_PAGE, + }; + + for (int y = 0; y < config->height; y += 8) { + for (int x = 0; x < config->width; x++) { + cmd_buf[0] = ST7567_COLUMN_LSB | (x & 0xF); + cmd_buf[1] = ST7567_COLUMN_MSB | ((x >> 4) & 0xF); + cmd_buf[2] = ST7567_PAGE | (y >> 3); + ret = st7567_write_bus(dev, cmd_buf, sizeof(cmd_buf), true); + if (ret < 0) { + LOG_ERR("Error clearing display"); + return ret; + } + ret = st7567_write_bus(dev, (uint8_t *)&buf, 1, false); + if (ret < 0) { + LOG_ERR("Error clearing display"); + return ret; + } + } + } + return ret; + +#endif return 0; } static void *co5300_get_framebuffer(const struct device *dev) { +#if 0 + struct display_stm32_ltdc_data *data = dev->data; + + return ((void *)data->front_buf); +#endif return 0; } -static int co5300_set_brightness(const struct device *dev, uint8_t) +static int co5300_set_brightness(const struct device *dev, const uint8_t contrast) { +#if 0 + uint8_t cmd_buf[] = { + MIPI_DCS_SET_DISPLAY_BRIGHTNESS, + contrast, + }; + + return st7567_write_bus(dev, cmd_buf, sizeof(cmd_buf), true); +#endif return 0; } static int co5300_set_contrast(const struct device *dev, uint8_t contrast) { - return 0; -} - #if 0 -static void co5300_get_capabilities(const struct device *dev, - struct display_capabilities *capabilities) -{ - const struct co5300_config *config = dev->config; - const struct co5300_data *data = dev->data; + uint8_t cmd_buf[] = { + ST7567_SET_CONTRAST_CTRL, + contrast, + }; - memset(capabilities, 0, sizeof(struct display_capabilities)); - capabilities->x_resolution = config->panel_width; - capabilities->y_resolution = config->panel_height; - capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | - PIXEL_FORMAT_RGB_888; + return st7567_write_bus(dev, cmd_buf, sizeof(cmd_buf), true); - switch (data->pixel_format) { - case MIPI_DSI_PIXFMT_RGB565: - capabilities->current_pixel_format = PIXEL_FORMAT_RGB_565; - break; - case MIPI_DSI_PIXFMT_RGB888: - capabilities->current_pixel_format = PIXEL_FORMAT_RGB_888; - break; - default: - LOG_WRN("Unsupported display format"); - /* Other display formats not implemented */ - break; - } - capabilities->current_orientation = DISPLAY_ORIENTATION_ROTATED_90; +#endif + return 0; } -#else + static void co5300_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { const struct co5300_config *config = dev->config; - const struct co5300_data *data = dev->data; + struct co5300_data *data = dev->data; memset(capabilities, 0, sizeof(struct display_capabilities)); capabilities->x_resolution = config->panel_width; @@ -407,11 +289,9 @@ static void co5300_get_capabilities(const struct device *dev, /* Other display formats not implemented */ break; } - capabilities->current_orientation = DISPLAY_ORIENTATION_ROTATED_90; + capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; } -#endif -#if 0 static int co5300_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { @@ -419,7 +299,7 @@ static int co5300_set_pixel_format(const struct device *dev, struct co5300_data *data = dev->data; uint8_t param; - switch (data->pixel_format) { + switch (pixel_format) { case PIXEL_FORMAT_RGB_565: data->pixel_format = MIPI_DSI_PIXFMT_RGB565; param = MIPI_DCS_PIXEL_FORMAT_16BIT; @@ -439,51 +319,8 @@ static int co5300_set_pixel_format(const struct device *dev, MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); return 0; - } -#else -static int co5300_set_pixel_format(const struct device *dev, - const enum display_pixel_format pixel_format) -{ - const struct co5300_config *config = dev->config; - struct co5300_data *data = dev->data; - uint8_t param; - switch (data->pixel_format) { - case PIXEL_FORMAT_RGB_565: - data->pixel_format = MIPI_DSI_PIXFMT_RGB565; - param = MIPI_DCS_PIXEL_FORMAT_16BIT; - data->bytes_per_pixel = 2; - break; - case PIXEL_FORMAT_RGB_888: - data->pixel_format = MIPI_DSI_PIXFMT_RGB888; - param = MIPI_DCS_PIXEL_FORMAT_24BIT; - data->bytes_per_pixel = 3; - break; - default: - /* Other display formats not implemented */ - return -ENOTSUP; - } - - return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); - - return 0; - -} -#endif - -#if 0 -static int co5300_set_orientation(const struct device *dev, - const enum display_orientation orientation) -{ - if (orientation == DISPLAY_ORIENTATION_NORMAL) { - return 0; - } - LOG_ERR("Changing display orientation not implemented"); - return -ENOTSUP; -} -#else static int co5300_set_orientation(const struct device *dev, const enum display_orientation orientation) { @@ -493,7 +330,6 @@ static int co5300_set_orientation(const struct device *dev, LOG_ERR("Changing display orientation not implemented"); return -ENOTSUP; } -#endif static int co5300_init(const struct device *dev) { @@ -645,17 +481,17 @@ static int co5300_init(const struct device *dev) } static DEVICE_API(display, co5300_api) = { - .blanking_on = co5300_blanking_on, - .blanking_off = co5300_blanking_off, - .write = co5300_write, - .read = co5300_read, - .clear = co5300_clear, - .get_framebuffer = co5300_get_framebuffer, - .set_brightness = co5300_set_brightness, - .set_contrast = co5300_set_contrast, - .get_capabilities = co5300_get_capabilities, - .set_pixel_format = co5300_set_pixel_format, - .set_orientation = co5300_set_orientation, + .blanking_on = co5300_blanking_on, //[ ] + .blanking_off = co5300_blanking_off, //[ ] + .write = co5300_write, //[ ] + .read = co5300_read, //[ ] + .clear = co5300_clear, //[ ] + .get_framebuffer = co5300_get_framebuffer, //[ ] + .set_brightness = co5300_set_brightness, //[ ] + .set_contrast = co5300_set_contrast, //[ ] + .get_capabilities = co5300_get_capabilities, //[x] + .set_pixel_format = co5300_set_pixel_format, //[x] + .set_orientation = co5300_set_orientation, //[x] }; #define CO5300_DEVICE_INIT(node_id) \ From 2cfd8435c69c09e1268a391c9b8c0ec9c7626f2c Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Mon, 13 Oct 2025 09:04:52 -0500 Subject: [PATCH 09/16] initial work on touch input --- .../mimxrt700_evk_mimxrt798s_cm33_cpu0.dts | 5 +- .../zc143ac72mipi/zc143ac72mipi.overlay | 19 +- drivers/input/input_tma525b.c | 255 ++++++++++++++++++ 3 files changed, 262 insertions(+), 17 deletions(-) create mode 100644 drivers/input/input_tma525b.c diff --git a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts index d35762b53e52f..67e7519a2b248 100644 --- a/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts +++ b/boards/nxp/mimxrt700_evk/mimxrt700_evk_mimxrt798s_cm33_cpu0.dts @@ -403,7 +403,7 @@ zephyr_udc0: &usb0 { pinctrl-names = "default"; }; -p3t1755dp_ard_i2c_interface: &flexcomm8_lpi2c8 {}; +//p3t1755dp_ard_i2c_interface: &flexcomm8_lpi2c8 {}; &rtc0 { status = "okay"; @@ -421,6 +421,3 @@ p3t1755dp_ard_i2c_interface: &flexcomm8_lpi2c8 {}; status = "okay"; }; -&pca9422 { - status = "okay"; -}; diff --git a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay index ca294346790ef..a3f86a10c28d0 100644 --- a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay +++ b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay @@ -7,45 +7,38 @@ / { chosen { zephyr,display = &co5300_zc143ac72mipi; -/* zephyr,touch = &ft3267_g1120b0mipi;*/ + zephyr,touch = &tma525b_zc143ac72mipi; }; - /* en_mipi_display_g1120b0mipi: enable-mipi-display { compatible = "regulator-fixed"; regulator-name = "en_mipi_display"; enable-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; regulator-boot-on; }; - */ - /* lvgl_pointer { compatible = "zephyr,lvgl-pointer-input"; - input = <&ft3267_g1120b0mipi>; - display = <&rm67162_g1120b0mipi>; + input = <&ft3267_zc143ac72mipi>; + display = <&co5300_zc143ac72mipi>; invert-y; }; - */ }; -/* &nxp_mipi_i2c { status = "okay"; - ft3267_g1120b0mipi: ft3267@38 { + tma525b_zc143ac72mipi: tma525b@24 { /* * Note- the actual controller present on this IC is a FT3267, * but the FT35336 driver in Zephyr supports this IC. */ - /* - compatible = "focaltech,ft5336"; - reg = <0x38>; + compatible = "focaltech,tma525b"; + reg = <0x24>; int-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_LOW>; }; }; -*/ &zephyr_mipi_dsi { status = "okay"; diff --git a/drivers/input/input_tma525b.c b/drivers/input/input_tma525b.c new file mode 100644 index 0000000000000..f1989d44ecdab --- /dev/null +++ b/drivers/input/input_tma525b.c @@ -0,0 +1,255 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ..._tma525b + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(tma525b, CONFIG_INPUT_LOG_LEVEL); + +#if 0 +/* TMA525B used registers */ +#define REG_TD_STATUS 0x02U +#define REG_P1_XH 0x03U +#define REG_G_PMODE 0xA5U + +/* REG_TD_STATUS: Touch points. */ +#define TOUCH_POINTS_POS 0U +#define TOUCH_POINTS_MSK 0x0FU + +/* REG_Pn_XH: Events. */ +#define EVENT_POS 6U +#define EVENT_MSK 0x03U + +#define EVENT_PRESS_DOWN 0x00U +#define EVENT_LIFT_UP 0x01U +#define EVENT_CONTACT 0x02U +#define EVENT_NONE 0x03U + +/* REG_Pn_YH: Touch ID */ +#define TOUCH_ID_POS 4U +#define TOUCH_ID_MSK 0x0FU + +#define TOUCH_ID_INVALID 0x0FU + +/* REG_Pn_XH and REG_Pn_YH: Position */ +#define POSITION_H_MSK 0x0FU + +/* REG_G_PMODE: Power Consume Mode */ +#define PMOD_HIBERNATE 0x03U +#endif + +/** TMA525B configuration (DT). */ +struct tma525b_config { + struct input_touchscreen_common_config common; + /** I2C bus. */ + struct i2c_dt_spec bus; + struct gpio_dt_spec reset_gpio; +#ifdef CONFIG_INPUT_TMA525B_INTERRUPT + /** Interrupt GPIO information. */ + struct gpio_dt_spec int_gpio; +#endif +}; + +/** TMA525B data. */ +struct tma525b_data { + /** Work queue (for deferred read). */ + struct k_work work; +#ifdef CONFIG_INPUT_TMA525B_INTERRUPT + /** Interrupt GPIO callback. */ + struct gpio_callback int_gpio_cb; +#else + /** Timer (polling mode). */ + struct k_timer timer; +#endif + /** Last pressed state. */ + bool pressed_old; +}; + +INPUT_TOUCH_STRUCT_CHECK(struct tma525b_config); + +static int tma525b_process(const struct device *dev) +{ +#if 0 + const struct tma525b_config *config = dev->config; + struct tma525b_data *data = dev->data; + + int r; + uint8_t points; + uint8_t coords[4U]; + uint16_t row, col; + bool pressed; + + /* obtain number of touch points */ + r = i2c_reg_read_byte_dt(&config->bus, REG_TD_STATUS, &points); + if (r < 0) { + return r; + } + + points = FIELD_GET(TOUCH_POINTS_MSK, points); + if (points != 0) { + /* Any number of touches still counts as one touch. All touch + * points except the first are ignored. Obtain first point + * X, Y coordinates from: + * REG_P1_XH, REG_P1_XL, REG_P1_YH, REG_P1_YL. + * We ignore the Event Flag because Zephyr only cares about + * pressed / not pressed and not press down / lift up + */ + r = i2c_burst_read_dt(&config->bus, REG_P1_XH, coords, sizeof(coords)); + if (r < 0) { + return r; + } + + row = ((coords[0] & POSITION_H_MSK) << 8U) | coords[1]; + col = ((coords[2] & POSITION_H_MSK) << 8U) | coords[3]; + + uint8_t touch_id = FIELD_GET(TOUCH_ID_MSK, coords[2]); + + if (touch_id != TOUCH_ID_INVALID) { + pressed = true; + LOG_DBG("points: %d, touch_id: %d, row: %d, col: %d", + points, touch_id, row, col); + } else { + pressed = false; + LOG_WRN("bad TOUCH_ID: row: %d, col: %d", row, col); + } + } else { + /* no touch = no press */ + pressed = false; + } + + if (pressed) { + input_touchscreen_report_pos(dev, col, row, K_FOREVER); + input_report_key(dev, INPUT_BTN_TOUCH, 1, true, K_FOREVER); + } else if (data->pressed_old && !pressed) { + input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER); + } + data->pressed_old = pressed; +#endif + + return 0; +} + +static void tma525b_work_handler(struct k_work *work) +{ + struct tma525b_data *data = CONTAINER_OF(work, struct tma525b_data, work); + + tma525b_process(data->dev); +} + +#ifdef CONFIG_INPUT_TMA525B_INTERRUPT +static void tma525b_isr_handler(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct tma525b_data *data = CONTAINER_OF(cb, struct tma525b_data, int_gpio_cb); + + k_work_submit(&data->work); +} +#else +static void tma525b_timer_handler(struct k_timer *timer) +{ + struct tma525b_data *data = CONTAINER_OF(timer, struct tma525b_data, timer); + + k_work_submit(&data->work); +} +#endif + +static int tma525b_init(const struct device *dev) +{ + const struct tma525b_config *config = dev->config; + struct tma525b_data *data = dev->data; + int err_code; + + + if (!device_is_ready(config->bus.bus)) { + LOG_ERR("I2C controller device not ready"); + return -ENODEV; + } + + k_work_init(&data->work, tma525b_work_handler); + + /* GPIO Power on Sequence */ + if (config->power_gpio.port != NULL) { + err_code = gpio_pin_set_dt(&config->power_gpio, 1); + if (err_code < 0) { + LOG_ERR("Could not enable power GPIO"); + return err_code; + } + if (config->reset_gpio.port != NULL) { + err_code = gpio_pin_set_dt(&config->reset_gpio, 0); + if (err_code < 0) { + LOG_ERR("Could not set reset GPIO low"); + return r; + } + /* Datasheet states to hold for 5ms after activation of reset pin */ + k_sleep(K_MSEC(5)); + + err_code = gpio_pin_set_dt(&config->reset_gpio, 1); + if (err_code < 0) { + LOG_ERR("Could not set reset GPIO high"); + return err_code; + } + } + } else { + LOG_ERR("Could not enable power GPIO"); + return err_code; + } + +#ifdef CONFIG_INPUT_TMA525B_INTERRUPT + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("Interrupt GPIO controller device not ready"); + return -ENODEV; + } + + err_code = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + if (err_code < 0) { + LOG_ERR("Could not configure interrupt GPIO pin"); + return err_code; + } + + err_code = gpio_pin_interrupt_configure_dt(&config->int_gpio, + GPIO_INT_EDGE_TO_ACTIVE); + if (err_code < 0) { + LOG_ERR("Could not configure interrupt GPIO interrupt."); + return err_code; + } + + gpio_init_callback(&data->int_gpio_cb, tma525b_isr_handler, + BIT(config->int_gpio.pin)); + err_code = gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); + if (err_code < 0) { + LOG_ERR("Could not set gpio callback"); + return err_code; + } +#else + k_timer_init(&data->timer, tma525b_timer_handler, NULL); + k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_TMA525B_PERIOD), + K_MSEC(CONFIG_INPUT_TMA525B_PERIOD)); +#endif + return 0; +} + +#define TMA525B_INIT(index) \ + static const struct tma525b_config tma525b_config_##index = { \ + .common = INPUT_TOUCH_DT_INST_COMMON_CONFIG_INIT(index), \ + .bus = I2C_DT_SPEC_INST_GET(index), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(index, reset_gpios, {0}), \ + IF_ENABLED(CONFIG_INPUT_TMA525B_INTERRUPT, \ + (.int_gpio = GPIO_DT_SPEC_INST_GET(index, int_gpios),)) \ + }; \ + static struct tma525b_data tma525b_data_##index; \ + DEVICE_DT_INST_DEFINE(index, tma525b_init, 0, \ + &tma525b_data_##index, &tma525b_config_##index, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(TMA525B_INIT) From 0a517cc475fecd086284d7a2a23aa799a6e5ec4c Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Tue, 14 Oct 2025 12:42:30 -0500 Subject: [PATCH 10/16] cleaning up loose ends on display controller api, question about framebuffer --- drivers/display/display_co5300.c | 134 ++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 22 deletions(-) diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index a6a1ddfe36055..51751b0459ef2 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -40,6 +40,7 @@ struct co5300_config { }; struct co5300_data { + uint8_t* last_known_framebuffer; uint8_t pixel_format; uint8_t bytes_per_pixel; struct gpio_callback tear_effect_gpio_cb; @@ -111,7 +112,15 @@ static int co5300_write(const struct device *dev, uint32_t framebuffer_size = 0U; int bytes_written = 0; - LOG_DBG("W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); + LOG_DBG("WRITE:: W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); + + //@TODO(Emilio): Should we update the api to allow this to happen + // Keep in mind we will now have a conflict the driver + // needs to settle, which framebuffer is our focus + // one given internally via Kconfig or DTS + // or one given externally via Application or external peripheral + /* Capture the buffer we are drawing to */ +// data->last_known_framebuffer = buf; /* Set column address of target area */ /* First two bytes are starting X coordinate */ @@ -189,6 +198,93 @@ static int co5300_read(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, void *buf) { +#if 0 + const struct co5300_config *config = dev->config; + struct co5300_data *data = dev->data; + int ret; + uint16_t start_xpos; + uint16_t end_xpos; + uint16_t start_ypos; + uint16_t end_ypos; + const uint8_t *framebuffer_addr; + uint8_t cmd_params[4]; + struct mipi_dsi_msg msg = {0}; + uint32_t total_bytes_sent = 0U; + uint32_t framebuffer_size = 0U; + int bytes_written = 0; + + LOG_DBG("READ:: W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); + + /* Set column address of target area */ + /* First two bytes are starting X coordinate */ + start_xpos = x; + sys_put_be16(start_xpos, &cmd_params[0]); + + /* Second two bytes are ending X coordinate */ + end_xpos = x + desc->width - 1; + sys_put_be16(end_xpos, &cmd_params[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_COLUMN_ADDRESS, cmd_params, + sizeof(cmd_params)); + if (ret < 0) { + return ret; + } + + /* Set page address of target area */ + /* First two bytes are starting Y coordinate */ + start_ypos = y; + sys_put_be16(start_ypos, &cmd_params[0]); + + /* Second two bytes are ending X coordinate */ + end_ypos = y + desc->height - 1; + sys_put_be16(end_ypos, &cmd_params[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PAGE_ADDRESS, cmd_params, + sizeof(cmd_params)); + if (ret < 0) { + return ret; + } + + /* + * When writing the to the framebuffer and the tearing effect GPIO is present, + * we need to wait for the tear_effect GPIO semaphore to be released. + */ + if (config->tear_effect_gpio.port != NULL) { + k_sem_take(&data->tear_effect_sem, K_FOREVER); + } + + + /* Start filling out the framebuffer */ + framebuffer_addr = buf; + framebuffer_size = desc->height * desc->width * data->bytes_per_pixel; + + msg.type = MIPI_DSI_DCS_LONG_WRITE; + msg.flags = MCUX_DSI_2L_FB_DATA; + msg.user_data = (void *)desc; + msg.cmd = MIPI_DCS_WRITE_MEMORY_START; + + while (framebuffer_size > 0) { + msg.tx_len = framebuffer_size; + msg.tx_buf = framebuffer_addr; + bytes_written = (int)mipi_dsi_transfer(config->mipi_dsi, config->channel, &msg); + if (bytes_written < 0) { + return bytes_written; + } + + /* Advance source pointer and decrement remaining */ + if (desc->pitch > desc->width) { + total_bytes_sent += bytes_written; + framebuffer_addr += bytes_written + total_bytes_sent / (desc->width * data->bytes_per_pixel) * + ((desc->pitch - desc->width) * data->bytes_per_pixel); + } else { + framebuffer_addr += bytes_written; + } + framebuffer_size -= bytes_written; + + /* All future commands should use WRITE_MEMORY_CONTINUE */ + msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; + } +#endif return 0; } @@ -230,38 +326,32 @@ static int co5300_clear(const struct device *dev) static void *co5300_get_framebuffer(const struct device *dev) { -#if 0 - struct display_stm32_ltdc_data *data = dev->data; + struct co5300_data *data = dev->data; - return ((void *)data->front_buf); -#endif - return 0; + if(data->last_known_framebuffer) + { + return data->last_known_framebuffer; + } + + /* Value NULL is reported as unsupported function. */ + /* Thus, -1 will result in framebuffer not found */ + return (void*)-1; } static int co5300_set_brightness(const struct device *dev, const uint8_t contrast) { -#if 0 - uint8_t cmd_buf[] = { - MIPI_DCS_SET_DISPLAY_BRIGHTNESS, - contrast, - }; + const struct co5300_config *config = dev->config; - return st7567_write_bus(dev, cmd_buf, sizeof(cmd_buf), true); -#endif - return 0; + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, &contrast, 1); } static int co5300_set_contrast(const struct device *dev, uint8_t contrast) { -#if 0 - uint8_t cmd_buf[] = { - ST7567_SET_CONTRAST_CTRL, - contrast, - }; - - return st7567_write_bus(dev, cmd_buf, sizeof(cmd_buf), true); + /* + const struct co5300_config *config = dev->config; -#endif + return mipi_dcs_write(config->mipi_dsi, config->channel, **CONTRAST**, &contrast, 1); + */ return 0; } From abb996fcec0dba4c7a77bceafe9b3cc36f499bd8 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 15 Oct 2025 02:19:42 -0500 Subject: [PATCH 11/16] important clock update --- boards/shields/zc143ac72mipi/zc143ac72mipi.overlay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay index a3f86a10c28d0..d16e2d0684bb3 100644 --- a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay +++ b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay @@ -43,7 +43,7 @@ &zephyr_mipi_dsi { status = "okay"; autoinsert-eotp; - phy-clock = <316800000>; + phy-clock = <319488000>; co5300_zc143ac72mipi: co5300@0 { status = "okay"; From 6de867c2a340bfcf532a90f7faba2ad1994e9dc6 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 15 Oct 2025 02:19:59 -0500 Subject: [PATCH 12/16] DEL ME --- drivers/mipi_dsi/dsi_mcux_2l.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mipi_dsi/dsi_mcux_2l.c b/drivers/mipi_dsi/dsi_mcux_2l.c index 14ec387960178..619d3ee4b302b 100644 --- a/drivers/mipi_dsi/dsi_mcux_2l.c +++ b/drivers/mipi_dsi/dsi_mcux_2l.c @@ -481,6 +481,7 @@ static int dsi_mcux_attach(const struct device *dev, return -EINVAL; } + //@IMPORTANT @TODO(Emilio): Comeback to this line of code after dts question is answered. switch (config->dpi_config.pixelPacket) { case kDSI_PixelPacket16Bit: bit_width = 16; From ead2f8577811a142e9be657799f950ef644b2b9c Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 15 Oct 2025 04:01:22 -0500 Subject: [PATCH 13/16] updated todo --- todo.txt | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/todo.txt b/todo.txt index afd6ea1fec263..783236543e37e 100644 --- a/todo.txt +++ b/todo.txt @@ -17,7 +17,7 @@ BOARD_InitMipiPanelPins(); BOARD_InitMipiTouchPanelPins(); -@IMPORTANT @TODO(Emilio): I2C is going to be needed for the Touch pins to +@IMPORTANT @TODO(Emilio): I2C is going to be needed for the Touch pins to work. @SPEED(Emilio): Until we have the actual display working we will not worry about I2C. @@ -235,7 +235,7 @@ /*****************************/ @IMPORTANT @NOTE(Emilio): We are currently skipping lv_init, since we think - it is mostly init for middleware code and nothing to deal with + it is mostly init for middleware code and nothing to deal with the actual display, may need to look at this again. @@ -250,7 +250,7 @@ #define DEMO_FB_WIDTH (DEMO_PANEL_WIDTH) // 466 #define DEMO_FB_HEIGHT (DEMO_PANEL_HEIGHT) // 466 // 960 -#define DEMO_BUFFER_STRIDE_BYTE DEMO_FB_WIDTH * DEMO_BUFFER_BYTE_PER_PIXEL +#define DEMO_BUFFER_STRIDE_BYTE DEMO_FB_WIDTH * DEMO_BUFFER_BYTE_PER_PIXEL // 447360 #define DEMO_FB_SIZE (DEMO_BUFFER_STRIDE_BYTE * DEMO_FB_HEIGHT) @@ -266,3 +266,31 @@ is located in examples\_boards\mimxrt700evk\display_support.c in func BOARD_PrepareDisplayController() + +/*****************************/ +//@NOTE(Emilio): Where you left off + +//@TODO(Emilio): Look at enabling mipi_dsi->mode_flag = MIPI_DSI_MODE_VIDEO; + +//@IMPORTANT @NOTE(Emilio): While the register fields in both GPIO + drivers line up, the api interface seems to be + unaligned with how the bit mask values and flags + are defined, as a result it will take more digging to + find out if the gpio signals are being configured correctly. + Specifically is ACTIVE HIGH or ACTIVE LOW? + +//@TODO(Emilio): GPIOs we KNOWN we need to configure referanced above. + /////////////////////// + //SIGNAL_DIR | ACTIVE / + /////////////////////// + reset-gpios = <&nxp_mipi_connector 21 GPIO_ACTIVE_HIGH>; //OUTPUT | + backlight-gpios = <&nxp_mipi_connector 0 GPIO_ACTIVE_HIGH>; //--- | + tear-effect-gpios = <&nxp_mipi_connector 22 GPIO_ACTIVE_HIGH>; //INPUT | + power-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; //OUTPUT | + + //@NOTE(Emilio): Touch Screen + int-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; //--- | + reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_LOW>; //--- | + + + From 804f24210865d5d317f22a0af956825107f2c988 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 15 Oct 2025 10:59:54 -0500 Subject: [PATCH 14/16] latest changes, updated gpios to proper map, added pixel_format cmd code --- .../zc143ac72mipi/zc143ac72mipi.overlay | 8 +- drivers/display/display_co5300.c | 109 +++++++++++++----- todo.txt | 2 +- 3 files changed, 86 insertions(+), 33 deletions(-) diff --git a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay index d16e2d0684bb3..69e3e7b9f13db 100644 --- a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay +++ b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay @@ -13,7 +13,7 @@ en_mipi_display_g1120b0mipi: enable-mipi-display { compatible = "regulator-fixed"; regulator-name = "en_mipi_display"; - enable-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; + enable-gpio = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; regulator-boot-on; }; @@ -35,8 +35,8 @@ */ compatible = "focaltech,tma525b"; reg = <0x24>; - int-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; - reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_LOW>; + int-gpio = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; + reset-gpio = <&nxp_mipi_connector 28 GPIO_ACTIVE_LOW>; }; }; @@ -50,7 +50,7 @@ compatible = "chipone,co5300"; reg = <0x0>; reset-gpios = <&nxp_mipi_connector 21 GPIO_ACTIVE_HIGH>; - backlight-gpios = <&nxp_mipi_connector 0 GPIO_ACTIVE_HIGH>; + backlight-gpios = <&nxp_mipi_connector 34 GPIO_ACTIVE_HIGH>; tear-effect-gpios = <&nxp_mipi_connector 22 GPIO_ACTIVE_HIGH>; power-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; data-lanes = <1>; diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index 51751b0459ef2..8b2477eb25a7c 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -29,10 +29,10 @@ struct display_cmds { struct co5300_config { const struct device *mipi_dsi; - const struct gpio_dt_spec reset_gpio; - const struct gpio_dt_spec backlight_gpio; - const struct gpio_dt_spec tear_effect_gpio; - const struct gpio_dt_spec power_gpio; + const struct gpio_dt_spec reset_gpios; + const struct gpio_dt_spec backlight_gpios; + const struct gpio_dt_spec tear_effect_gpios; + const struct gpio_dt_spec power_gpios; uint16_t panel_width; uint16_t panel_height; uint16_t channel; @@ -62,6 +62,9 @@ uint8_t lcm_init_cmds[] = { 0xFE, 0x1, 0x20, 0x2A, 0x4, 0x00, 0x06, 0x01, 0xD7, 0x2B, 0x4, 0x00, 0x00, 0x01, 0xD1}; +uint8_t pixel_format_bgr_cmds[] = {0x36, 0x1, 0x8}; + + static void co5300_tear_effect_isr_handler(const struct device* gpio_dev, struct gpio_callback *cb, uint32_t pins) { @@ -75,8 +78,8 @@ static int co5300_blanking_on(const struct device *dev) { const struct co5300_config *config = dev->config; - if (config->backlight_gpio.port != NULL) { - return gpio_pin_set_dt(&config->backlight_gpio, 0); + if (config->backlight_gpios.port != NULL) { + return gpio_pin_set_dt(&config->backlight_gpios, 0); } else { return -ENOTSUP; } @@ -86,8 +89,8 @@ static int co5300_blanking_off(const struct device *dev) { const struct co5300_config *config = dev->config; - if (config->backlight_gpio.port != NULL) { - return gpio_pin_set_dt(&config->backlight_gpio, 1); + if (config->backlight_gpios.port != NULL) { + return gpio_pin_set_dt(&config->backlight_gpios, 1); } else { return -ENOTSUP; } @@ -156,7 +159,7 @@ static int co5300_write(const struct device *dev, * When writing the to the framebuffer and the tearing effect GPIO is present, * we need to wait for the tear_effect GPIO semaphore to be released. */ - if (config->tear_effect_gpio.port != NULL) { + if (config->tear_effect_gpios.port != NULL) { k_sem_take(&data->tear_effect_sem, K_FOREVER); } @@ -249,7 +252,7 @@ static int co5300_read(const struct device *dev, * When writing the to the framebuffer and the tearing effect GPIO is present, * we need to wait for the tear_effect GPIO semaphore to be released. */ - if (config->tear_effect_gpio.port != NULL) { + if (config->tear_effect_gpios.port != NULL) { k_sem_take(&data->tear_effect_sem, K_FOREVER); } @@ -427,6 +430,7 @@ static int co5300_init(const struct device *dev) struct co5300_data *data = dev->data; struct mipi_dsi_device mdev = {0}; struct display_cmds lcm_init_settings = {0}; + struct display_cmds pixel_format_bgr_settings = {0}; uint8_t* ptr_to_curr_cmd = 0; uint8_t* ptr_to_last_cmd = 0; uint8_t cmd_params = 0; @@ -443,14 +447,15 @@ static int co5300_init(const struct device *dev) } /* Perform GPIO Reset */ - if (config->power_gpio.port != NULL) { - ret = gpio_pin_configure_dt(&config->power_gpio, GPIO_OUTPUT_INACTIVE); + /* + if (config->power_gpios.port != NULL) { + ret = gpio_pin_configure_dt(&config->power_gpios, GPIO_OUTPUT_INACTIVE); if (ret < 0) { LOG_ERR("Could not configure power GPIO (%d)", ret); return ret; } - ret = gpio_pin_set_dt(&config->power_gpio, 1); + ret = gpio_pin_set_dt(&config->power_gpios, 1); if (ret < 0) { LOG_ERR("Could not pull power high (%d)", ret); return ret; @@ -458,21 +463,22 @@ static int co5300_init(const struct device *dev) k_sleep(K_MSEC(100)); - if (config->reset_gpio.port != NULL) { - ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (config->reset_gpios.port != NULL) { + ret = gpio_pin_set_dt(&config->power_gpios, 1); if (ret < 0) { - LOG_ERR("Could not configure reset GPIO (%d)", ret); + LOG_ERR("Could not set power GPIO (%d)", ret); return ret; } - ret = gpio_pin_set_dt(&config->reset_gpio, 0); + k_sleep(K_MSEC(100)); + ret = gpio_pin_set_dt(&config->reset_gpios, 0); if (ret < 0) { LOG_ERR("Could not pull reset low (%d)", ret); return ret; } k_sleep(K_MSEC(1)); - gpio_pin_set_dt(&config->reset_gpio, 1); + gpio_pin_set_dt(&config->reset_gpios, 1); if (ret < 0) { LOG_ERR("Could not pull reset high (%d)", ret); return ret; @@ -480,6 +486,43 @@ static int co5300_init(const struct device *dev) k_sleep(K_MSEC(150)); } } + */ + if (config->reset_gpios.port != NULL) { + ret = gpio_pin_configure_dt(&config->reset_gpios, 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_gpios, 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_gpios, 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)); + } + + /* Set the LCM init settings. */ lcm_init_settings.cmd_code = lcm_init_cmds; @@ -501,6 +544,12 @@ static int co5300_init(const struct device *dev) } /* Set pixel format */ +// curr_cmd = pixel_format_bgr_cmds[0]; +// cmd_param_size = pixel_format_bgr_cmds[1]; + cmd_params = pixel_format_bgr_cmds[2]; + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + 0x36, &cmd_params, 1); + if (data->pixel_format == MIPI_DSI_PIXFMT_RGB888) { cmd_params = (uint8_t)MIPI_DCS_PIXEL_FORMAT_24BIT; data->bytes_per_pixel = 3; @@ -512,6 +561,9 @@ static int co5300_init(const struct device *dev) LOG_ERR("Pixel format not supported"); return -ENOTSUP; } + cmd_params = (uint8_t)MIPI_DCS_PIXEL_FORMAT_24BIT; + data->bytes_per_pixel = 2; + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_PIXEL_FORMAT, &cmd_params, 1); if (ret < 0) { @@ -530,8 +582,8 @@ static int co5300_init(const struct device *dev) k_sleep(K_MSEC(150)); /* Setup backlight */ - if (config->backlight_gpio.port != NULL) { - ret = gpio_pin_configure_dt(&config->backlight_gpio, GPIO_OUTPUT_ACTIVE); + if (config->backlight_gpios.port != NULL) { + ret = gpio_pin_configure_dt(&config->backlight_gpios, GPIO_OUTPUT_ACTIVE); if (ret < 0) { LOG_ERR("Could not configure bl GPIO (%d)", ret); return ret; @@ -539,14 +591,14 @@ static int co5300_init(const struct device *dev) } /* Setup tear effect pin and callback */ - if (config->tear_effect_gpio.port != NULL) { - ret = gpio_pin_configure_dt(&config->tear_effect_gpio, GPIO_INPUT); + if (config->tear_effect_gpios.port != NULL) { + ret = gpio_pin_configure_dt(&config->tear_effect_gpios, GPIO_INPUT); if (ret < 0) { LOG_ERR("Could not configure TE GPIO (%d)", ret); return ret; } - ret = gpio_pin_interrupt_configure_dt(&config->tear_effect_gpio, + ret = gpio_pin_interrupt_configure_dt(&config->tear_effect_gpios, GPIO_INT_EDGE_TO_ACTIVE); if (ret < 0) { LOG_ERR("Could not configure TE interrupt (%d)", ret); @@ -554,8 +606,8 @@ static int co5300_init(const struct device *dev) } gpio_init_callback(&data->tear_effect_gpio_cb, co5300_tear_effect_isr_handler, - BIT(config->tear_effect_gpio.pin)); - ret = gpio_add_callback(config->tear_effect_gpio.port, &data->tear_effect_gpio_cb); + BIT(config->tear_effect_gpios.pin)); + ret = gpio_add_callback(config->tear_effect_gpios.port, &data->tear_effect_gpio_cb); if (ret < 0) { LOG_ERR("Could not add TE gpio callback"); return ret; @@ -589,9 +641,10 @@ static DEVICE_API(display, co5300_api) = { .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(node_id)), \ .num_of_lanes = DT_INST_PROP_BY_IDX(node_id, data_lanes, 0), \ .channel = DT_INST_REG_ADDR(node_id), \ - .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, reset_gpios, {0}), \ - .backlight_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, backlight_gpios, {0}), \ - .tear_effect_gpio = GPIO_DT_SPEC_INST_GET_OR(node_id, tear_effect_gpios, {0}), \ + .reset_gpios = GPIO_DT_SPEC_INST_GET_OR(node_id, reset_gpios, {0}), \ + .power_gpios = GPIO_DT_SPEC_INST_GET_OR(node_id, power_gpios, {0}), \ + .backlight_gpios = GPIO_DT_SPEC_INST_GET_OR(node_id, backlight_gpios, {0}), \ + .tear_effect_gpios = GPIO_DT_SPEC_INST_GET_OR(node_id, tear_effect_gpios, {0}), \ .panel_width = DT_INST_PROP(node_id, width), \ .panel_height = DT_INST_PROP(node_id, height), \ }; \ diff --git a/todo.txt b/todo.txt index 783236543e37e..d8f19e584ddc0 100644 --- a/todo.txt +++ b/todo.txt @@ -284,7 +284,7 @@ //SIGNAL_DIR | ACTIVE / /////////////////////// reset-gpios = <&nxp_mipi_connector 21 GPIO_ACTIVE_HIGH>; //OUTPUT | - backlight-gpios = <&nxp_mipi_connector 0 GPIO_ACTIVE_HIGH>; //--- | + backlight-gpios = <&nxp_mipi_connector 0 GPIO_ACTIVE_HIGH>; //INPUT | tear-effect-gpios = <&nxp_mipi_connector 22 GPIO_ACTIVE_HIGH>; //INPUT | power-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; //OUTPUT | From 8d47eb95418827bf8d31a45d03f68a648a046c11 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Thu, 16 Oct 2025 12:12:39 -0500 Subject: [PATCH 15/16] Pass in personal sample into todo.txt --- drivers/display/display_co5300.c | 23 ++++++++-- todo.txt | 79 ++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index 8b2477eb25a7c..a5672019702ee 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -166,7 +166,7 @@ static int co5300_write(const struct device *dev, /* Start filling out the framebuffer */ framebuffer_addr = buf; - framebuffer_size = desc->height * desc->width * data->bytes_per_pixel; + framebuffer_size = desc->buf_size; msg.type = MIPI_DSI_DCS_LONG_WRITE; msg.flags = MCUX_DSI_2L_FB_DATA; @@ -391,9 +391,15 @@ static int co5300_set_pixel_format(const struct device *dev, const struct co5300_config *config = dev->config; struct co5300_data *data = dev->data; uint8_t param; + //@SPEED(Emilio): From init function + uint8_t curr_cmd = pixel_format_bgr_cmds[0]; + uint8_t cmd_param_size = pixel_format_bgr_cmds[1]; + uint8_t cmd_params = pixel_format_bgr_cmds[1]; + int ret; switch (pixel_format) { case PIXEL_FORMAT_RGB_565: + cmd_params = pixel_format_bgr_cmds[2]; data->pixel_format = MIPI_DSI_PIXFMT_RGB565; param = MIPI_DCS_PIXEL_FORMAT_16BIT; data->bytes_per_pixel = 2; @@ -408,6 +414,13 @@ static int co5300_set_pixel_format(const struct device *dev, return -ENOTSUP; } + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + 0x36, &cmd_params, 1); + if (ret < 0) { + return ret; + } + + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); @@ -561,11 +574,13 @@ static int co5300_init(const struct device *dev) LOG_ERR("Pixel format not supported"); return -ENOTSUP; } - cmd_params = (uint8_t)MIPI_DCS_PIXEL_FORMAT_24BIT; - data->bytes_per_pixel = 2; + + uint8_t temp_cmd_params[2]; + temp_cmd_params[0] = (uint8_t)cmd_params; + temp_cmd_params[1] = (uint8_t)MIPI_DCS_PIXEL_FORMAT_24BIT; ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - MIPI_DCS_SET_PIXEL_FORMAT, &cmd_params, 1); + MIPI_DCS_SET_PIXEL_FORMAT, &temp_cmd_params, 2); if (ret < 0) { return ret; } diff --git a/todo.txt b/todo.txt index d8f19e584ddc0..8f0d2b9339dac 100644 --- a/todo.txt +++ b/todo.txt @@ -294,3 +294,82 @@ + +/*****************************/ +@NOTE(Emilio): Handmade Sample to test individual pixel color and memory writing. +#include +#include +#include +#include + + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; + + +typedef struct +{ + s32 Width; + s32 Height; + s32 BytesPerPixel; + u8* Memory; +} zephyr_graphics_buffer; + + +//@IMPORTANT Color is in u16 + +#define SQUARE_WIDTH 60 +#define X_POS (466 / 2) - SQUARE_WIDTH +#define Y_POS (466 / 2) - SQUARE_WIDTH + +int main(void) +{ + const struct device* DisplayController = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); + + struct display_capabilities Capabilities = {}; + display_get_capabilities(DisplayController, &Capabilities); + + zephyr_graphics_buffer GraphicsBuffer = {}; + GraphicsBuffer.Width = 466; + GraphicsBuffer.Height = 466; + GraphicsBuffer.BytesPerPixel = 2; + u32 GraphicsBufferMemorySize = GraphicsBuffer.Width * GraphicsBuffer.Height * GraphicsBuffer.BytesPerPixel; +// GraphicsBuffer.Memory = (u8*)malloc(GraphicsBufferMemorySize); +// memset(GraphicsBuffer.Memory, 0xFF, GraphicsBufferMemorySize); + + struct display_buffer_descriptor Descriptor = {}; + + Descriptor.buf_size = GraphicsBufferMemorySize; + Descriptor.width = GraphicsBuffer.Width; + Descriptor.height = GraphicsBuffer.Height; + Descriptor.pitch = GraphicsBuffer.Width; + Descriptor.frame_incomplete = true; + + u8 Color = 0xAAFF; + display_write(DisplayController, 0, 0, &Descriptor, &Color); + + +// memset(GraphicsBuffer.Memory, 0x3812, GraphicsBufferMemorySize); + //display_write(DisplayController, X_POS, Y_POS, &Descriptor, GraphicsBuffer.Memory); + display_write(DisplayController, 50, 50, &Descriptor, 0xFF); +// display_write(DisplayController, 350, 350, &Descriptor, GraphicsBuffer.Memory); + + /* + for(u32 Y = 300; Y < GraphicsBuffer.Height; Y++) + { + for(u32 X = 100; X < GraphicsBuffer.Width; X++) + { + display_write(DisplayController, X, Y, &Descriptor, GraphicsBuffer.Memory); + } + } + */ + +// display_blanking_off(DisplayController); + return 0; +} + From 14936e92a16adc100a0a3bbe518cc348c411877c Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Tue, 14 Oct 2025 09:26:13 -0500 Subject: [PATCH 16/16] commit of clean build always on top, #removing touch screen support in dts until driver is ready --- boards/shields/zc143ac72mipi/zc143ac72mipi.overlay | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay index 69e3e7b9f13db..98f23dacd376e 100644 --- a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay +++ b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay @@ -7,9 +7,10 @@ / { chosen { zephyr,display = &co5300_zc143ac72mipi; - zephyr,touch = &tma525b_zc143ac72mipi; +// zephyr,touch = &tma525b_zc143ac72mipi; }; + /* en_mipi_display_g1120b0mipi: enable-mipi-display { compatible = "regulator-fixed"; regulator-name = "en_mipi_display"; @@ -23,8 +24,9 @@ display = <&co5300_zc143ac72mipi>; invert-y; }; + */ }; - +/* &nxp_mipi_i2c { status = "okay"; @@ -33,12 +35,14 @@ * Note- the actual controller present on this IC is a FT3267, * but the FT35336 driver in Zephyr supports this IC. */ + /* compatible = "focaltech,tma525b"; reg = <0x24>; int-gpio = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; reset-gpio = <&nxp_mipi_connector 28 GPIO_ACTIVE_LOW>; }; }; +*/ &zephyr_mipi_dsi { status = "okay";