From: Michael Trimarchi <mich...@amarulasolutions.com>

Update mxsfb for LCD video driver

Signed-off-by: Ye Li <ye...@nxp.com>
Signed-off-by: Michael Trimarchi <mich...@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binac...@amarulasolutions.com>
---

 drivers/video/mxsfb.c | 139 ++++++++++++++++++++++++++++--------------
 1 file changed, 93 insertions(+), 46 deletions(-)

diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 792d6314d15e..45431f0a1047 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -21,8 +21,13 @@
 #include <asm/global_data.h>
 #include <asm/mach-imx/dma.h>
 #include <asm/io.h>
+#include <reset.h>
+#include <panel.h>
+#include <video_bridge.h>
+#include <video_link.h>
 
 #include "videomodes.h"
+#include <dm/device-internal.h>
 
 #define        PS2KHZ(ps)      (1000000000UL / (ps))
 #define HZ2PS(hz)      (1000000000UL / ((hz) / 1000))
@@ -30,6 +35,11 @@
 #define BITS_PP                18
 #define BYTES_PP       4
 
+struct mxsfb_priv {
+       fdt_addr_t reg_base;
+       struct udevice *disp_dev;
+};
+
 struct mxs_dma_desc desc;
 
 /**
@@ -56,9 +66,10 @@ __weak void mxsfb_system_setup(void)
  */
 
 static void mxs_lcd_init(struct udevice *dev, u32 fb_addr,
-                        struct display_timing *timings, int bpp)
+                        struct display_timing *timings, int bpp, bool bridge)
 {
-       struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)MXS_LCDIF_BASE;
+       struct mxsfb_priv *priv = dev_get_priv(dev);
+       struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)priv->reg_base;
        const enum display_flags flags = timings->flags;
        uint32_t word_len = 0, bus_width = 0;
        uint8_t valid_data = 0;
@@ -109,7 +120,7 @@ static void mxs_lcd_init(struct udevice *dev, u32 fb_addr,
        }
 #else
        /* Kick in the LCDIF clock */
-       mxs_set_lcdclk(MXS_LCDIF_BASE, timings->pixelclock.typ / 1000);
+       mxs_set_lcdclk(priv->reg_base, timings->pixelclock.typ / 1000);
 #endif
 
        /* Restart the LCDIF block */
@@ -142,26 +153,30 @@ static void mxs_lcd_init(struct udevice *dev, u32 fb_addr,
                LCDIF_CTRL_BYPASS_COUNT | LCDIF_CTRL_LCDIF_MASTER,
                &regs->hw_lcdif_ctrl);
 
