drm/omap: Implement workaround for DRA7 errata ID:i932
authorVenkateswara Rao Mandela <venkat.mandela@ti.com>
Wed, 24 Jan 2018 10:45:09 +0000 (16:15 +0530)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Thu, 28 Jun 2018 10:41:05 +0000 (13:41 +0300)
Description of DRA7 Errata i932:

In rare circumstances DPLL_VIDEO1 and DPLL_VIDEO2 PLL's may not lock on
the first attempt during DSS initialization. When this occurs, a
subsequent attempt to relock the PLL will result in PLL successfully
locking.

This patch does the following as per the errata recommendation:

- retries locking the PLL upto 20 times.

- The time to wait for a PLL lock set to 1000 REFCLK cycles. We use
usleep_range to wait for 1000 REFCLK cycles in the us range. This tight
constraint is imposed as a lock later than 1000 REFCLK cycles may have
high jitter.

- Criteria for PLL lock is extended from check on just the PLL_LOCK bit
to check on 6 PLL_STATUS bits.

Silicon Versions Impacted:
DRA71, DRA72, DRA74, DRA76 - All silicon revisions
AM57x - All silicon revisions

OMAP4/5 are not impacted by this errata

Signed-off-by: Venkateswara Rao Mandela <venkat.mandela@ti.com>
[tomi.valkeinen@ti.com: ported to v4.14]
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
drivers/gpu/drm/omapdrm/dss/dss.h
drivers/gpu/drm/omapdrm/dss/pll.c
drivers/gpu/drm/omapdrm/dss/video-pll.c

index 847c78ade024d5cc8c353372a3ed96b137a7b452..9f9a700bb6d5d278f91253a496abbb5a20aa2db1 100644 (file)
@@ -180,6 +180,9 @@ struct dss_pll_hw {
 
        /* DRA7 errata i886: use high N & M to avoid jitter */
        bool errata_i886;
+
+       /* DRA7 errata i932: retry pll lock on failure */
+       bool errata_i932;
 };
 
 struct dss_pll {
index 078b0e8216c382c88769c51f1b7cb29d86d9c6df..ff362b38bf0d436485c68e2cf4c6e60331df0444 100644 (file)
@@ -16,6 +16,7 @@
 
 #define DSS_SUBSYS_NAME "PLL"
 
+#include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -381,6 +382,22 @@ static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
        return -ETIMEDOUT;
 }
 
+static bool pll_is_locked(u32 stat)
+{
+       /*
+        * Required value for each bitfield listed below
+        *
+        * PLL_STATUS[6] = 0  PLL_BYPASS
+        * PLL_STATUS[5] = 0  PLL_HIGHJITTER
+        *
+        * PLL_STATUS[3] = 0  PLL_LOSSREF
+        * PLL_STATUS[2] = 0  PLL_RECAL
+        * PLL_STATUS[1] = 1  PLL_LOCK
+        * PLL_STATUS[0] = 1  PLL_CTRL_RESET_DONE
+        */
+       return ((stat & 0x6f) == 0x3);
+}
+
 int dss_pll_write_config_type_a(struct dss_pll *pll,
                const struct dss_pll_clock_info *cinfo)
 {
@@ -436,18 +453,54 @@ int dss_pll_write_config_type_a(struct dss_pll *pll,
        l = FLD_MOD(l, 0, 25, 25);              /* M7_CLOCK_EN */
        writel_relaxed(l, base + PLL_CONFIGURATION2);
 
-       writel_relaxed(1, base + PLL_GO);       /* PLL_GO */
+       if (hw->errata_i932) {
+               int cnt = 0;
+               u32 sleep_time;
+               const u32 max_lock_retries = 20;
 
-       if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
-               DSSERR("DSS DPLL GO bit not going down.\n");
-               r = -EIO;
-               goto err;
-       }
+               /*
+                * Calculate wait time for PLL LOCK
+                * 1000 REFCLK cycles in us.
+                */
+               sleep_time = DIV_ROUND_UP(1000*1000*1000, cinfo->fint);
 
-       if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
-               DSSERR("cannot lock DSS DPLL\n");
-               r = -EIO;
-               goto err;
+               for (cnt = 0; cnt < max_lock_retries; cnt++) {
+                       writel_relaxed(1, base + PLL_GO);       /* PLL_GO */
+
+                       /**
+                        * read the register back to ensure the write is
+                        * flushed
+                        */
+                       readl_relaxed(base + PLL_GO);
+
+                       usleep_range(sleep_time, sleep_time + 5);
+                       l = readl_relaxed(base + PLL_STATUS);
+
+                       if (pll_is_locked(l) &&
+                           !(readl_relaxed(base + PLL_GO) & 0x1))
+                               break;
+
+               }
+
+               if (cnt == max_lock_retries) {
+                       DSSERR("cannot lock PLL\n");
+                       r = -EIO;
+                       goto err;
+               }
+       } else {
+               writel_relaxed(1, base + PLL_GO);       /* PLL_GO */
+
+               if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
+                       DSSERR("DSS DPLL GO bit not going down.\n");
+                       r = -EIO;
+                       goto err;
+               }
+
+               if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
+                       DSSERR("cannot lock DSS DPLL\n");
+                       r = -EIO;
+                       goto err;
+               }
        }
 
        l = readl_relaxed(base + PLL_CONFIGURATION2);
index 585ed94ccf1781f1633279ac7ed0d651d2f20fa1..cb46311f92c9d3c1990605e387a0b7bc9d898aaf 100644 (file)
@@ -134,6 +134,7 @@ static const struct dss_pll_hw dss_dra7_video_pll_hw = {
        .has_refsel = true,
 
        .errata_i886 = true,
+       .errata_i932 = true,
 };
 
 struct dss_pll *dss_video_pll_init(struct dss_device *dss,