]> git.sur5r.net Git - u-boot/blobdiff - drivers/video/sunxi/sunxi_de2.c
video: sunxi: de2: Reserve the fb region in the EFI memory map
[u-boot] / drivers / video / sunxi / sunxi_de2.c
index 9a32c3a0209dce132f56cddcc3a61bbaefc01979..4ed035d556a852d49903374a1d19bdf92838a772 100644 (file)
@@ -1,15 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Allwinner DE2 display driver
  *
  * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net>
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <display.h>
 #include <dm.h>
 #include <edid.h>
+#include <efi_loader.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
 #include <video.h>
 #include <asm/global_data.h>
 #include <asm/io.h>
@@ -17,6 +19,7 @@
 #include <asm/arch/display2.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
+#include "simplefb_common.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -56,7 +59,7 @@ static void sunxi_de2_composer_init(void)
 }
 
 static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
-                              int bpp, ulong address)
+                              int bpp, ulong address, bool is_composite)
 {
        ulong de_mux_base = (mux == 0) ?
                            SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE;
@@ -72,6 +75,9 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
                (struct de_ui *)(de_mux_base +
                                 SUNXI_DE2_MUX_CHAN_REGS +
                                 SUNXI_DE2_MUX_CHAN_SZ * 1);
+       struct de_csc * const de_csc_regs =
+               (struct de_csc *)(de_mux_base +
+                                 SUNXI_DE2_MUX_DCSC_REGS);
        u32 size = SUNXI_DE2_WH(mode->hactive.typ, mode->vactive.typ);
        int channel;
        u32 format;
@@ -128,7 +134,27 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
        writel(0, de_mux_base + SUNXI_DE2_MUX_PEAK_REGS);
        writel(0, de_mux_base + SUNXI_DE2_MUX_ASE_REGS);
        writel(0, de_mux_base + SUNXI_DE2_MUX_FCC_REGS);
-       writel(0, de_mux_base + SUNXI_DE2_MUX_DCSC_REGS);
+
+       if (is_composite) {
+               /* set CSC coefficients */
+               writel(0x107, &de_csc_regs->coef11);
+               writel(0x204, &de_csc_regs->coef12);
+               writel(0x64, &de_csc_regs->coef13);
+               writel(0x4200, &de_csc_regs->coef14);
+               writel(0x1f68, &de_csc_regs->coef21);
+               writel(0x1ed6, &de_csc_regs->coef22);
+               writel(0x1c2, &de_csc_regs->coef23);
+               writel(0x20200, &de_csc_regs->coef24);
+               writel(0x1c2, &de_csc_regs->coef31);
+               writel(0x1e87, &de_csc_regs->coef32);
+               writel(0x1fb7, &de_csc_regs->coef33);
+               writel(0x20200, &de_csc_regs->coef34);
+
+               /* enable CSC unit */
+               writel(1, &de_csc_regs->csc_ctl);
+       } else {
+               writel(0, &de_csc_regs->csc_ctl);
+       }
 
        switch (bpp) {
        case 16:
@@ -153,7 +179,7 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
 
 static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
                          enum video_log2_bpp l2bpp,
-                         struct udevice *disp, int mux)
+                         struct udevice *disp, int mux, bool is_composite)
 {
        struct video_priv *uc_priv = dev_get_uclass_priv(dev);
        struct display_timing timing;
@@ -183,7 +209,7 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
        }
 
        sunxi_de2_composer_init();
-       sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase);
+       sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase, is_composite);
 
        ret = display_enable(disp, 1 << l2bpp, &timing);
        if (ret) {
@@ -196,6 +222,13 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
        uc_priv->bpix = l2bpp;
        debug("fb=%lx, size=%d %d\n", fbbase, uc_priv->xsize, uc_priv->ysize);
 
+#ifdef CONFIG_EFI_LOADER
+       efi_add_memory_map(fbbase,
+                          ALIGN(timing.hactive.typ * timing.vactive.typ *
+                          (1 << l2bpp) / 8, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT,
+                          EFI_RESERVED_MEMORY_TYPE, false);
+#endif
+
        return 0;
 }
 
@@ -204,25 +237,55 @@ static int sunxi_de2_probe(struct udevice *dev)
        struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
        struct udevice *disp;
        int ret;
-       int mux;
 
        /* Before relocation we don't need to do anything */
        if (!(gd->flags & GD_FLG_RELOC))
                return 0;
 
+       ret = uclass_find_device_by_name(UCLASS_DISPLAY,
+                                        "sunxi_lcd", &disp);
+       if (!ret) {
+               int mux;
+
+               mux = 0;
+
+               ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
+                                    false);
+               if (!ret) {
+                       video_set_flush_dcache(dev, 1);
+                       return 0;
+               }
+       }
+
+       debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
+
        ret = uclass_find_device_by_name(UCLASS_DISPLAY,
                                         "sunxi_dw_hdmi", &disp);
