From 437c2841e3a2f04ee70c785c4c206edadf29f19f Mon Sep 17 00:00:00 2001 From: Kate Wang Date: Thu, 6 Nov 2025 18:37:12 +0800 Subject: [PATCH 1/4] samples: drivers: display: Add user configuration Add user configuration of buffer address alignment and update area pitch alignment. Signed-off-by: Kate Wang --- samples/drivers/display/Kconfig | 16 ++++++++++++++++ .../mimxrt700_evk_mimxrt798s_cm33_cpu0.conf | 8 ++++++++ samples/drivers/display/src/main.c | 8 +++++--- 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 samples/drivers/display/Kconfig create mode 100644 samples/drivers/display/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf diff --git a/samples/drivers/display/Kconfig b/samples/drivers/display/Kconfig new file mode 100644 index 0000000000000..43b0ae3ed27a0 --- /dev/null +++ b/samples/drivers/display/Kconfig @@ -0,0 +1,16 @@ +# Private config options for display sample + +# Copyright (c) 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Display sample application" + +source "Kconfig.zephyr" + +config SAMPLE_BUFFER_ADDR_ALIGN + int "The display buffer address alignment" + default 1 + +config SAMPLE_PITCH_ALIGN + int "The update area pitch alignment" + default 1 diff --git a/samples/drivers/display/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf b/samples/drivers/display/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf new file mode 100644 index 0000000000000..a3429f2c531f3 --- /dev/null +++ b/samples/drivers/display/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf @@ -0,0 +1,8 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SAMPLE_BUFFER_ADDR_ALIGN=64 +CONFIG_SAMPLE_PITCH_ALIGN=64 diff --git a/samples/drivers/display/src/main.c b/samples/drivers/display/src/main.c index 7616ef61c7010..273349e5897d4 100644 --- a/samples/drivers/display/src/main.c +++ b/samples/drivers/display/src/main.c @@ -271,6 +271,8 @@ int main(void) rect_w = capabilities.x_resolution; } + rect_w = ROUND_UP(rect_w, CONFIG_SAMPLE_PITCH_ALIGN); + buf_size = rect_w * rect_h; if (buf_size < (capabilities.x_resolution * h_step)) { @@ -328,7 +330,7 @@ int main(void) #endif } - buf = k_malloc(buf_size); + buf = k_aligned_alloc(CONFIG_SAMPLE_BUFFER_ADDR_ALIGN, buf_size); if (buf == NULL) { LOG_ERR("Could not allocate memory. Aborting sample."); @@ -342,7 +344,7 @@ int main(void) (void)memset(buf, bg_color, buf_size); buf_desc.buf_size = buf_size; - buf_desc.pitch = capabilities.x_resolution; + buf_desc.pitch = ROUND_UP(capabilities.x_resolution, CONFIG_SAMPLE_PITCH_ALIGN); buf_desc.width = capabilities.x_resolution; buf_desc.height = h_step; @@ -374,7 +376,7 @@ int main(void) } } - buf_desc.pitch = rect_w; + buf_desc.pitch = ROUND_UP(rect_w, CONFIG_SAMPLE_PITCH_ALIGN); buf_desc.width = rect_w; buf_desc.height = rect_h; From 57d6b9e7c78a4e61d17aa24fa8525e61587d8d02 Mon Sep 17 00:00:00 2001 From: Kate Wang Date: Thu, 6 Nov 2025 18:40:16 +0800 Subject: [PATCH 2/4] samples: lvgl: Add board specific configuration for mimxrt700_evk The mimxrt700_evk uses DC8000 to drive panel which requires a 64 byte align of buffer address and stride. Signed-off-by: Kate Wang --- .../boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 samples/modules/lvgl/demos/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf diff --git a/samples/modules/lvgl/demos/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf b/samples/modules/lvgl/demos/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf new file mode 100644 index 0000000000000..580b4ff5d42f6 --- /dev/null +++ b/samples/modules/lvgl/demos/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.conf @@ -0,0 +1,10 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_LV_Z_MEM_POOL_SIZE=81920 +# RT700 uses DC8000 to drive all panels which requires a 64 byte align of buffer address and stride. +CONFIG_LV_DRAW_BUF_STRIDE_ALIGN=64 +CONFIG_LV_DRAW_BUF_ALIGN=64 From 2220811cc893732e33f1e537c3d9f6702406b725 Mon Sep 17 00:00:00 2001 From: Kate Wang Date: Fri, 28 Nov 2025 14:16:40 +0800 Subject: [PATCH 3/4] drivers: display: display_co5300: Update panel driver 1. Fix wrong backlight pin in driver overlay 2. Remove the power-on pin configuration in code and binding, and add mipi display panel regulator in panel overlay instead. Set regulator-boot-on' to true means the power-on pin will be enabled uring system boot. 3. Remove 'last_known_framebuffer' from panel data structure. It is not used anywhere 4. Fix bug in 'co5300_set_pixel_format' function. 5. Fix the issue that the panel does not support start coordinates and the width/height of the updated area being odd value. Solution: In panel driver, maintain a full screen-sized buffer, its address and pitch alignment is configurable in device tree and shall be compliant with the display controller's requirements. It can be placed in RAM or if the RAM space is not enough it can also be placed in other memory resion. When there is a frame update request, the updated area will be first filled to the buffer, if the area's size or coordinate is odd, adjust the value so the real updated area covers the requested updated area, then use this buffer to send pixel to panel, this can ensure the updated area's size and coordinate are always even. Signed-off-by: Kate Wang --- .../zc143ac72mipi/zc143ac72mipi.overlay | 10 +- drivers/display/display_co5300.c | 364 +++++++++++------- dts/bindings/display/chipone,co5300.yaml | 24 +- 3 files changed, 259 insertions(+), 139 deletions(-) diff --git a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay index 39974c25b9fde..3ce68aacf7b36 100644 --- a/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay +++ b/boards/shields/zc143ac72mipi/zc143ac72mipi.overlay @@ -8,6 +8,13 @@ chosen { zephyr,display = &co5300_zc143ac72mipi; }; + + en_mipi_display_zc143ac72mipi: enable-mipi-display { + compatible = "regulator-fixed"; + regulator-name = "en_mipi_display"; + enable-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; }; &zephyr_mipi_dsi { @@ -20,9 +27,8 @@ compatible = "chipone,co5300"; reg = <0x0>; reset-gpios = <&nxp_mipi_connector 21 GPIO_ACTIVE_HIGH>; - backlight-gpios = <&nxp_mipi_connector 34 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>; diff --git a/drivers/display/display_co5300.c b/drivers/display/display_co5300.c index 9fecef17799b8..934c14f3a19a3 100644 --- a/drivers/display/display_co5300.c +++ b/drivers/display/display_co5300.c @@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(co5300, CONFIG_DISPLAY_LOG_LEVEL); #include #include #include - +#include #include #include @@ -40,11 +40,13 @@ 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; struct k_sem tear_effect_sem; + /* Pointer to framebuffer */ + uint8_t *frame_ptr; + uint32_t frame_pitch; }; /* Organized as MIPI_CMD | SIZE OF MIPI PARAM | MIPI PARAM */ @@ -62,9 +64,6 @@ 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) { @@ -96,6 +95,53 @@ static int co5300_blanking_off(const struct device *dev) return -ENOTSUP; } +static void co5300_copy_and_adjust_coordinates(const struct device *dev, + const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, + const void *buf, + uint16_t *local_x, uint16_t *local_y, + struct display_buffer_descriptor *local_desc) +{ + struct co5300_data *data = dev->data; + const uint8_t *src; + uint8_t *dst; + + /* Copy the update area to the framebuffer */ + src = buf; + dst = data->frame_ptr + (y * data->frame_pitch * data->bytes_per_pixel) + + (x * data->bytes_per_pixel); + for (uint16_t row = 0; row < desc->height; row++) { + memcpy(dst, src, desc->width * data->bytes_per_pixel); + src += desc->pitch * data->bytes_per_pixel; + dst += data->frame_pitch * data->bytes_per_pixel; + } + + /* + * Initialize descriptor for local frame buffer. + * The start coordinates and the width/height of the updated area + * cannot be odd value for the panel. Adjust them to be even. + */ + if (x % 2 != 0) { + *local_x = x - 1; + local_desc->width = desc->width + 1U; + } else { + *local_x = x; + local_desc->width = desc->width; + } + if (y % 2 != 0) { + *local_y = y - 1; + local_desc->height = desc->height + 1U; + } else { + *local_y = y; + local_desc->height = desc->height; + } + local_desc->width = ROUND_UP(local_desc->width, 2U); + local_desc->height = ROUND_UP(local_desc->height, 2U); + local_desc->pitch = data->frame_pitch; + local_desc->frame_incomplete = desc->frame_incomplete; + local_desc->buf_size = local_desc->width * local_desc->height * data->bytes_per_pixel; +} + static int co5300_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, @@ -104,27 +150,46 @@ 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_xpos; - uint16_t end_xpos; - uint16_t start_ypos; - uint16_t end_ypos; - const uint8_t *framebuffer_addr; + uint16_t start_pos; + uint16_t end_pos; 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; + const uint8_t *src; + uint32_t tx_size = 0U; + uint16_t local_x, local_y; + struct display_buffer_descriptor local_desc = {0}; + + /* Check whether the updated area is outside of the panel frame. */ + if ((x > config->panel_width) || (y > config->panel_height) || + ((x + desc->width) > config->panel_width) || + ((y + desc->height) > config->panel_height)) { + LOG_ERR("Update area outside panel dimensions"); + return -EINVAL; + } - LOG_DBG("WRITE:: W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); + /* Check whether the updated area is valid */ + if (desc->width == 0 || desc->height == 0) { + LOG_ERR("The height/width of the update area cannot be 0"); + return -EINVAL; + } + + /* Copy data to framebuffer and adjust coordinates for even values */ + co5300_copy_and_adjust_coordinates(dev, x, y, desc, buf, &local_x, &local_y, &local_desc); - /* Set column address of target area */ + /* + * Set column address of target area. The circular panel actually starts + * to show from row 6, row 0~5 are cut off physically. The actual display + * area is row 6~472 and line 0~466. So adjust coordinates accordingly. + */ /* First two bytes are starting X coordinate */ - start_xpos = x; - sys_put_be16(start_xpos, &cmd_params[0]); + start_pos = local_x + 6U; + sys_put_be16(start_pos, &cmd_params[0]); /* Second two bytes are ending X coordinate */ - end_xpos = x + desc->width - 1; - sys_put_be16(end_xpos, &cmd_params[2]); + end_pos = local_x + local_desc.width + 5U; + sys_put_be16(end_pos, &cmd_params[2]); ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_COLUMN_ADDRESS, cmd_params, sizeof(cmd_params)); @@ -134,12 +199,12 @@ static int co5300_write(const struct device *dev, /* Set page address of target area */ /* First two bytes are starting Y coordinate */ - start_ypos = y; - sys_put_be16(start_ypos, &cmd_params[0]); + start_pos = local_y; + sys_put_be16(start_pos, &cmd_params[0]); /* Second two bytes are ending Y coordinate */ - end_ypos = y + desc->height - 1; - sys_put_be16(end_ypos, &cmd_params[2]); + end_pos = local_y + local_desc.height - 1; + sys_put_be16(end_pos, &cmd_params[2]); ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_PAGE_ADDRESS, cmd_params, sizeof(cmd_params)); @@ -155,34 +220,40 @@ static int co5300_write(const struct device *dev, k_sem_take(&data->tear_effect_sem, K_FOREVER); } - - /* Start filling out the framebuffer */ - framebuffer_addr = buf; - framebuffer_size = desc->width * desc->height * data->bytes_per_pixel; + /* Start memory write. */ + /* The address and the total pixel size of the updated area. */ + src = data->frame_ptr + (local_y * data->frame_pitch * data->bytes_per_pixel) + + (local_x * data->bytes_per_pixel); + tx_size = local_desc.buf_size; msg.type = MIPI_DSI_DCS_LONG_WRITE; msg.flags = MCUX_DSI_2L_FB_DATA; - msg.user_data = (void *)desc; + msg.user_data = &local_desc; msg.cmd = MIPI_DCS_WRITE_MEMORY_START; - while (framebuffer_size > 0) { - msg.tx_len = framebuffer_size; - msg.tx_buf = framebuffer_addr; + while (tx_size > 0) { + msg.tx_len = tx_size; + msg.tx_buf = src; bytes_written = (int)mipi_dsi_transfer(config->mipi_dsi, config->channel, &msg); if (bytes_written < 0) { return bytes_written; } + tx_size -= bytes_written; + + if (tx_size == 0U) { + break; + } + /* Advance source pointer and decrement remaining */ - if (desc->pitch > desc->width) { + if (local_desc.pitch > local_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); + src += bytes_written + total_bytes_sent / + (local_desc.width * data->bytes_per_pixel) * + ((local_desc.pitch - local_desc.width) * data->bytes_per_pixel); } else { - framebuffer_addr += bytes_written; + src += bytes_written; } - framebuffer_size -= bytes_written; /* All future commands should use WRITE_MEMORY_CONTINUE */ msg.cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; @@ -230,37 +301,48 @@ 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 cmd_register = pixel_format_bgr_cmds[0]; - uint8_t cmd_param_size = pixel_format_bgr_cmds[1]; - uint8_t cmd_params = pixel_format_bgr_cmds[2]; + uint8_t cmd_params[2]; int ret; + uint8_t mipi_pixel_format, bytes_per_pixel; switch (pixel_format) { case PIXEL_FORMAT_RGB_565: - mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - cmd_register, &cmd_params, cmd_param_size); - - cmd_params = pixel_format_bgr_cmds[2]; - data->pixel_format = MIPI_DSI_PIXFMT_RGB565; - cmd_params = MIPI_DCS_PIXEL_FORMAT_16BIT; - data->bytes_per_pixel = 2; + mipi_pixel_format = MIPI_DSI_PIXFMT_RGB565; + bytes_per_pixel = 2U; + cmd_params[0] = MIPI_DCS_ADDRESS_MODE_BGR; + cmd_params[1] = MIPI_DCS_PIXEL_FORMAT_16BIT; break; case PIXEL_FORMAT_RGB_888: - data->pixel_format = MIPI_DSI_PIXFMT_RGB888; - cmd_params = MIPI_DCS_PIXEL_FORMAT_24BIT; - data->bytes_per_pixel = 3; + mipi_pixel_format = MIPI_DSI_PIXFMT_RGB888; + bytes_per_pixel = 3U; + cmd_params[0] = 0U; + cmd_params[1] = MIPI_DCS_PIXEL_FORMAT_24BIT; break; default: /* Other display formats not implemented */ return -ENOTSUP; } + /* + * Controller-specific requirement, when using RGB565 format + * the order shall be set to BGR. + */ + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_ADDRESS_MODE, &cmd_params[0], 1U); + if (ret < 0) { + return ret; + } + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - 0x36, &cmd_params, 1); + MIPI_DCS_SET_PIXEL_FORMAT, &cmd_params[1], 1U); if (ret < 0) { return ret; } + /* Update the format in the device data after DCS command succeeds. */ + data->bytes_per_pixel = bytes_per_pixel; + data->pixel_format = mipi_pixel_format; + return 0; } @@ -274,13 +356,78 @@ static int co5300_set_orientation(const struct device *dev, return -ENOTSUP; } +static int co5300_reset(const struct device *dev) +{ + const struct co5300_config *config = dev->config; + int ret = 0; + + 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; + } + + k_sleep(K_MSEC(10)); + 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(30)); + gpio_pin_set_dt(&config->reset_gpios, 1); + if (ret < 0) { + LOG_ERR("Could not pull reset high (%d)", ret); + return ret; + } + k_sleep(K_MSEC(150)); + } + + return 0; +} + +static int co5300_setup_tear_effect(const struct device *dev) +{ + const struct co5300_config *config = dev->config; + struct co5300_data *data = dev->data; + int ret = 0; + + 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_gpios, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure TE interrupt (%d)", ret); + return ret; + } + + gpio_init_callback(&data->tear_effect_gpio_cb, co5300_tear_effect_isr_handler, + 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; + } + + /* Setup semaphore for using the tear effect pin */ + k_sem_init(&data->tear_effect_sem, 0, 1); + } + + return 0; +} + 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 temp_cmd_params[2]; uint8_t *ptr_to_cmd_register = 0; uint8_t *ptr_to_last_cmd = 0; uint8_t cmd_params = 0; @@ -298,43 +445,9 @@ static int co5300_init(const struct device *dev) } /* Perform GPIO Reset */ - 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_gpios, 1); - if (ret < 0) { - LOG_ERR("Could not pull power high (%d)", ret); - return ret; - } - - k_sleep(K_MSEC(100)); - - if (config->reset_gpios.port != NULL) { - ret = gpio_pin_set_dt(&config->power_gpios, 1); - if (ret < 0) { - LOG_ERR("Could not set power GPIO (%d)", ret); - return ret; - } - - 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_gpios, 1); - if (ret < 0) { - LOG_ERR("Could not pull reset high (%d)", ret); - return ret; - } - k_sleep(K_MSEC(150)); - } + ret = co5300_reset(dev); + if (ret < 0) { + return ret; } /* Set the LCM init settings. */ @@ -343,7 +456,10 @@ static int co5300_init(const struct device *dev) ptr_to_cmd_register = lcm_init_settings.cmd_code; ptr_to_last_cmd = lcm_init_settings.cmd_code + lcm_init_settings.size; while (ptr_to_cmd_register < ptr_to_last_cmd) { - /* Walk through the display_cmds array, incrementing the ptr by the param size */ + /* + * Walk through the display_cmds array, + * incrementing the ptr by the param size. + */ cmd_register = *ptr_to_cmd_register++; cmd_param_size = *ptr_to_cmd_register++; cmd_params = *ptr_to_cmd_register; @@ -357,34 +473,17 @@ static int co5300_init(const struct device *dev) } /* Set pixel format */ - cmd_register = 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, - cmd_register, &cmd_params, cmd_param_size); - if (data->pixel_format == MIPI_DSI_PIXFMT_RGB888) { - cmd_params = (uint8_t)MIPI_DCS_PIXEL_FORMAT_24BIT; - data->bytes_per_pixel = 3; + co5300_set_pixel_format(dev, PIXEL_FORMAT_RGB_888); } else if (data->pixel_format == MIPI_DSI_PIXFMT_RGB565) { - cmd_params = (uint8_t)MIPI_DCS_PIXEL_FORMAT_16BIT; - data->bytes_per_pixel = 2; + co5300_set_pixel_format(dev, PIXEL_FORMAT_RGB_565); } else { /* Unsupported pixel format */ LOG_ERR("Pixel format not supported"); return -ENOTSUP; } - 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, &temp_cmd_params, 2); - if (ret < 0) { - return ret; - } - - /* Command the display to enter sleep mode */ + /* 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); @@ -405,32 +504,15 @@ static int co5300_init(const struct device *dev) } /* Setup tear effect pin and callback */ - 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_gpios, - GPIO_INT_EDGE_TO_ACTIVE); - if (ret < 0) { - LOG_ERR("Could not configure TE interrupt (%d)", ret); - return ret; - } - - gpio_init_callback(&data->tear_effect_gpio_cb, co5300_tear_effect_isr_handler, - 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; - } - - /* Setup semaphore for using the tear effect pin */ - k_sem_init(&data->tear_effect_sem, 0, 1); + ret = co5300_setup_tear_effect(dev); + if (ret < 0) { + return ret; } + /* Clear frame buffer. */ + memset(data->frame_ptr, 0, + config->panel_height * data->frame_pitch * data->bytes_per_pixel); + /* Enable display */ return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); @@ -446,6 +528,19 @@ static DEVICE_API(display, co5300_api) = { .set_orientation = co5300_set_orientation, }; +/* Place the frame buffer in secondary RAM if specified, otherwise use default RAM */ +#define CO5300_FRAMEBUFFER_PLACEMENT(node_id) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(node_id, ext_ram), \ + (Z_GENERIC_SECTION(LINKER_DT_NODE_REGION_NAME(DT_INST_PHANDLE(node_id, ext_ram)))), ()) + +#define CO5300_FRAMEBUFFER_DECL(node_id) \ + CO5300_FRAMEBUFFER_PLACEMENT(node_id) static uint8_t \ + __aligned(DT_INST_PROP(node_id, addr_align)) \ + co5300_frame_buffer_##node_id[DT_INST_PROP(node_id, height) * 3U * \ + ROUND_UP(DT_INST_PROP(node_id, width), DT_INST_PROP(node_id, pitch_align))] + +#define CO5300_FRAMEBUFFER(node_id) co5300_frame_buffer_##node_id + #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)), \ @@ -458,8 +553,12 @@ static DEVICE_API(display, co5300_api) = { .panel_width = DT_INST_PROP(node_id, width), \ .panel_height = DT_INST_PROP(node_id, height), \ }; \ + CO5300_FRAMEBUFFER_DECL(node_id); \ static struct co5300_data co5300_data_##node_id = { \ .pixel_format = DT_INST_PROP(node_id, pixel_format), \ + .frame_ptr = CO5300_FRAMEBUFFER(node_id), \ + .frame_pitch = ROUND_UP(DT_INST_PROP(node_id, width), \ + DT_INST_PROP(node_id, pitch_align)), \ }; \ DEVICE_DT_INST_DEFINE(node_id, \ &co5300_init, \ @@ -470,5 +569,4 @@ static DEVICE_API(display, co5300_api) = { CONFIG_APPLICATION_INIT_PRIORITY, \ &co5300_api); - DT_INST_FOREACH_STATUS_OKAY(CO5300_DEVICE_INIT) diff --git a/dts/bindings/display/chipone,co5300.yaml b/dts/bindings/display/chipone,co5300.yaml index b7559462eefae..b164236d99fdb 100644 --- a/dts/bindings/display/chipone,co5300.yaml +++ b/dts/bindings/display/chipone,co5300.yaml @@ -29,8 +29,24 @@ properties: VSYNC interval. This permits the controller to send new display data during a VSYNC interval, removing tearing. - power-gpios: - type: phandle-array + pitch-align: + type: int + default: 1 description: | - The RESETn pin is asserted to disable the controller causing a hard - reset. The controller receives this as an active-low signal. + The CO5300 driver maintains an internal frame buffer. This property + serves for defining a pitch for it that's compliant with the SoC's + display controller's requirements. + + addr-align: + type: int + default: 1 + description: | + The CO5300 driver maintains an internal frame buffer. This property + serves for defining an alignment for its address that's compliant + with the SoC's display controller's requirements. + + ext-ram: + type: phandle + description: | + Secondary RAM in which the panel controller's frame buffer will + be stored. If not defined, the 'zephyr,ram' chosen memory will be used. From 1e666df8708fd0a411b65c6c310772ab0b94d2cf Mon Sep 17 00:00:00 2001 From: Kate Wang Date: Thu, 27 Nov 2025 14:18:00 +0800 Subject: [PATCH 4/4] boards: shield: Update shield support for zc143ac72mipi The zc143ac72mipi panel can only accept update area that has even size and coordinates, so the panel driver was updated to maintain a buffer to collect all dirty areas. This buffer shall have address and pitch alignments which compliant to the board's display driver's requirement, and can be placed outside of ram. Update the board specific overlay to add such configurations. Signed-off-by: Kate Wang --- .../boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay b/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay index f8da3f636192f..20850325c153b 100644 --- a/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay +++ b/boards/shields/zc143ac72mipi/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay @@ -25,3 +25,9 @@ &gpio3 { status = "okay"; }; + +&co5300_zc143ac72mipi { + ext-ram = <&sram1>; + addr-align = <64>; + pitch-align = <64>; +};