at91: video: Support driver-model for the LCD driver
authorSimon Glass <sjg@chromium.org>
Thu, 5 May 2016 13:28:20 +0000 (07:28 -0600)
committerAndreas Bießmann <andreas@biessmann.org>
Sun, 12 Jun 2016 21:49:38 +0000 (23:49 +0200)
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>
drivers/video/atmel_lcdfb.c
include/atmel_lcd.h

index 37838a8..39cd7ca 100644 (file)
@@ -7,7 +7,10 @@
  */
 
 #include <common.h>
+#include <atmel_lcd.h>
+#include <dm.h>
 #include <fdtdec.h>
+#include <video.h>
 #include <asm/io.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/clk.h>
 #include <bmp_layout.h>
 #include <atmel_lcdc.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_DM_VIDEO
+enum {
+       /* Maximum LCD size we support */
+       LCD_MAX_WIDTH           = 1366,
+       LCD_MAX_HEIGHT          = 768,
+       LCD_MAX_LOG2_BPP        = VIDEO_BPP16,
+};
+#endif
+
+struct atmel_fb_priv {
+       struct display_timing timing;
+};
+
 /* configurable parameters */
 #define ATMEL_LCDC_CVAL_DEFAULT                0xc8
 #define ATMEL_LCDC_DMA_BURST_LEN       8
@@ -31,6 +49,7 @@
 #define lcdc_readl(mmio, reg)          __raw_readl((mmio)+(reg))
 #define lcdc_writel(mmio, reg, val)    __raw_writel((val), (mmio)+(reg))
 
+#ifndef CONFIG_DM_VIDEO
 ushort *configuration_get_cmap(void)
 {
        return (ushort *)(panel_info.mmio + ATMEL_LCDC_LUT(0));
@@ -91,6 +110,7 @@ void lcd_set_cmap(struct bmp_image *bmp, unsigned colors)
                lcd_setcolreg(i, cte.red, cte.green, cte.blue);
        }
 }
+#endif
 
 static void atmel_fb_init(ulong addr, struct display_timing *timing, int bpix,
                          bool tft, bool cont_pol_low, ulong lcdbase)
@@ -190,6 +210,7 @@ static void atmel_fb_init(ulong addr, struct display_timing *timing, int bpix,
                    (ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
 }
 
+#ifndef CONFIG_DM_VIDEO
 void lcd_ctrl_init(void *lcdbase)
 {
        struct display_timing timing;
@@ -221,3 +242,73 @@ ulong calc_fbsize(void)
        return ((panel_info.vl_col * panel_info.vl_row *
                NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE;
 }
+#endif
+
+#ifdef CONFIG_DM_VIDEO
+static int atmel_fb_lcd_probe(struct udevice *dev)
+{
+       struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
+       struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct atmel_fb_priv *priv = dev_get_priv(dev);
+       struct display_timing *timing = &priv->timing;
+
+       /*
+        * For now some values are hard-coded. We could use the device tree
+        * bindings in simple-framebuffer.txt to specify the format/bpp and
+        * some Atmel-specific binding for tft and cont_pol_low.
+        */
+       atmel_fb_init(ATMEL_BASE_LCDC, timing, VIDEO_BPP16, true, false,
+                     uc_plat->base);
+       uc_priv->xsize = timing->hactive.typ;
+       uc_priv->ysize = timing->vactive.typ;
+       uc_priv->bpix = VIDEO_BPP16;
+       video_set_flush_dcache(dev, true);
+       debug("LCD frame buffer at %lx, size %x, %dx%d pixels\n", uc_plat->base,
+             uc_plat->size, uc_priv->xsize, uc_priv->ysize);
+
+       return 0;
+}
+
+static int atmel_fb_ofdata_to_platdata(struct udevice *dev)
+{
+       struct atmel_lcd_platdata *plat = dev_get_platdata(dev);
+       struct atmel_fb_priv *priv = dev_get_priv(dev);
+       struct display_timing *timing = &priv->timing;
+       const void *blob = gd->fdt_blob;
+
+       if (fdtdec_decode_display_timing(blob, dev->of_offset,
+                                        plat->timing_index, timing)) {
+               debug("%s: Failed to decode display timing\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int atmel_fb_lcd_bind(struct udevice *dev)
+{
+       struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
+
+       uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
+                       (1 << VIDEO_BPP16) / 8;
+       debug("%s: Frame buffer size %x\n", __func__, uc_plat->size);
+
+       return 0;
+}
+
+static const struct udevice_id atmel_fb_lcd_ids[] = {
+       { .compatible = "atmel,at91sam9g45-lcdc" },
+       { }
+};
+
+U_BOOT_DRIVER(atmel_fb) = {
+       .name   = "atmel_fb",
+       .id     = UCLASS_VIDEO,
+       .of_match = atmel_fb_lcd_ids,
+       .bind   = atmel_fb_lcd_bind,
+       .ofdata_to_platdata     = atmel_fb_ofdata_to_platdata,
+       .probe  = atmel_fb_lcd_probe,
+       .platdata_auto_alloc_size = sizeof(struct atmel_lcd_platdata),
+       .priv_auto_alloc_size   = sizeof(struct atmel_fb_priv),
+};
+#endif
index 6993128..8a2f46f 100644 (file)
 #ifndef _ATMEL_LCD_H_
 #define _ATMEL_LCD_H_
 
+/**
+ * struct atmel_lcd_platdata - platform data for Atmel LCDs with driver model
+ *
+ * @timing_index:      Index of LCD timing to use in device tree node
+ */
+struct atmel_lcd_platdata {
+       int timing_index;
+};
+
 typedef struct vidinfo {
        ushort vl_col;          /* Number of columns (i.e. 640) */
        ushort vl_row;          /* Number of rows (i.e. 480) */