+       if (!ret) {
+               int mux;
+               if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
+                       mux = 0;
+               else
+                       mux = 1;
+
+               ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
+                                    false);
+               if (!ret) {
+                       video_set_flush_dcache(dev, 1);
+                       return 0;
+               }
+       }
+
+       debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
+
+       ret = uclass_find_device_by_name(UCLASS_DISPLAY,
+                                       "sunxi_tve", &disp);
        if (ret) {
-               debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
+               debug("%s: tv not found (ret=%d)\n", __func__, ret);
                return ret;
        }
 
-       if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
-               mux = 0;
-       else
-               mux = 1;
-
-       ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux);
+       ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true);
        if (ret)
                return ret;
 
@@ -256,3 +319,87 @@ U_BOOT_DRIVER(sunxi_de2) = {
 U_BOOT_DEVICE(sunxi_de2) = {
        .name = "sunxi_de2"
 };
+
+/*
+ * Simplefb support.
+ */
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
+int sunxi_simplefb_setup(void *blob)
+{
+       struct udevice *de2, *hdmi, *lcd;
+       struct video_priv *de2_priv;
+       struct video_uc_platdata *de2_plat;
+       int mux;
+       int offset, ret;
+       u64 start, size;
+       const char *pipeline = NULL;
+
+       debug("Setting up simplefb\n");
+
+       if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
+               mux = 0;
+       else
+               mux = 1;
+
+       /* Skip simplefb setting if DE2 / HDMI is not present */
+       ret = uclass_find_device_by_name(UCLASS_VIDEO,
+                                        "sunxi_de2", &de2);
+       if (ret) {
+               debug("DE2 not present\n");
+               return 0;
+       }
+
+       ret = uclass_find_device_by_name(UCLASS_DISPLAY,
+                                        "sunxi_dw_hdmi", &hdmi);
+       if (ret) {
+               debug("HDMI not present\n");
+       } else if (device_active(hdmi)) {
+               if (mux == 0)
+                       pipeline = "mixer0-lcd0-hdmi";
+               else
+                       pipeline = "mixer1-lcd1-hdmi";
+       } else {
+               debug("HDMI present but not probed\n");
+       }
+
+       ret = uclass_find_device_by_name(UCLASS_DISPLAY,
+                                        "sunxi_lcd", &lcd);
+       if (ret)
+               debug("LCD not present\n");
+       else if (device_active(lcd))
+               pipeline = "mixer0-lcd0";
+       else
+               debug("LCD present but not probed\n");
+
+       if (!pipeline) {
+               debug("No active display present\n");
+               return 0;
+       }
+
+       de2_priv = dev_get_uclass_priv(de2);
+       de2_plat = dev_get_uclass_platdata(de2);
+
+       offset = sunxi_simplefb_fdt_match(blob, pipeline);
+       if (offset < 0) {
+               eprintf("Cannot setup simplefb: node not found\n");
+               return 0; /* Keep older kernels working */
+       }
+
+       start = gd->bd->bi_dram[0].start;
+       size = de2_plat->base - start;
+       ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
+       if (ret) {
+               eprintf("Cannot setup simplefb: Error reserving memory\n");
+               return ret;
+       }
+
+       ret = fdt_setup_simplefb_node(blob, offset, de2_plat->base,
+                       de2_priv->xsize, de2_priv->ysize,
+                       VNBYTES(de2_priv->bpix) * de2_priv->xsize,
+                       "x8r8g8b8");
+       if (ret)
+               eprintf("Cannot setup simplefb: Error setting properties\n");
+
+       return ret;
+}
+#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */