1 /*
2 * Copyright (c) 2019, NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT fsl_imx6sx_lcdif
8
9 #include <drivers/display.h>
10 #include <fsl_elcdif.h>
11
12 #ifdef CONFIG_HAS_MCUX_CACHE
13 #include <fsl_cache.h>
14 #endif
15
16 #include <logging/log.h>
17
18 LOG_MODULE_REGISTER(display_mcux_elcdif, CONFIG_DISPLAY_LOG_LEVEL);
19
20 K_HEAP_DEFINE(mcux_elcdif_pool,
21 CONFIG_MCUX_ELCDIF_POOL_BLOCK_MAX *
22 CONFIG_MCUX_ELCDIF_POOL_BLOCK_NUM);
23
24 struct mcux_elcdif_config {
25 LCDIF_Type *base;
26 void (*irq_config_func)(const struct device *dev);
27 elcdif_rgb_mode_config_t rgb_mode;
28 enum display_pixel_format pixel_format;
29 uint8_t bits_per_pixel;
30 };
31
32 struct mcux_mem_block {
33 void *data;
34 };
35
36 struct mcux_elcdif_data {
37 struct mcux_mem_block fb[2];
38 struct k_sem sem;
39 size_t pixel_bytes;
40 size_t fb_bytes;
41 uint8_t write_idx;
42 };
43
mcux_elcdif_write(const struct device * dev,const uint16_t x,const uint16_t y,const struct display_buffer_descriptor * desc,const void * buf)44 static int mcux_elcdif_write(const struct device *dev, const uint16_t x,
45 const uint16_t y,
46 const struct display_buffer_descriptor *desc,
47 const void *buf)
48 {
49 const struct mcux_elcdif_config *config = dev->config;
50 struct mcux_elcdif_data *data = dev->data;
51
52 uint8_t write_idx = data->write_idx;
53 uint8_t read_idx = !write_idx;
54
55 int h_idx;
56 const uint8_t *src;
57 uint8_t *dst;
58
59 __ASSERT((data->pixel_bytes * desc->pitch * desc->height) <=
60 desc->buf_size, "Input buffer too small");
61
62 LOG_DBG("W=%d, H=%d, @%d,%d", desc->width, desc->height, x, y);
63
64 k_sem_take(&data->sem, K_FOREVER);
65
66 memcpy(data->fb[write_idx].data, data->fb[read_idx].data,
67 data->fb_bytes);
68
69 src = buf;
70 dst = data->fb[data->write_idx].data;
71 dst += data->pixel_bytes * (y * config->rgb_mode.panelWidth + x);
72
73 for (h_idx = 0; h_idx < desc->height; h_idx++) {
74 memcpy(dst, src, data->pixel_bytes * desc->width);
75 src += data->pixel_bytes * desc->pitch;
76 dst += data->pixel_bytes * config->rgb_mode.panelWidth;
77 }
78
79 #ifdef CONFIG_HAS_MCUX_CACHE
80 DCACHE_CleanByRange((uint32_t) data->fb[write_idx].data,
81 data->fb_bytes);
82 #endif
83
84 ELCDIF_SetNextBufferAddr(config->base,
85 (uint32_t) data->fb[write_idx].data);
86
87 data->write_idx = read_idx;
88
89 return 0;
90 }
91
mcux_elcdif_read(const struct device * dev,const uint16_t x,const uint16_t y,const struct display_buffer_descriptor * desc,void * buf)92 static int mcux_elcdif_read(const struct device *dev, const uint16_t x,
93 const uint16_t y,
94 const struct display_buffer_descriptor *desc,
95 void *buf)
96 {
97 LOG_ERR("Read not implemented");
98 return -ENOTSUP;
99 }
100
mcux_elcdif_get_framebuffer(const struct device * dev)101 static void *mcux_elcdif_get_framebuffer(const struct device *dev)
102 {
103 LOG_ERR("Direct framebuffer access not implemented");
104 return NULL;
105 }
106
mcux_elcdif_display_blanking_off(const struct device * dev)107 static int mcux_elcdif_display_blanking_off(const struct device *dev)
108 {
109 LOG_ERR("Display blanking control not implemented");
110 return -ENOTSUP;
111 }
112
mcux_elcdif_display_blanking_on(const struct device * dev)113 static int mcux_elcdif_display_blanking_on(const struct device *dev)
114 {
115 LOG_ERR("Display blanking control not implemented");
116 return -ENOTSUP;
117 }
118
mcux_elcdif_set_brightness(const struct device * dev,const uint8_t brightness)119 static int mcux_elcdif_set_brightness(const struct device *dev,
120 const uint8_t brightness)
121 {
122 LOG_WRN("Set brightness not implemented");
123 return -ENOTSUP;
124 }
125
mcux_elcdif_set_contrast(const struct device * dev,const uint8_t contrast)126 static int mcux_elcdif_set_contrast(const struct device *dev,
127 const uint8_t contrast)
128 {
129 LOG_ERR("Set contrast not implemented");
130 return -ENOTSUP;
131 }
132
mcux_elcdif_set_pixel_format(const struct device * dev,const enum display_pixel_format pixel_format)133 static int mcux_elcdif_set_pixel_format(const struct device *dev,
134 const enum display_pixel_format
135 pixel_format)
136 {
137 const struct mcux_elcdif_config *config = dev->config;
138
139 if (pixel_format == config->pixel_format) {
140 return 0;
141 }
142 LOG_ERR("Pixel format change not implemented");
143 return -ENOTSUP;
144 }
145
mcux_elcdif_set_orientation(const struct device * dev,const enum display_orientation orientation)146 static int mcux_elcdif_set_orientation(const struct device *dev,
147 const enum display_orientation orientation)
148 {
149 if (orientation == DISPLAY_ORIENTATION_NORMAL) {
150 return 0;
151 }
152 LOG_ERR("Changing display orientation not implemented");
153 return -ENOTSUP;
154 }
155
mcux_elcdif_get_capabilities(const struct device * dev,struct display_capabilities * capabilities)156 static void mcux_elcdif_get_capabilities(const struct device *dev,
157 struct display_capabilities *capabilities)
158 {
159 const struct mcux_elcdif_config *config = dev->config;
160
161 memset(capabilities, 0, sizeof(struct display_capabilities));
162 capabilities->x_resolution = config->rgb_mode.panelWidth;
163 capabilities->y_resolution = config->rgb_mode.panelHeight;
164 capabilities->supported_pixel_formats = config->pixel_format;
165 capabilities->current_pixel_format = config->pixel_format;
166 capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL;
167 }
168
mcux_elcdif_isr(const struct device * dev)169 static void mcux_elcdif_isr(const struct device *dev)
170 {
171 const struct mcux_elcdif_config *config = dev->config;
172 struct mcux_elcdif_data *data = dev->data;
173 uint32_t status;
174
175 status = ELCDIF_GetInterruptStatus(config->base);
176 ELCDIF_ClearInterruptStatus(config->base, status);
177
178 k_sem_give(&data->sem);
179 }
180
mcux_elcdif_init(const struct device * dev)181 static int mcux_elcdif_init(const struct device *dev)
182 {
183 const struct mcux_elcdif_config *config = dev->config;
184 struct mcux_elcdif_data *data = dev->data;
185 int i;
186
187 elcdif_rgb_mode_config_t rgb_mode = config->rgb_mode;
188
189 data->pixel_bytes = config->bits_per_pixel / 8U;
190 data->fb_bytes = data->pixel_bytes *
191 rgb_mode.panelWidth * rgb_mode.panelHeight;
192 data->write_idx = 1U;
193
194 for (i = 0; i < ARRAY_SIZE(data->fb); i++) {
195 data->fb[i].data = k_heap_alloc(&mcux_elcdif_pool,
196 data->fb_bytes, K_NO_WAIT);
197 if (data->fb[i].data == NULL) {
198 LOG_ERR("Could not allocate frame buffer %d", i);
199 return -ENOMEM;
200 }
201 memset(data->fb[i].data, 0, data->fb_bytes);
202 }
203 rgb_mode.bufferAddr = (uint32_t) data->fb[0].data;
204
205 k_sem_init(&data->sem, 1, 1);
206
207 config->irq_config_func(dev);
208
209 ELCDIF_RgbModeInit(config->base, &rgb_mode);
210 ELCDIF_EnableInterrupts(config->base,
211 kELCDIF_CurFrameDoneInterruptEnable);
212 ELCDIF_RgbModeStart(config->base);
213
214 return 0;
215 }
216
217 static const struct display_driver_api mcux_elcdif_api = {
218 .blanking_on = mcux_elcdif_display_blanking_on,
219 .blanking_off = mcux_elcdif_display_blanking_off,
220 .write = mcux_elcdif_write,
221 .read = mcux_elcdif_read,
222 .get_framebuffer = mcux_elcdif_get_framebuffer,
223 .set_brightness = mcux_elcdif_set_brightness,
224 .set_contrast = mcux_elcdif_set_contrast,
225 .get_capabilities = mcux_elcdif_get_capabilities,
226 .set_pixel_format = mcux_elcdif_set_pixel_format,
227 .set_orientation = mcux_elcdif_set_orientation,
228 };
229
230 static void mcux_elcdif_config_func_1(const struct device *dev);
231
232 static struct mcux_elcdif_config mcux_elcdif_config_1 = {
233 .base = (LCDIF_Type *) DT_INST_REG_ADDR(0),
234 .irq_config_func = mcux_elcdif_config_func_1,
235 #ifdef CONFIG_MCUX_ELCDIF_PANEL_RK043FN02H
236 .rgb_mode = {
237 .panelWidth = 480,
238 .panelHeight = 272,
239 .hsw = 41,
240 .hfp = 4,
241 .hbp = 8,
242 .vsw = 10,
243 .vfp = 4,
244 .vbp = 2,
245 .polarityFlags = kELCDIF_DataEnableActiveHigh |
246 kELCDIF_VsyncActiveLow |
247 kELCDIF_HsyncActiveLow |
248 kELCDIF_DriveDataOnRisingClkEdge,
249 .pixelFormat = kELCDIF_PixelFormatRGB565,
250 .dataBus = kELCDIF_DataBus16Bit,
251 },
252 .pixel_format = PIXEL_FORMAT_BGR_565,
253 .bits_per_pixel = 16,
254 #endif
255 };
256
257 static struct mcux_elcdif_data mcux_elcdif_data_1;
258
259 DEVICE_DT_INST_DEFINE(0,
260 &mcux_elcdif_init,
261 NULL,
262 &mcux_elcdif_data_1, &mcux_elcdif_config_1,
263 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
264 &mcux_elcdif_api);
265
mcux_elcdif_config_func_1(const struct device * dev)266 static void mcux_elcdif_config_func_1(const struct device *dev)
267 {
268 IRQ_CONNECT(DT_INST_IRQN(0),
269 DT_INST_IRQ(0, priority),
270 mcux_elcdif_isr, DEVICE_DT_INST_GET(0), 0);
271
272 irq_enable(DT_INST_IRQN(0));
273 }
274