From 0eef4fe15040125a9d20c5ee7bcec6179f6bf71d Mon Sep 17 00:00:00 2001 From: Danh Doan Date: Thu, 12 Dec 2024 10:22:51 +0700 Subject: [PATCH] drivers: display: extend support for renesas,ra-glcdc driver Change pinctrl-0 dts prop as optional in case DSI display is used Add these APIs support: set_brightness, set_contrast, get_framebuffer Add a new config to select frame buffer section Signed-off-by: Danh Doan --- boards/renesas/ek_ra8d1/Kconfig.defconfig | 14 +- drivers/display/Kconfig.renesas_ra | 10 +- drivers/display/display_renesas_ra.c | 442 ++++++++++++--------- drivers/display/display_renesas_ra.h | 126 ++++-- dts/bindings/display/renesas,ra-glcdc.yaml | 90 ++++- 5 files changed, 453 insertions(+), 229 deletions(-) diff --git a/boards/renesas/ek_ra8d1/Kconfig.defconfig b/boards/renesas/ek_ra8d1/Kconfig.defconfig index db92a2bd461..4e44f332563 100644 --- a/boards/renesas/ek_ra8d1/Kconfig.defconfig +++ b/boards/renesas/ek_ra8d1/Kconfig.defconfig @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Renesas Electronics Corporation +# Copyright (c) 2024-2025 Renesas Electronics Corporation # SPDX-License-Identifier: Apache-2.0 if BOARD_EK_RA8D1 @@ -10,11 +10,21 @@ config NET_L2_ETHERNET endif # NETWORKING +if DISPLAY + if SHIELD_RTKMIPILCDB00000BE config MEMC default y +config RENESAS_RA_GLCDC_FRAME_BUFFER_SECTION + default ".sdram" + depends on RENESAS_RA_GLCDC + +endif # SHIELD_RTKMIPILCDB00000BE + +endif # DISPLAY + if LVGL config LV_Z_VDB_CUSTOM_SECTION @@ -22,6 +32,4 @@ config LV_Z_VDB_CUSTOM_SECTION endif # LVGL -endif # SHIELD_RTKMIPILCDB00000BE - endif # BOARD_EK_RA8D1 diff --git a/drivers/display/Kconfig.renesas_ra b/drivers/display/Kconfig.renesas_ra index 4eaaeb99196..8bd872b240f 100644 --- a/drivers/display/Kconfig.renesas_ra +++ b/drivers/display/Kconfig.renesas_ra @@ -1,6 +1,6 @@ # Renesas RA Family -# Copyright (c) 2024 Renesas Electronics Corporation +# Copyright (c) 2024-2025 Renesas Electronics Corporation # SPDX-License-Identifier: Apache-2.0 config RENESAS_RA_GLCDC @@ -23,6 +23,14 @@ config RENESAS_RA_GLCDC_FB_NUM - 1 single frame buffer in RENESAS RA GLCDC driver. - 2 double frame buffer in RENESAS RA GLCDC driver. +config RENESAS_RA_GLCDC_FRAME_BUFFER_SECTION + string "RAM memory section to place frame buffer" + depends on RENESAS_RA_GLCDC_FB_NUM > 0 + help + RAM memory section name to place frame buffer. + Example: to place display frame buffer in external SDRAM (.sdram section) + CONFIG_RENESAS_RA_GLCDC_FRAME_BUFFER_SECTION=".sdram" + if LVGL # Force display buffers to be aligned to cache line size (64 bytes) diff --git a/drivers/display/display_renesas_ra.c b/drivers/display/display_renesas_ra.c index 24df57099cd..9d53aa55e83 100644 --- a/drivers/display/display_renesas_ra.c +++ b/drivers/display/display_renesas_ra.c @@ -17,7 +17,6 @@ LOG_MODULE_REGISTER(display_renesas_ra, CONFIG_DISPLAY_LOG_LEVEL); -void glcdc_line_detect_isr(void); struct display_ra_config { const struct pinctrl_dev_config *pincfg; const struct gpio_dt_spec backlight_gpio; @@ -25,31 +24,40 @@ struct display_ra_config { struct clock_control_ra_subsys_cfg clock_glcdc_subsys; uint16_t height; uint16_t width; - uint32_t display_frame_size; - enum display_pixel_format pixel_format; void (*irq_configure)(void); }; struct display_ra_data { glcdc_instance_ctrl_t display_ctrl; display_cfg_t display_fsp_cfg; - uint8_t *p_base; - uint32_t frame_buffer_len; const uint8_t *pend_buf; const uint8_t *front_buf; uint8_t pixel_size; + enum display_pixel_format current_pixel_format; uint8_t *frame_buffer; - struct k_sem sem; + uint32_t frame_buffer_len; + struct k_sem frame_buf_sem; }; +extern void glcdc_line_detect_isr(void); + static void renesas_ra_glcdc_isr(const struct device *dev) { + ARG_UNUSED(dev); + glcdc_line_detect_isr(); +} + +static void renesas_ra_callback_adapter(display_callback_args_t *p_args) +{ + const struct device *dev = p_args->p_context; struct display_ra_data *data = dev->data; - glcdc_line_detect_isr(); - if (data->front_buf != data->pend_buf) { - data->front_buf = data->pend_buf; - k_sem_give(&data->sem); + if (p_args->event == DISPLAY_EVENT_LINE_DETECTION) { + if (data->front_buf != data->pend_buf) { + data->front_buf = data->pend_buf; + } + + k_sem_give(&data->frame_buf_sem); } } @@ -58,24 +66,31 @@ static int ra_display_write(const struct device *dev, const uint16_t x, const ui { struct display_ra_data *data = dev->data; const struct display_ra_config *config = dev->config; - uint8_t *dst = NULL; - const uint8_t *src = buf; const uint8_t *l_pend_buf = NULL; - uint16_t row; - int err; + bool vsync_wait = false; + fsp_err_t err; - __ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width"); - __ASSERT((desc->pitch * BYTE_PER_PIXEL * desc->height) <= desc->buf_size, - "Input buffer too small"); + if (desc->pitch < desc->width) { + LOG_ERR("Pitch is smaller than width"); + return -EINVAL; + } - if (x == 0 && y == 0 && desc->height == DISPLAY_VSIZE && desc->width == DISPLAY_HSIZE && - desc->pitch == DISPLAY_HSIZE) { + if ((desc->pitch * data->pixel_size * desc->height) > desc->buf_size) { + LOG_ERR("Input buffer too small"); + return -EINVAL; + } + + if (x == 0 && y == 0 && desc->height == config->height && desc->width == config->width) { l_pend_buf = buf; } else { - if (CONFIG_RENESAS_RA_GLCDC_FB_NUM == 0) { - LOG_ERR("Partial write requires internal frame buffer"); - return -ENOTSUP; - } +#if CONFIG_RENESAS_RA_GLCDC_FB_NUM == 0 + LOG_ERR("Partial write requires internal frame buffer"); + return -ENOTSUP; +#else + const uint8_t *src = buf; + uint8_t *dst = NULL; + uint16_t row; + dst = data->frame_buffer; if (CONFIG_RENESAS_RA_GLCDC_FB_NUM == 2) { @@ -99,24 +114,37 @@ static int ra_display_write(const struct device *dev, const uint16_t x, const ui dst += (config->width * data->pixel_size); src += (desc->pitch * data->pixel_size); } +#endif /* CONFIG_RENESAS_RA_GLCDC_FB_NUM == 0 */ } - if (data->front_buf == l_pend_buf) { - return 0; - } + k_sem_reset(&data->frame_buf_sem); - k_sem_reset(&data->sem); + if (data->front_buf != l_pend_buf) { + data->pend_buf = l_pend_buf; - data->pend_buf = l_pend_buf; + err = R_GLCDC_BufferChange(&data->display_ctrl, (uint8_t *)data->pend_buf, + DISPLAY_FRAME_LAYER_1); + if (err != FSP_SUCCESS) { + LOG_ERR("GLCDC buffer change failed"); + return -EIO; + } - err = R_GLCDC_BufferChange(&data->display_ctrl, (uint8_t *)data->pend_buf, - DISPLAY_FRAME_LAYER_1); - if (err) { - LOG_ERR("GLCDC buffer change failed"); - return -EIO; + vsync_wait = true; + } + + if (data->display_ctrl.state != DISPLAY_STATE_DISPLAYING) { + err = R_GLCDC_Start(&data->display_ctrl); + if (err != FSP_SUCCESS) { + LOG_ERR("GLCDC start failed"); + return -EIO; + } + + vsync_wait = true; } - k_sem_take(&data->sem, K_FOREVER); + if (vsync_wait) { + k_sem_take(&data->frame_buf_sem, K_FOREVER); + } return 0; } @@ -146,65 +174,179 @@ static int ra_display_read(const struct device *dev, const uint16_t x, const uin static int ra_display_blanking_on(const struct device *dev) { const struct display_ra_config *config = dev->config; - int err; + int ret = 0; if (config->backlight_gpio.port != NULL) { - err = gpio_pin_set_dt(&config->backlight_gpio, 0); - if (err) { - LOG_ERR("Disable backlight failed! (%d)", err); - return err; - } + ret = gpio_pin_set_dt(&config->backlight_gpio, 0); } else { - return -ENOTSUP; + ret = -ENOTSUP; } - return 0; + return ret; } static int ra_display_blanking_off(const struct device *dev) { const struct display_ra_config *config = dev->config; - int err; + int ret = 0; if (config->backlight_gpio.port != NULL) { - err = gpio_pin_set_dt(&config->backlight_gpio, 1); - if (err) { - LOG_ERR("Enable backlight failed! (%d)", err); - return err; - } + ret = gpio_pin_set_dt(&config->backlight_gpio, 1); } else { - return -ENOTSUP; + ret = -ENOTSUP; } - return 0; + return ret; } static void ra_display_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { const struct display_ra_config *config = dev->config; + struct display_ra_data *data = dev->data; - memset(capabilities, 0, sizeof(struct display_capabilities)); capabilities->x_resolution = config->width; capabilities->y_resolution = config->height; capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_888 | PIXEL_FORMAT_ARGB_8888 | PIXEL_FORMAT_RGB_565; - capabilities->current_pixel_format = (config->pixel_format == PIXEL_FORMAT_RGB_888) - ? PIXEL_FORMAT_ARGB_8888 - : config->pixel_format; + capabilities->current_pixel_format = data->current_pixel_format; + capabilities->screen_info = 0U; } static int ra_display_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { const struct display_ra_config *config = dev->config; + struct display_ra_data *data = dev->data; + display_runtime_cfg_t layer_cfg; + enum display_pixel_format set_pixel_format; + display_in_format_t hardware_pixel_format; + uint32_t buf_len; + fsp_err_t err; - if (pixel_format == config->pixel_format) { + if (pixel_format == data->current_pixel_format) { return 0; } - LOG_ERR("Pixel format changes must be set in dts at build time."); - return -ENOTSUP; + + if (data->display_ctrl.state == DISPLAY_STATE_DISPLAYING) { + LOG_ERR("Cannot change the display format while displaying"); + return -EWOULDBLOCK; + } + + switch (pixel_format) { + case PIXEL_FORMAT_RGB_888: + set_pixel_format = PIXEL_FORMAT_ARGB_8888; + hardware_pixel_format = DISPLAY_IN_FORMAT_32BITS_RGB888; + break; + + case PIXEL_FORMAT_ARGB_8888: + set_pixel_format = PIXEL_FORMAT_ARGB_8888; + hardware_pixel_format = DISPLAY_IN_FORMAT_32BITS_ARGB8888; + break; + + case PIXEL_FORMAT_RGB_565: + set_pixel_format = PIXEL_FORMAT_RGB_565; + hardware_pixel_format = DISPLAY_IN_FORMAT_16BITS_RGB565; + break; + + default: + return -ENOTSUP; + } + + buf_len = (config->height * config->width * DISPLAY_BITS_PER_PIXEL(set_pixel_format)) >> 3; + + if (buf_len > data->frame_buffer_len) { + LOG_ERR("Frame buffer is smaller than new pixel format require"); + return -ENOTSUP; + } + + memcpy(&layer_cfg.input, &data->display_fsp_cfg.input[0], sizeof(display_input_cfg_t)); + memcpy(&layer_cfg.layer, &data->display_fsp_cfg.layer[0], sizeof(display_layer_t)); + layer_cfg.input.format = hardware_pixel_format; + layer_cfg.input.hstride = + ROUND_UP(layer_cfg.input.hsize * DISPLAY_BITS_PER_PIXEL(set_pixel_format), + NUM_BITS(uint64_t)) / + DISPLAY_BITS_PER_PIXEL(set_pixel_format); + + err = R_GLCDC_LayerChange(&data->display_ctrl, &layer_cfg, DISPLAY_FRAME_LAYER_1); + if (err != FSP_SUCCESS) { + LOG_ERR("Failed to change the pixel format"); + return -EIO; + } + + data->current_pixel_format = pixel_format; + data->pixel_size = DISPLAY_BITS_PER_PIXEL(set_pixel_format) >> 3; + + return 0; +} + +static int ra_display_color_config(const struct device *dev, + const display_correction_t *display_color_cfg) +{ + struct display_ra_data *data = dev->data; + fsp_err_t err; + int ret; + + err = R_GLCDC_ColorCorrection(&data->display_ctrl, display_color_cfg); + switch (err) { + case FSP_SUCCESS: + ret = 0; + break; + case FSP_ERR_INVALID_UPDATE_TIMING: + ret = -EWOULDBLOCK; + break; + default: + ret = -EIO; + break; + } + + return ret; +} + +#define RENESAS_RA_GLCDC_BRIGHTNESS_MAX 1023U + +static int ra_display_set_brightness(const struct device *dev, const uint8_t brightness) +{ + struct display_ra_data *data = dev->data; + const uint32_t brightness_adj = + DIV_ROUND_CLOSEST(brightness * RENESAS_RA_GLCDC_BRIGHTNESS_MAX, UINT8_MAX); + display_correction_t display_color_cfg; + + if (brightness_adj == 0) { + return -EINVAL; + } + + memcpy(&display_color_cfg.contrast, &data->display_fsp_cfg.output.contrast, + sizeof(display_contrast_t)); + display_color_cfg.brightness = (display_brightness_t){ + .enable = true, .r = brightness_adj, .g = brightness_adj, .b = brightness_adj}; + + return ra_display_color_config(dev, &display_color_cfg); +} + +static int ra_display_set_contrast(const struct device *dev, const uint8_t contrast) +{ + struct display_ra_data *data = dev->data; + display_correction_t display_color_cfg; + + if (contrast == 0) { + return -EINVAL; + } + + memcpy(&display_color_cfg.brightness, &data->display_fsp_cfg.output.brightness, + sizeof(display_brightness_t)); + display_color_cfg.contrast = + (display_contrast_t){.enable = true, .r = contrast, .g = contrast, .b = contrast}; + + return ra_display_color_config(dev, &display_color_cfg); +} + +static void *ra_display_get_framebuffer(const struct device *dev) +{ + struct display_ra_data *data = dev->data; + + return (void *)data->front_buf; } static DEVICE_API(display, display_api) = { @@ -214,6 +356,9 @@ static DEVICE_API(display, display_api) = { .set_pixel_format = ra_display_set_pixel_format, .write = ra_display_write, .read = ra_display_read, + .set_brightness = ra_display_set_brightness, + .set_contrast = ra_display_set_contrast, + .get_framebuffer = ra_display_get_framebuffer, }; static int display_init(const struct device *dev) @@ -235,12 +380,16 @@ static int display_init(const struct device *dev) R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT); #endif - err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); - if (err) { - LOG_ERR("pin function initial failed"); - return err; + + if (config->pincfg != NULL) { + err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (err) { + LOG_ERR("pin function initial failed"); + return err; + } } - k_sem_init(&data->sem, 0, 1); + + k_sem_init(&data->frame_buf_sem, 0, 1); err = clock_control_on(config->clock_dev, (clock_control_subsys_t)&config->clock_glcdc_subsys); @@ -261,12 +410,6 @@ static int display_init(const struct device *dev) return err; } - err = R_GLCDC_Start(&data->display_ctrl); - if (err) { - LOG_ERR("GLCDC start failed"); - return -EIO; - } - config->irq_configure(); return 0; @@ -286,146 +429,83 @@ static int display_init(const struct device *dev) #define IRQ_CONFIGURE_DEFINE(id) .irq_configure = glcdc_renesas_ra_configure_func_##id #define RENESAS_RA_FRAME_BUFFER_LEN(id) \ - (BYTE_PER_PIXEL * DT_INST_PROP(id, height) * DT_INST_PROP(id, width)) + (RENESAS_RA_GLCDC_PIXEL_BYTE_SIZE(id) * DT_INST_PROP(id, height) * DT_INST_PROP(id, width)) + +#ifdef CONFIG_RENESAS_RA_GLCDC_FRAME_BUFFER_SECTION +#define FRAME_BUFFER_SECTION Z_GENERIC_SECTION(CONFIG_RENESAS_RA_GLCDC_FRAME_BUFFER_SECTION) +#else +#define FRAME_BUFFER_SECTION +#endif /* CONFIG_RENESAS_RA_GLCDC_FRAME_BUFFER_SECTION */ + +#define RENESAS_RA_GLCDC_DEVICE_PINCTRL_INIT(n) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, pinctrl_0), (PINCTRL_DT_INST_DEFINE(n)), ()) + +#define RENESAS_RA_GLCDC_DEVICE_PINCTRL_GET(n) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, pinctrl_0), (PINCTRL_DT_INST_DEV_CONFIG_GET(n)), \ + (NULL)) #define RENESAS_RA_DEVICE_INIT(id) \ - PINCTRL_DT_INST_DEFINE(id); \ + RENESAS_RA_GLCDC_DEVICE_PINCTRL_INIT(id); \ IRQ_CONFIGURE_FUNC(id) \ - Z_GENERIC_SECTION(".sdram") \ - static uint8_t __aligned(64) \ + FRAME_BUFFER_SECTION static uint8_t __aligned(64) \ fb_background##id[CONFIG_RENESAS_RA_GLCDC_FB_NUM * RENESAS_RA_FRAME_BUFFER_LEN(id)]; \ static const glcdc_extended_cfg_t display_extend_cfg##id = { \ - .tcon_hsync = GLCDC_TCON_PIN_1, \ - .tcon_vsync = GLCDC_TCON_PIN_0, \ - .tcon_de = GLCDC_TCON_PIN_2, \ + .tcon_hsync = RENESAS_RA_GLCDC_TCON_HSYNC_PIN(id), \ + .tcon_vsync = RENESAS_RA_GLCDC_TCON_VSYNC_PIN(id), \ + .tcon_de = RENESAS_RA_GLCDC_TCON_DE_PIN(id), \ .correction_proc_order = GLCDC_CORRECTION_PROC_ORDER_BRIGHTNESS_CONTRAST2GAMMA, \ .clksrc = GLCDC_CLK_SRC_INTERNAL, \ - .clock_div_ratio = GLCDC_PANEL_CLK_DIVISOR_8, \ - .dithering_mode = GLCDC_DITHERING_MODE_TRUNCATE, \ - .dithering_pattern_A = GLCDC_DITHERING_PATTERN_11, \ - .dithering_pattern_B = GLCDC_DITHERING_PATTERN_11, \ - .dithering_pattern_C = GLCDC_DITHERING_PATTERN_11, \ - .dithering_pattern_D = GLCDC_DITHERING_PATTERN_11, \ - .phy_layer = NULL, \ - }; \ + .clock_div_ratio = RENESAS_RA_GLCDC_OUTPUT_CLOCK_DIV(id), \ + .phy_layer = NULL}; \ static struct display_ra_data ra_data##id = { \ .frame_buffer = fb_background##id, \ .frame_buffer_len = RENESAS_RA_FRAME_BUFFER_LEN(id), \ .front_buf = fb_background##id, \ .pend_buf = fb_background##id, \ - .pixel_size = BYTE_PER_PIXEL, \ - .p_base = (uint8_t *)&fb_background##id, \ + .pixel_size = RENESAS_RA_GLCDC_PIXEL_BYTE_SIZE(id), \ + .current_pixel_format = RENESAS_RA_DISPLAY_GET_PIXEL_FORMAT(id), \ .display_fsp_cfg = { \ - .input[0] = {.p_base = (uint32_t *)&fb_background##id, \ - .hsize = DISPLAY_HSIZE, \ - .vsize = DISPLAY_VSIZE, \ - .hstride = DISPLAY_BUFFER_STRIDE_PIXELS_INPUT0, \ - .format = \ - (INPUT_FORMAT_PIXEL == PANEL_PIXEL_FORMAT_RGB_565) \ - ? DISPLAY_IN_FORMAT_16BITS_RGB565 \ - : (INPUT_FORMAT_PIXEL == PANEL_PIXEL_FORMAT_RGB_888) \ - ? DISPLAY_IN_FORMAT_32BITS_RGB888 \ - : DISPLAY_IN_FORMAT_32BITS_ARGB8888, \ - .line_descending_enable = false, \ - .lines_repeat_enable = false, \ - .lines_repeat_times = 0}, \ - .input[1] = {.p_base = NULL, \ - .hsize = DISPLAY_HSIZE, \ - .vsize = DISPLAY_VSIZE, \ - .hstride = DISPLAY_BUFFER_STRIDE_PIXELS_INPUT1, \ - .format = DISPLAY_IN_FORMAT_16BITS_RGB565, \ + .input[0] = {.p_base = (uint32_t *)fb_background##id, \ + .hsize = DISPLAY_HSIZE(id), \ + .vsize = DISPLAY_VSIZE(id), \ + .hstride = RENESAS_RA_DISPLAY_BUFFER_HSTRIDE_BYTE(id), \ + .format = RENESAS_RA_GLCDC_IN_PIXEL_FORMAT(id), \ .line_descending_enable = false, \ .lines_repeat_enable = false, \ .lines_repeat_times = 0}, \ .layer[0] = {.coordinate = {.x = 0, .y = 0}, \ - .bg_color = {.byte = {.a = LAYER_ALPHA, \ - .r = LAYER_RED, \ - .g = LAYER_GREEN, \ - .b = LAYER_BLUE}}, \ - .fade_control = DISPLAY_FADE_CONTROL_NONE, \ - .fade_speed = 0}, \ - .layer[1] = {.coordinate = {.x = 0, .y = 0}, \ - .bg_color = {.byte = {.a = LAYER_ALPHA, \ - .r = LAYER_RED, \ - .g = LAYER_GREEN, \ - .b = LAYER_BLUE}}, \ + .bg_color = RENESAS_RA_GLCDC_BG_COLOR(id), \ .fade_control = DISPLAY_FADE_CONTROL_NONE, \ .fade_speed = 0}, \ - .output = {.htiming = {.total_cyc = \ - DT_INST_PROP(id, width) + \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - hback_porch) + \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - hfront_porch) + \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - hsync_len), \ - .display_cyc = DT_INST_PROP(id, width), \ - .back_porch = \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - hback_porch), \ - .sync_width = \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - hsync_len), \ - .sync_polarity = \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - hsync_active)}, \ - .vtiming = {.total_cyc = \ - DT_INST_PROP(id, height) + \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - vback_porch) + \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - vfront_porch) + \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - vsync_len), \ - .display_cyc = DT_INST_PROP(id, height), \ - .back_porch = \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - vback_porch), \ - .sync_width = \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - vsync_len), \ - .sync_polarity = \ - DT_PROP(DT_INST_CHILD(id, display_timings), \ - vsync_active)}, \ - .format = (OUTPUT_FORMAT_PIXEL == PANEL_PIXEL_FORMAT_RGB_565) \ - ? DISPLAY_OUT_FORMAT_16BITS_RGB565 \ - : DISPLAY_OUT_FORMAT_24BITS_RGB888, \ - .endian = DISPLAY_ENDIAN_LITTLE, \ - .color_order = DISPLAY_COLOR_ORDER_RGB, \ - .data_enable_polarity = DISPLAY_SIGNAL_POLARITY_HIACTIVE, \ - .sync_edge = DISPLAY_SIGNAL_SYNC_EDGE_FALLING, \ - .bg_color = {.byte = {.a = OUTPUT_ALPHA, \ - .r = OUTPUT_RED, \ - .g = OUTPUT_GREEN, \ - .b = OUTPUT_BLUE}}, \ - .brightness = {.enable = false, \ - .r = OUTPUT_RED, \ - .g = OUTPUT_GREEN, \ - .b = OUTPUT_BLUE}, \ - .contrast = {.enable = false, \ - .r = OUTPUT_RED, \ - .g = OUTPUT_GREEN, \ - .b = OUTPUT_BLUE}, \ + .input[1] = {.p_base = NULL}, \ + .output = {.htiming = RENESAS_RA_GLCDC_HTIMING(id), \ + .vtiming = RENESAS_RA_GLCDC_VTIMING(id), \ + .format = RENESAS_RA_GLCDC_OUT_PIXEL_FORMAT(id), \ + .endian = RENESAS_RA_GLCDC_OUTPUT_ENDIAN(id), \ + .color_order = RENESAS_RA_GLCDC_OUTPUT_COLOR_ODER(id), \ + .data_enable_polarity = \ + RENESAS_RA_GLCDC_OUTPUT_DE_POLARITY(id), \ + .sync_edge = RENESAS_RA_GLCDC_OUTPUT_SYNC_EDGE(id), \ + .bg_color = RENESAS_RA_GLCDC_BG_COLOR(id), \ + .brightness = {.enable = false}, \ + .contrast = {.enable = false}, \ .dithering_on = false}, \ - .p_callback = NULL, \ - .p_context = NULL, \ + .p_callback = renesas_ra_callback_adapter, \ + .p_context = DEVICE_DT_INST_GET(id), \ .p_extend = (void *)(&display_extend_cfg##id), \ - .line_detect_ipl = BSP_IRQ_DISABLED, \ - .underflow_1_ipl = BSP_IRQ_DISABLED, \ - .underflow_2_ipl = BSP_IRQ_DISABLED}}; \ + .line_detect_irq = DT_INST_IRQ_BY_NAME(id, line, irq), \ + .line_detect_ipl = DT_INST_IRQ_BY_NAME(id, line, priority), \ + .underflow_1_irq = BSP_IRQ_DISABLED, \ + .underflow_2_irq = BSP_IRQ_DISABLED}}; \ static struct display_ra_config ra_config##id = { \ IRQ_CONFIGURE_DEFINE(id), \ - .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ - .backlight_gpio = GPIO_DT_SPEC_INST_GET(id, backlight_gpios), \ + .pincfg = RENESAS_RA_GLCDC_DEVICE_PINCTRL_GET(id), \ + .backlight_gpio = GPIO_DT_SPEC_INST_GET_OR(id, backlight_gpios, NULL), \ .height = DT_INST_PROP(id, height), \ .width = DT_INST_PROP(id, width), \ - .pixel_format = DT_INST_PROP(id, input_pixel_format), \ - .display_frame_size = \ - (DT_INST_PROP(id, width)) * (DT_INST_PROP(id, height)) * BYTE_PER_PIXEL, \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(id)), \ .clock_glcdc_subsys = {.mstp = (uint32_t)DT_INST_CLOCKS_CELL_BY_IDX(id, 0, mstp), \ - .stop_bit = DT_INST_CLOCKS_CELL_BY_IDX(id, 0, stop_bit)}, \ - }; \ + .stop_bit = DT_INST_CLOCKS_CELL_BY_IDX(id, 0, stop_bit)}}; \ DEVICE_DT_INST_DEFINE(id, &display_init, NULL, &ra_data##id, &ra_config##id, POST_KERNEL, \ CONFIG_DISPLAY_INIT_PRIORITY, &display_api); diff --git a/drivers/display/display_renesas_ra.h b/drivers/display/display_renesas_ra.h index e3cddbcc3b7..d7695255fc3 100644 --- a/drivers/display/display_renesas_ra.h +++ b/drivers/display/display_renesas_ra.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Renesas Electronics Corporation + * Copyright (c) 2024-2025 Renesas Electronics Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,42 +9,92 @@ #include -#define INPUT_FORMAT_PIXEL DT_INST_PROP(0, input_pixel_format) -#define OUTPUT_FORMAT_PIXEL DT_INST_PROP(0, output_pixel_format) - -#if (INPUT_FORMAT_PIXEL == PANEL_PIXEL_FORMAT_RGB_565) -#define BYTE_PER_PIXEL (2) -#define DISPLAY_BITS_PER_PIXEL_INPUT0 (16) -#elif (INPUT_FORMAT_PIXEL == PANEL_PIXEL_FORMAT_RGB_888) -#define BYTE_PER_PIXEL (4) -#define DISPLAY_BITS_PER_PIXEL_INPUT0 (32) -#elif (INPUT_FORMAT_PIXEL == PANEL_PIXEL_FORMAT_ARGB_8888) -#define BYTE_PER_PIXEL (4) -#define DISPLAY_BITS_PER_PIXEL_INPUT0 (32) -#endif - -#define DISPLAY_BITS_PER_PIXEL_INPUT1 (16) -#define DISPLAY_HSIZE DT_INST_PROP(0, width) -#define DISPLAY_VSIZE DT_INST_PROP(0, height) -#define DISPLAY_BUFFER_STRIDE_BYTES_INPUT0 \ - (((DISPLAY_HSIZE * DISPLAY_BITS_PER_PIXEL_INPUT0 + 0x1FF) >> 9) << 6) -#define DISPLAY_BUFFER_STRIDE_PIXELS_INPUT0 \ - ((DISPLAY_BUFFER_STRIDE_BYTES_INPUT0 * 8) / DISPLAY_BITS_PER_PIXEL_INPUT0) -#define DISPLAY_BUFFER_STRIDE_BYTES_INPUT1 \ - (((DISPLAY_HSIZE * DISPLAY_BITS_PER_PIXEL_INPUT1 + 0x1FF) >> 9) << 6) -#define DISPLAY_BUFFER_STRIDE_PIXELS_INPUT1 \ - ((DISPLAY_BUFFER_STRIDE_BYTES_INPUT1 * 8) / DISPLAY_BITS_PER_PIXEL_INPUT1) - -#define LAYER_GREEN (255) -#define LAYER_RED (255) -#define LAYER_BLUE (255) -#define LAYER_ALPHA (255) -#define OUTPUT_GREEN (0) -#define OUTPUT_RED (0) -#define OUTPUT_BLUE (0) -#define OUTPUT_ALPHA (255) -#define GLCDC_BRIGHTNESS_MAX (1023U) -#define BRIGHTNESS_MAX (255U) -#define GLCDC_CONTRAST_MAX (255U) +#define ROUND_UP_64BYTES(x) ROUND_UP(x, NUM_BITS(uint64_t)) +#define INPUT_FORMAT_PIXEL(n) DT_INST_PROP(n, input_pixel_format) +#define OUTPUT_FORMAT_PIXEL(n) DT_INST_PROP(n, output_pixel_format) + +#define RENESAS_RA_GLCDC_IN_PIXEL_FORMAT_1 (DISPLAY_IN_FORMAT_32BITS_RGB888) +#define RENESAS_RA_GLCDC_IN_PIXEL_FORMAT_8 (DISPLAY_IN_FORMAT_32BITS_ARGB8888) +#define RENESAS_RA_GLCDC_IN_PIXEL_FORMAT_16 (DISPLAY_IN_FORMAT_16BITS_RGB565) + +#define RENESAS_RA_GLCDC_OUT_PIXEL_FORMAT_1 (DISPLAY_OUT_FORMAT_24BITS_RGB888) +#define RENESAS_RA_GLCDC_OUT_PIXEL_FORMAT_16 (DISPLAY_OUT_FORMAT_16BITS_RGB565) + +#define RENESAS_RA_DISPLAY_GET_PIXEL_FORMAT(n) \ + (DT_INST_PROP(n, input_pixel_format) == PANEL_PIXEL_FORMAT_RGB_888 \ + ? PANEL_PIXEL_FORMAT_ARGB_8888 \ + : DT_INST_PROP(n, input_pixel_format)) + +#define DISPLAY_HSIZE(n) (DT_INST_PROP(n, width)) +#define DISPLAY_VSIZE(n) (DT_INST_PROP(n, height)) + +#define RENESAS_RA_GLCDC_IN_PIXEL_FORMAT(n) \ + UTIL_CAT(RENESAS_RA_GLCDC_IN_PIXEL_FORMAT_, INPUT_FORMAT_PIXEL(n)) + +#define RENESAS_RA_GLCDC_OUT_PIXEL_FORMAT(n) \ + UTIL_CAT(RENESAS_RA_GLCDC_OUT_PIXEL_FORMAT_, OUTPUT_FORMAT_PIXEL(n)) + +#define RENESAS_RA_GLCDC_PIXEL_BYTE_SIZE(n) \ + (DISPLAY_BITS_PER_PIXEL(RENESAS_RA_DISPLAY_GET_PIXEL_FORMAT(n)) >> 3) + +#define RENESAS_RA_DISPLAY_BUFFER_HSTRIDE_BYTE(n) \ + (ROUND_UP_64BYTES(DISPLAY_HSIZE(n) * DISPLAY_BITS_PER_PIXEL(INPUT_FORMAT_PIXEL(n))) / \ + DISPLAY_BITS_PER_PIXEL(INPUT_FORMAT_PIXEL(n))) + +#define RENESAS_RA_GLCDC_HTIMING(n) \ + {.total_cyc = DT_INST_PROP(n, width) + \ + DT_PROP(DT_INST_CHILD(n, display_timings), hback_porch) + \ + DT_PROP(DT_INST_CHILD(n, display_timings), hfront_porch) + \ + DT_PROP(DT_INST_CHILD(n, display_timings), hsync_len), \ + .display_cyc = DT_INST_PROP(n, width), \ + .back_porch = DT_PROP(DT_INST_CHILD(n, display_timings), hback_porch), \ + .sync_width = DT_PROP(DT_INST_CHILD(n, display_timings), hsync_len), \ + .sync_polarity = DT_PROP(DT_INST_CHILD(n, display_timings), hsync_active)} + +#define RENESAS_RA_GLCDC_VTIMING(n) \ + {.total_cyc = DT_INST_PROP(n, height) + \ + DT_PROP(DT_INST_CHILD(n, display_timings), vback_porch) + \ + DT_PROP(DT_INST_CHILD(n, display_timings), vfront_porch) + \ + DT_PROP(DT_INST_CHILD(n, display_timings), vsync_len), \ + .display_cyc = DT_INST_PROP(n, height), \ + .back_porch = DT_PROP(DT_INST_CHILD(n, display_timings), vback_porch), \ + .sync_width = DT_PROP(DT_INST_CHILD(n, display_timings), vsync_len), \ + .sync_polarity = DT_PROP(DT_INST_CHILD(n, display_timings), vsync_active)} + +#define RENESAS_RA_GLCDC_OUTPUT_ENDIAN(n) \ + UTIL_CAT(DISPLAY_ENDIAN_, DT_INST_STRING_UPPER_TOKEN_OR(n, output_endian, LITTLE)) + +#define RENESAS_RA_GLCDC_OUTPUT_COLOR_ODER(n) \ + UTIL_CAT(DISPLAY_COLOR_ORDER_, DT_INST_STRING_UPPER_TOKEN_OR(n, output_color_oder, RGB)) + +#define RENESAS_RA_GLCDC_OUTPUT_DE_POLARITY(n) \ + UTIL_CAT(DISPLAY_SIGNAL_POLARITY_, \ + DT_INST_STRING_UPPER_TOKEN_OR(n, output_data_signal_polarity, HIACTIVE)) + +#define RENESAS_RA_GLCDC_OUTPUT_SYNC_EDGE(n) \ + UTIL_CAT(DISPLAY_SIGNAL_SYNC_EDGE_, \ + DT_INST_STRING_UPPER_TOKEN_OR(n, output_signal_sync_edge, FALLING)) + +#define RENESAS_RA_GLCDC_BG_COLOR(n) \ + { \ + .byte = { \ + .a = DT_INST_PROP_OR(n, def_back_color_alpha, 255), \ + .r = DT_INST_PROP_OR(n, def_back_color_red, 255), \ + .g = DT_INST_PROP_OR(n, def_back_color_green, 255), \ + .b = DT_INST_PROP_OR(n, def_back_color_blue, 255) \ + } \ + } + +#define RENESAS_RA_GLCDC_TCON_HSYNC_PIN(n) \ + UTIL_CAT(GLCDC_, DT_INST_STRING_UPPER_TOKEN_OR(n, output_pin_hsync, TCON_PIN_1)) + +#define RENESAS_RA_GLCDC_TCON_VSYNC_PIN(n) \ + UTIL_CAT(GLCDC_, DT_INST_STRING_UPPER_TOKEN_OR(n, output_pin_vsync, TCON_PIN_0)) + +#define RENESAS_RA_GLCDC_TCON_DE_PIN(n) \ + UTIL_CAT(GLCDC_, DT_INST_STRING_UPPER_TOKEN_OR(n, output_pin_de, TCON_PIN_2)) + +#define RENESAS_RA_GLCDC_OUTPUT_CLOCK_DIV(n) \ + UTIL_CAT(GLCDC_PANEL_CLK_DIVISOR_, DT_INST_PROP_OR(n, output_clock_divisor, 8)) #endif /* ZEPHYR_DRIVERS_DISPLAY_RENESAS_RA_H_ */ diff --git a/dts/bindings/display/renesas,ra-glcdc.yaml b/dts/bindings/display/renesas,ra-glcdc.yaml index c57816709c1..c4186d1b761 100644 --- a/dts/bindings/display/renesas,ra-glcdc.yaml +++ b/dts/bindings/display/renesas,ra-glcdc.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Renesas Electronics Corporation +# Copyright (c) 2024-2025 Renesas Electronics Corporation # SPDX-License-Identifier: Apache-2.0 description: Renesas Graphic LCD controller @@ -15,10 +15,9 @@ properties: required: true pinctrl-0: - required: true - - pinctrl-names: - required: true + description: | + Provide a pin configuration for using parallel pixel output. In combination with DSI HOST + the pin configuration is not necessary due to dedicated (MIPI D-PHY) pins. interrupts: required: true @@ -30,11 +29,74 @@ properties: backlight-gpios: type: phandle-array - required: true description: | The BLn pin is asserted to control the backlight of the panel. The sensor receives this as an active-high signal. + output-pin-hsync: + type: string + enum: + - "TCON_PIN_NONE" + - "TCON_PIN_0" + - "TCON_PIN_1" + - "TCON_PIN_2" + - "TCON_PIN_3" + description: Select the Parallel LCD HSYNC pin. Please do not select if using DSI Display. + + output-pin-vsync: + type: string + enum: + - "TCON_PIN_NONE" + - "TCON_PIN_0" + - "TCON_PIN_1" + - "TCON_PIN_2" + - "TCON_PIN_3" + description: Select the Parallel LCD VSYNC pin. Please do not select if using DSI Display. + + output-pin-de: + type: string + enum: + - "TCON_PIN_NONE" + - "TCON_PIN_0" + - "TCON_PIN_1" + - "TCON_PIN_2" + - "TCON_PIN_3" + description: Select the Parallel LCD DE pin. Please do not select if using DSI Display. + + output-clock-divisor: + type: int + enum: [1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 16, 24, 32] + description: | + Select the GLCDC clock frequency division ratio to output for panel. + + output-endian: + type: string + enum: + - "LITTLE" + - "BIG" + description: Select the output data bit order. Default is little endian. + + output-color-oder: + type: string + enum: + - "RGB" + - "GBR" + description: Select the output color order in pixel. Default is RGB. + + output-data-signal-polarity: + type: string + enum: + - "LOACTIVE" + - "HIACTIVE" + description: Select the output data enable signal polarity. Default is high active. + + output-signal-sync-edge: + type: string + enum: + - "FALLING" + - "RISING" + description: Select the output signal synchronization edge. Default is falling edge. + input-pixel-format: type: int required: true @@ -46,3 +108,19 @@ properties: required: true description: | Initial output Pixel format for Graphic LCD controller. + + def-back-color-alpha: + type: int + description: Default display background color - alpha + + def-back-color-red: + type: int + description: Default display background color - red + + def-back-color-green: + type: int + description: Default display background color - green + + def-back-color-blue: + type: int + description: Default display background color - blue