-       writel(valid_data << LCDIF_CTRL1_BYTE_PACKING_FORMAT_OFFSET,
+       writel((valid_data << LCDIF_CTRL1_BYTE_PACKING_FORMAT_OFFSET) |
+               LCDIF_CTRL1_RECOVER_ON_UNDERFLOW,
                &regs->hw_lcdif_ctrl1);
 
+       if (bridge)
+               writel(LCDIF_CTRL2_OUTSTANDING_REQS_REQ_16, 
&regs->hw_lcdif_ctrl2);
+
        mxsfb_system_setup();
 
        writel((timings->vactive.typ << LCDIF_TRANSFER_COUNT_V_COUNT_OFFSET) |
                timings->hactive.typ, &regs->hw_lcdif_transfer_count);
 
-       vdctrl0 = LCDIF_VDCTRL0_ENABLE_PRESENT | LCDIF_VDCTRL0_ENABLE_POL |
+       vdctrl0 = LCDIF_VDCTRL0_ENABLE_PRESENT |
                  LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT |
                  LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
                  timings->vsync_len.typ;
 
-       if(flags & DISPLAY_FLAGS_HSYNC_HIGH)
+       if (flags & DISPLAY_FLAGS_HSYNC_HIGH)
                vdctrl0 |= LCDIF_VDCTRL0_HSYNC_POL;
-       if(flags & DISPLAY_FLAGS_VSYNC_HIGH)
+       if (flags & DISPLAY_FLAGS_VSYNC_HIGH)
                vdctrl0 |= LCDIF_VDCTRL0_VSYNC_POL;
-       if(flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+       if (flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
                vdctrl0 |= LCDIF_VDCTRL0_DOTCLK_POL;
-       if(flags & DISPLAY_FLAGS_DE_HIGH)
+       if (flags & DISPLAY_FLAGS_DE_HIGH)
                vdctrl0 |= LCDIF_VDCTRL0_ENABLE_POL;
 
        writel(vdctrl0, &regs->hw_lcdif_vdctrl0);
@@ -198,10 +213,10 @@ static void mxs_lcd_init(struct udevice *dev, u32 fb_addr,
 }
 
 static int mxs_probe_common(struct udevice *dev, struct display_timing 
*timings,
-                           int bpp, u32 fb)
+                           int bpp, u32 fb, bool bridge)
 {
        /* Start framebuffer */
-       mxs_lcd_init(dev, fb, timings, bpp);
+       mxs_lcd_init(dev, fb, timings, bpp, bridge);
 
 #ifdef CONFIG_VIDEO_MXS_MODE_SYSTEM
        /*
@@ -212,7 +227,8 @@ static int mxs_probe_common(struct udevice *dev, struct 
display_timing *timings,
         * sets the RUN bit, then waits until it gets cleared and repeats this
         * infinitelly. This way, we get smooth continuous updates of the LCD.
         */
-       struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)MXS_LCDIF_BASE;
+       struct mxsfb_priv *priv = dev_get_priv(dev);
+       struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)priv->reg_base;
 
        memset(&desc, 0, sizeof(struct mxs_dma_desc));
        desc.address = (dma_addr_t)&desc;
@@ -229,9 +245,9 @@ static int mxs_probe_common(struct udevice *dev, struct 
display_timing *timings,
        return 0;
 }
 
-static int mxs_remove_common(u32 fb)
+static int mxs_remove_common(phys_addr_t reg_base, u32 fb)
 {
-       struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)MXS_LCDIF_BASE;
+       struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)(reg_base);
        int timeout = 1000000;
 
        if (!fb)
