diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index 6f7f17950ad..bd546671917 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -1,4 +1,5 @@ +zephyr_sources_ifdef(CONFIG_DISPLAY_MCUX_ELCDIF display_mcux_elcdif.c) zephyr_sources_ifdef(CONFIG_GROVE_LCD_RGB grove_lcd_rgb.c) zephyr_sources_ifdef(CONFIG_MICROBIT_DISPLAY mb_display.c diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index 22f834322f8..dbf1998c04f 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -18,7 +18,7 @@ module-str = display source "subsys/logging/Kconfig.template.log_config" source "drivers/display/Kconfig.grove" - +source "drivers/display/Kconfig.mcux_elcdif" source "drivers/display/Kconfig.microbit" source "drivers/display/Kconfig.ili9340" source "drivers/display/Kconfig.sdl" diff --git a/drivers/display/Kconfig.mcux_elcdif b/drivers/display/Kconfig.mcux_elcdif new file mode 100644 index 00000000000..7a2f4dbf2c4 --- /dev/null +++ b/drivers/display/Kconfig.mcux_elcdif @@ -0,0 +1,48 @@ +# +# Copyright (c) 2019, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig DISPLAY_MCUX_ELCDIF + bool "MCUX eLCDIF driver" + depends on HAS_MCUX_ELCDIF + help + Enable support for mcux eLCDIF driver. + +if DISPLAY_MCUX_ELCDIF + +config MCUX_ELCDIF_POOL_BLOCK_NUM + int "Number of memory pool blocks" + default 2 + help + Number of blocks in the frame buffer memory pool. + +config MCUX_ELCDIF_POOL_BLOCK_MIN + hex "Minimum memory pool block size" + default 0x400 + help + Minimum block size in the frame buffer memory pool. + +config MCUX_ELCDIF_POOL_BLOCK_MAX + hex "Maximum memory pool block size" + default 0x40000 + help + Maximum block size in the frame buffer memory pool. + +config MCUX_ELCDIF_POOL_BLOCK_ALIGN + int "Alignment of memory pool blocks" + default 64 + help + Byte alignment in the frame buffer memory pool. + +choice MCUX_ELCDIF_PANEL + prompt "Panel selection" + default MCUX_ELCDIF_PANEL_RK043FN02H + +config MCUX_ELCDIF_PANEL_RK043FN02H + bool "Rocktech rk043fn02h-ct" + +endchoice + +endif # DISPLAY_MCUX_ELCDIF diff --git a/drivers/display/display_mcux_elcdif.c b/drivers/display/display_mcux_elcdif.c new file mode 100644 index 00000000000..573a545f7c7 --- /dev/null +++ b/drivers/display/display_mcux_elcdif.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2019, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#ifdef CONFIG_HAS_MCUX_CACHE +#include +#endif + +#include + +LOG_MODULE_REGISTER(display_mcux_elcdif, CONFIG_DISPLAY_LOG_LEVEL); + +K_MEM_POOL_DEFINE(mcux_elcdif_pool, + CONFIG_MCUX_ELCDIF_POOL_BLOCK_MIN, + CONFIG_MCUX_ELCDIF_POOL_BLOCK_MAX, + CONFIG_MCUX_ELCDIF_POOL_BLOCK_NUM, + CONFIG_MCUX_ELCDIF_POOL_BLOCK_ALIGN); + +struct mcux_elcdif_config { + LCDIF_Type *base; + void (*irq_config_func)(struct device *dev); + elcdif_rgb_mode_config_t rgb_mode; + enum display_pixel_format pixel_format; + u8_t bits_per_pixel; +}; + +struct mcux_elcdif_data { + struct k_mem_block fb[2]; + struct k_sem sem; + size_t pixel_bytes; + size_t fb_bytes; + u8_t write_idx; +}; + +static int mcux_elcdif_write(const struct device *dev, const u16_t x, + const u16_t y, + const struct display_buffer_descriptor *desc, + const void *buf) +{ + const struct mcux_elcdif_config *config = dev->config->config_info; + struct mcux_elcdif_data *data = dev->driver_data; + + u8_t write_idx = data->write_idx; + u8_t read_idx = !write_idx; + + int h_idx; + const u8_t *src; + u8_t *dst; + + __ASSERT((data->pixel_bytes * desc->pitch * desc->height) <= + desc->buf_size, "Input buffer too small"); + + LOG_DBG("W=%d, H=%d, @%d,%d", desc->width, desc->height, x, y); + + k_sem_take(&data->sem, K_FOREVER); + + memcpy(data->fb[write_idx].data, data->fb[read_idx].data, + data->fb_bytes); + + src = buf; + dst = data->fb[data->write_idx].data; + dst += data->pixel_bytes * (y * config->rgb_mode.panelWidth + x); + + for (h_idx = 0; h_idx < desc->height; h_idx++) { + memcpy(dst, src, data->pixel_bytes * desc->width); + src += data->pixel_bytes * desc->pitch; + dst += data->pixel_bytes * config->rgb_mode.panelWidth; + } + +#ifdef CONFIG_HAS_MCUX_CACHE + DCACHE_CleanByRange((uint32_t) data->fb[write_idx].data, + data->fb_bytes); +#endif + + ELCDIF_SetNextBufferAddr(config->base, + (uint32_t) data->fb[write_idx].data); + + data->write_idx = read_idx; + + return 0; +} + +static int mcux_elcdif_read(const struct device *dev, const u16_t x, + const u16_t y, + const struct display_buffer_descriptor *desc, + void *buf) +{ + LOG_ERR("Read not implemented"); + return -ENOTSUP; +} + +static void *mcux_elcdif_get_framebuffer(const struct device *dev) +{ + LOG_ERR("Direct framebuffer access not implemented"); + return NULL; +} + +static int mcux_elcdif_display_blanking_off(const struct device *dev) +{ + LOG_ERR("Display blanking control not implemented"); + return -ENOTSUP; +} + +static int mcux_elcdif_display_blanking_on(const struct device *dev) +{ + LOG_ERR("Display blanking control not implemented"); + return -ENOTSUP; +} + +static int mcux_elcdif_set_brightness(const struct device *dev, + const u8_t brightness) +{ + LOG_WRN("Set brightness not implemented"); + return -ENOTSUP; +} + +static int mcux_elcdif_set_contrast(const struct device *dev, + const u8_t contrast) +{ + LOG_ERR("Set contrast not implemented"); + return -ENOTSUP; +} + +static int mcux_elcdif_set_pixel_format(const struct device *dev, + const enum display_pixel_format + pixel_format) +{ + const struct mcux_elcdif_config *config = dev->config->config_info; + + if (pixel_format == config->pixel_format) { + return 0; + } + LOG_ERR("Pixel format change not implemented"); + return -ENOTSUP; +} + +static int mcux_elcdif_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 void mcux_elcdif_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + const struct mcux_elcdif_config *config = dev->config->config_info; + + memset(capabilities, 0, sizeof(struct display_capabilities)); + capabilities->x_resolution = config->rgb_mode.panelWidth; + capabilities->y_resolution = config->rgb_mode.panelHeight; + capabilities->supported_pixel_formats = config->pixel_format; + capabilities->current_pixel_format = config->pixel_format; + capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; +} + +static void mcux_elcdif_isr(void *arg) +{ + struct device *dev = (struct device *)arg; + const struct mcux_elcdif_config *config = dev->config->config_info; + struct mcux_elcdif_data *data = dev->driver_data; + u32_t status; + + status = ELCDIF_GetInterruptStatus(config->base); + ELCDIF_ClearInterruptStatus(config->base, status); + + k_sem_give(&data->sem); +} + +static int mcux_elcdif_init(struct device *dev) +{ + const struct mcux_elcdif_config *config = dev->config->config_info; + struct mcux_elcdif_data *data = dev->driver_data; + int i; + + elcdif_rgb_mode_config_t rgb_mode = config->rgb_mode; + + data->pixel_bytes = config->bits_per_pixel / 8; + data->fb_bytes = data->pixel_bytes * + rgb_mode.panelWidth * rgb_mode.panelHeight; + data->write_idx = 1; + + for (i = 0; i < ARRAY_SIZE(data->fb); i++) { + if (k_mem_pool_alloc(&mcux_elcdif_pool, &data->fb[i], + data->fb_bytes, K_NO_WAIT) != 0) { + LOG_ERR("Could not allocate frame buffer %d", i); + return -ENOMEM; + } + memset(data->fb[i].data, 0, data->fb_bytes); + } + rgb_mode.bufferAddr = (uint32_t) data->fb[0].data; + + k_sem_init(&data->sem, 1, 1); + + config->irq_config_func(dev); + + ELCDIF_RgbModeInit(config->base, &rgb_mode); + ELCDIF_EnableInterrupts(config->base, + kELCDIF_CurFrameDoneInterruptEnable); + ELCDIF_RgbModeStart(config->base); + + return 0; +} + +static const struct display_driver_api mcux_elcdif_api = { + .blanking_on = mcux_elcdif_display_blanking_on, + .blanking_off = mcux_elcdif_display_blanking_off, + .write = mcux_elcdif_write, + .read = mcux_elcdif_read, + .get_framebuffer = mcux_elcdif_get_framebuffer, + .set_brightness = mcux_elcdif_set_brightness, + .set_contrast = mcux_elcdif_set_contrast, + .get_capabilities = mcux_elcdif_get_capabilities, + .set_pixel_format = mcux_elcdif_set_pixel_format, + .set_orientation = mcux_elcdif_set_orientation, +}; + +static void mcux_elcdif_config_func_1(struct device *dev); + +static struct mcux_elcdif_config mcux_elcdif_config_1 = { + .base = (LCDIF_Type *) DT_FSL_IMX6SX_LCDIF_0_BASE_ADDRESS, + .irq_config_func = mcux_elcdif_config_func_1, +#ifdef CONFIG_MCUX_ELCDIF_PANEL_RK043FN02H + .rgb_mode = { + .panelWidth = 480, + .panelHeight = 272, + .hsw = 41, + .hfp = 4, + .hbp = 8, + .vsw = 10, + .vfp = 4, + .vbp = 2, + .polarityFlags = kELCDIF_DataEnableActiveHigh | + kELCDIF_VsyncActiveLow | + kELCDIF_HsyncActiveLow | + kELCDIF_DriveDataOnRisingClkEdge, + .pixelFormat = kELCDIF_PixelFormatRGB565, + .dataBus = kELCDIF_DataBus16Bit, + }, + .pixel_format = PIXEL_FORMAT_RGB_565, + .bits_per_pixel = 16, +#endif +}; + +static struct mcux_elcdif_data mcux_elcdif_data_1; + +DEVICE_AND_API_INIT(mcux_elcdif_1, DT_FSL_IMX6SX_LCDIF_0_LABEL, + &mcux_elcdif_init, + &mcux_elcdif_data_1, &mcux_elcdif_config_1, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &mcux_elcdif_api); + +static void mcux_elcdif_config_func_1(struct device *dev) +{ + IRQ_CONNECT(DT_FSL_IMX6SX_LCDIF_0_IRQ_0, + DT_FSL_IMX6SX_LCDIF_0_IRQ_0_PRIORITY, + mcux_elcdif_isr, DEVICE_GET(mcux_elcdif_1), 0); + + irq_enable(DT_FSL_IMX6SX_LCDIF_0_IRQ_0); +} diff --git a/ext/hal/nxp/mcux/Kconfig b/ext/hal/nxp/mcux/Kconfig index 0544c66ee80..7e11e03db46 100644 --- a/ext/hal/nxp/mcux/Kconfig +++ b/ext/hal/nxp/mcux/Kconfig @@ -27,6 +27,12 @@ config HAS_MCUX_CCM help Set if the clock control module (CCM) module is present in the SoC. +config HAS_MCUX_ELCDIF + bool + help + Set if the enhanced LCD interface (eLCDIF) module is present in the + SoC. + config HAS_MCUX_ENET bool help diff --git a/ext/hal/nxp/mcux/drivers/imx/CMakeLists.txt b/ext/hal/nxp/mcux/drivers/imx/CMakeLists.txt index 8872bc40b7f..fc4bb6ff286 100644 --- a/ext/hal/nxp/mcux/drivers/imx/CMakeLists.txt +++ b/ext/hal/nxp/mcux/drivers/imx/CMakeLists.txt @@ -15,6 +15,7 @@ zephyr_library_compile_definitions_ifdef( ) zephyr_sources_ifdef(CONFIG_HAS_MCUX_CACHE fsl_cache.c) +zephyr_sources_ifdef(CONFIG_DISPLAY_MCUX_ELCDIF fsl_elcdif.c) zephyr_sources_ifdef(CONFIG_GPIO_MCUX_IGPIO fsl_gpio.c) zephyr_sources_ifdef(CONFIG_I2C_MCUX_LPI2C fsl_lpi2c.c) zephyr_sources_ifdef(CONFIG_SPI_MCUX_LPSPI fsl_lpspi.c)