drivers: display: Introduce mcux elcdif shim driver

Adds a shim layer around the mcux elcdif driver to adapt it to the
zephyr display interface. Although the hardware and underlying mcux sdk
driver can support additional configurations, some shortcuts are
currently made in the shim that force a given pixel format, lcd data
bus width, and signal polarity. This works with the rocktech lcd module
used on imx rt boards, but will need to be updated for other display
panels.

Signed-off-by: Maureen Helm <maureen.helm@nxp.com>
This commit is contained in:
Maureen Helm 2019-01-02 11:31:08 -06:00 committed by Kumar Gala
commit ab84cbfc40
6 changed files with 325 additions and 1 deletions

View file

@ -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_GROVE_LCD_RGB grove_lcd_rgb.c)
zephyr_sources_ifdef(CONFIG_MICROBIT_DISPLAY zephyr_sources_ifdef(CONFIG_MICROBIT_DISPLAY
mb_display.c mb_display.c

View file

@ -18,7 +18,7 @@ module-str = display
source "subsys/logging/Kconfig.template.log_config" source "subsys/logging/Kconfig.template.log_config"
source "drivers/display/Kconfig.grove" source "drivers/display/Kconfig.grove"
source "drivers/display/Kconfig.mcux_elcdif"
source "drivers/display/Kconfig.microbit" source "drivers/display/Kconfig.microbit"
source "drivers/display/Kconfig.ili9340" source "drivers/display/Kconfig.ili9340"
source "drivers/display/Kconfig.sdl" source "drivers/display/Kconfig.sdl"

View file

@ -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

View file

@ -0,0 +1,268 @@
/*
* Copyright (c) 2019, NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <display.h>
#include <fsl_elcdif.h>
#ifdef CONFIG_HAS_MCUX_CACHE
#include <fsl_cache.h>
#endif
#include <logging/log.h>
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);
}

View file

@ -27,6 +27,12 @@ config HAS_MCUX_CCM
help help
Set if the clock control module (CCM) module is present in the SoC. 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 config HAS_MCUX_ENET
bool bool
help help

View file

@ -15,6 +15,7 @@ zephyr_library_compile_definitions_ifdef(
) )
zephyr_sources_ifdef(CONFIG_HAS_MCUX_CACHE fsl_cache.c) 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_GPIO_MCUX_IGPIO fsl_gpio.c)
zephyr_sources_ifdef(CONFIG_I2C_MCUX_LPI2C fsl_lpi2c.c) zephyr_sources_ifdef(CONFIG_I2C_MCUX_LPI2C fsl_lpi2c.c)
zephyr_sources_ifdef(CONFIG_SPI_MCUX_LPSPI fsl_lpspi.c) zephyr_sources_ifdef(CONFIG_SPI_MCUX_LPSPI fsl_lpspi.c)