@@ -258,6 +274,7 @@ static int mxs_of_get_timings(struct udevice *dev,
        int ret = 0;
        u32 display_phandle;
        ofnode display_node;
+       struct mxsfb_priv *priv = dev_get_priv(dev);
 
        ret = ofnode_read_u32(dev_ofnode(dev), "display", &display_phandle);
        if (ret) {
@@ -278,10 +295,19 @@ static int mxs_of_get_timings(struct udevice *dev,
                return -EINVAL;
        }
 
-       ret = ofnode_decode_display_timing(display_node, 0, timings);
-       if (ret) {
-               dev_err(dev, "failed to get any display timings\n");
-               return -EINVAL;
+       priv->disp_dev = video_link_get_next_device(dev);
+       if (priv->disp_dev) {
+               ret = video_link_get_display_timings(timings);
+               if (ret) {
+                       dev_err(dev, "failed to get any video link display 
timings\n");
+                       return -EINVAL;
+               }
+       } else {
+               ret = ofnode_decode_display_timing(display_node, 0, timings);
+               if (ret) {
+                       dev_err(dev, "failed to get any display timings\n");
+                       return -EINVAL;
+               }
        }
 
        return ret;
@@ -291,20 +317,58 @@ static int mxs_video_probe(struct udevice *dev)
 {
        struct video_uc_plat *plat = dev_get_uclass_plat(dev);
        struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct mxsfb_priv *priv = dev_get_priv(dev);
 
        struct display_timing timings;
        u32 bpp = 0;
        u32 fb_start, fb_end;
        int ret;
+       bool enable_bridge = false;
 
        debug("%s() plat: base 0x%lx, size 0x%x\n",
               __func__, plat->base, plat->size);
 
+       priv->reg_base = dev_read_addr(dev);
+       if (priv->reg_base == FDT_ADDR_T_NONE) {
+               dev_err(dev, "lcdif base address is not found\n");
+               return -EINVAL;
+       }
+
        ret = mxs_of_get_timings(dev, &timings, &bpp);
        if (ret)
                return ret;
 
-       ret = mxs_probe_common(dev, &timings, bpp, plat->base);
+       if (priv->disp_dev) {
+               if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) {
+                       if (device_get_uclass_id(priv->disp_dev) == 
UCLASS_VIDEO_BRIDGE) {
+                               ret = video_bridge_attach(priv->disp_dev);
+                               if (ret) {
+                                       dev_err(dev, "fail to attach bridge\n");
+                                       return ret;
+                               }
+
+                               ret = 
video_bridge_set_backlight(priv->disp_dev, 80);
+                               if (ret) {
+                                       dev_err(dev, "fail to set backlight\n");
+                                       return ret;
+                               }
+
+                               enable_bridge = true;
+                               video_bridge_check_timing(priv->disp_dev, 
&timings);
+                       }
+               }
+
+               if (device_get_uclass_id(priv->disp_dev) == UCLASS_PANEL) {
+                       ret = panel_enable_backlight(priv->disp_dev);
+                       if (ret) {
+                               dev_err(dev, "panel %s enable backlight error 
%d\n",
+                                       priv->disp_dev->name, ret);
+                               return ret;
+                       }
+               }
+       }
+
+       ret = mxs_probe_common(dev, &timings, bpp, plat->base, enable_bridge);
        if (ret)
                return ret;
 
@@ -343,33 +407,9 @@ static int mxs_video_probe(struct udevice *dev)
 static int mxs_video_bind(struct udevice *dev)
 {
        struct video_uc_plat *plat = dev_get_uclass_plat(dev);
-       struct display_timing timings;
-       u32 bpp = 0;
-       u32 bytes_pp = 0;
-       int ret;
 
-       ret = mxs_of_get_timings(dev, &timings, &bpp);
-       if (ret)
-               return ret;
-
-       switch (bpp) {
-       case 32:
-       case 24:
-       case 18:
-               bytes_pp = 4;
-               break;
-       case 16:
-               bytes_pp = 2;
-               break;
-       case 8:
-               bytes_pp = 1;
-               break;
-       default:
-               dev_err(dev, "invalid bpp specified (bpp = %i)\n", bpp);
-               return -EINVAL;
-       }
-
-       plat->size = timings.hactive.typ * timings.vactive.typ * bytes_pp;
+       /* Max size supported by LCDIF, because in bind, we can't probe panel */
+       plat->size = 1920 * 1080 * 4 * 2;
 
        return 0;
 }
@@ -377,8 +417,12 @@ static int mxs_video_bind(struct udevice *dev)
 static int mxs_video_remove(struct udevice *dev)
 {
        struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+       struct mxsfb_priv *priv = dev_get_priv(dev);
+
+       if (priv->disp_dev)
+               device_remove(priv->disp_dev, DM_REMOVE_NORMAL);
 
-       mxs_remove_common(plat->base);
+       mxs_remove_common(priv->reg_base, plat->base);
 
        return 0;
 }
@@ -389,6 +433,8 @@ static const struct udevice_id mxs_video_ids[] = {
        { .compatible = "fsl,imx6sx-lcdif" },
        { .compatible = "fsl,imx7ulp-lcdif" },
        { .compatible = "fsl,imxrt-lcdif" },
+       { .compatible = "fsl,imx8mm-lcdif" },
+       { .compatible = "fsl,imx8mn-lcdif" },
        { /* sentinel */ }
 };
 
@@ -400,4 +446,5 @@ U_BOOT_DRIVER(mxs_video) = {
        .probe  = mxs_video_probe,
        .remove = mxs_video_remove,
        .flags  = DM_FLAG_PRE_RELOC | DM_FLAG_OS_PREPARE,
+       .priv_auto   = sizeof(struct mxsfb_priv),
 };
-- 
2.43.0

Reply via email to