Commit 9dc89a053d29deea73c39ef49c9f1c6cb4c38820
Committed by
Andreas Bießmann
1 parent
d63ec26a49
Exists in
v2017.01-smarct4x
and in
25 other branches
at91: video: Support driver-model for the LCD driver
Add driver-model support to this driver. Most features can be controlled from the device tree. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Andreas Bießmann <andreas@biessmann.org>
Showing 2 changed files with 100 additions and 0 deletions Side-by-side Diff
drivers/video/atmel_lcdfb.c
... | ... | @@ -7,7 +7,10 @@ |
7 | 7 | */ |
8 | 8 | |
9 | 9 | #include <common.h> |
10 | +#include <atmel_lcd.h> | |
11 | +#include <dm.h> | |
10 | 12 | #include <fdtdec.h> |
13 | +#include <video.h> | |
11 | 14 | #include <asm/io.h> |
12 | 15 | #include <asm/arch/gpio.h> |
13 | 16 | #include <asm/arch/clk.h> |
... | ... | @@ -15,6 +18,21 @@ |
15 | 18 | #include <bmp_layout.h> |
16 | 19 | #include <atmel_lcdc.h> |
17 | 20 | |
21 | +DECLARE_GLOBAL_DATA_PTR; | |
22 | + | |
23 | +#ifdef CONFIG_DM_VIDEO | |
24 | +enum { | |
25 | + /* Maximum LCD size we support */ | |
26 | + LCD_MAX_WIDTH = 1366, | |
27 | + LCD_MAX_HEIGHT = 768, | |
28 | + LCD_MAX_LOG2_BPP = VIDEO_BPP16, | |
29 | +}; | |
30 | +#endif | |
31 | + | |
32 | +struct atmel_fb_priv { | |
33 | + struct display_timing timing; | |
34 | +}; | |
35 | + | |
18 | 36 | /* configurable parameters */ |
19 | 37 | #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 |
20 | 38 | #define ATMEL_LCDC_DMA_BURST_LEN 8 |
... | ... | @@ -31,6 +49,7 @@ |
31 | 49 | #define lcdc_readl(mmio, reg) __raw_readl((mmio)+(reg)) |
32 | 50 | #define lcdc_writel(mmio, reg, val) __raw_writel((val), (mmio)+(reg)) |
33 | 51 | |
52 | +#ifndef CONFIG_DM_VIDEO | |
34 | 53 | ushort *configuration_get_cmap(void) |
35 | 54 | { |
36 | 55 | return (ushort *)(panel_info.mmio + ATMEL_LCDC_LUT(0)); |
... | ... | @@ -91,6 +110,7 @@ |
91 | 110 | lcd_setcolreg(i, cte.red, cte.green, cte.blue); |
92 | 111 | } |
93 | 112 | } |
113 | +#endif | |
94 | 114 | |
95 | 115 | static void atmel_fb_init(ulong addr, struct display_timing *timing, int bpix, |
96 | 116 | bool tft, bool cont_pol_low, ulong lcdbase) |
... | ... | @@ -190,6 +210,7 @@ |
190 | 210 | (ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); |
191 | 211 | } |
192 | 212 | |
213 | +#ifndef CONFIG_DM_VIDEO | |
193 | 214 | void lcd_ctrl_init(void *lcdbase) |
194 | 215 | { |
195 | 216 | struct display_timing timing; |
... | ... | @@ -221,4 +242,74 @@ |
221 | 242 | return ((panel_info.vl_col * panel_info.vl_row * |
222 | 243 | NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE; |
223 | 244 | } |
245 | +#endif | |
246 | + | |
247 | +#ifdef CONFIG_DM_VIDEO | |
248 | +static int atmel_fb_lcd_probe(struct udevice *dev) | |
249 | +{ | |
250 | + struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); | |
251 | + struct video_priv *uc_priv = dev_get_uclass_priv(dev); | |
252 | + struct atmel_fb_priv *priv = dev_get_priv(dev); | |
253 | + struct display_timing *timing = &priv->timing; | |
254 | + | |
255 | + /* | |
256 | + * For now some values are hard-coded. We could use the device tree | |
257 | + * bindings in simple-framebuffer.txt to specify the format/bpp and | |
258 | + * some Atmel-specific binding for tft and cont_pol_low. | |
259 | + */ | |
260 | + atmel_fb_init(ATMEL_BASE_LCDC, timing, VIDEO_BPP16, true, false, | |
261 | + uc_plat->base); | |
262 | + uc_priv->xsize = timing->hactive.typ; | |
263 | + uc_priv->ysize = timing->vactive.typ; | |
264 | + uc_priv->bpix = VIDEO_BPP16; | |
265 | + video_set_flush_dcache(dev, true); | |
266 | + debug("LCD frame buffer at %lx, size %x, %dx%d pixels\n", uc_plat->base, | |
267 | + uc_plat->size, uc_priv->xsize, uc_priv->ysize); | |
268 | + | |
269 | + return 0; | |
270 | +} | |
271 | + | |
272 | +static int atmel_fb_ofdata_to_platdata(struct udevice *dev) | |
273 | +{ | |
274 | + struct atmel_lcd_platdata *plat = dev_get_platdata(dev); | |
275 | + struct atmel_fb_priv *priv = dev_get_priv(dev); | |
276 | + struct display_timing *timing = &priv->timing; | |
277 | + const void *blob = gd->fdt_blob; | |
278 | + | |
279 | + if (fdtdec_decode_display_timing(blob, dev->of_offset, | |
280 | + plat->timing_index, timing)) { | |
281 | + debug("%s: Failed to decode display timing\n", __func__); | |
282 | + return -EINVAL; | |
283 | + } | |
284 | + | |
285 | + return 0; | |
286 | +} | |
287 | + | |
288 | +static int atmel_fb_lcd_bind(struct udevice *dev) | |
289 | +{ | |
290 | + struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); | |
291 | + | |
292 | + uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * | |
293 | + (1 << VIDEO_BPP16) / 8; | |
294 | + debug("%s: Frame buffer size %x\n", __func__, uc_plat->size); | |
295 | + | |
296 | + return 0; | |
297 | +} | |
298 | + | |
299 | +static const struct udevice_id atmel_fb_lcd_ids[] = { | |
300 | + { .compatible = "atmel,at91sam9g45-lcdc" }, | |
301 | + { } | |
302 | +}; | |
303 | + | |
304 | +U_BOOT_DRIVER(atmel_fb) = { | |
305 | + .name = "atmel_fb", | |
306 | + .id = UCLASS_VIDEO, | |
307 | + .of_match = atmel_fb_lcd_ids, | |
308 | + .bind = atmel_fb_lcd_bind, | |
309 | + .ofdata_to_platdata = atmel_fb_ofdata_to_platdata, | |
310 | + .probe = atmel_fb_lcd_probe, | |
311 | + .platdata_auto_alloc_size = sizeof(struct atmel_lcd_platdata), | |
312 | + .priv_auto_alloc_size = sizeof(struct atmel_fb_priv), | |
313 | +}; | |
314 | +#endif |
include/atmel_lcd.h
... | ... | @@ -10,6 +10,15 @@ |
10 | 10 | #ifndef _ATMEL_LCD_H_ |
11 | 11 | #define _ATMEL_LCD_H_ |
12 | 12 | |
13 | +/** | |
14 | + * struct atmel_lcd_platdata - platform data for Atmel LCDs with driver model | |
15 | + * | |
16 | + * @timing_index: Index of LCD timing to use in device tree node | |
17 | + */ | |
18 | +struct atmel_lcd_platdata { | |
19 | + int timing_index; | |
20 | +}; | |
21 | + | |
13 | 22 | typedef struct vidinfo { |
14 | 23 | ushort vl_col; /* Number of columns (i.e. 640) */ |
15 | 24 | ushort vl_row; /* Number of rows (i.e. 480) */ |