소스 검색

drm/omap: Implement workaround for DRA7 errata ID:i932

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>
Venkateswara Rao Mandela 7 년 전
부모
커밋
c618a3a93b
3개의 변경된 파일67개의 추가작업 그리고 10개의 파일을 삭제
  1. 3 0
      drivers/gpu/drm/omapdrm/dss/dss.h
  2. 63 10
      drivers/gpu/drm/omapdrm/dss/pll.c
  3. 1 0
      drivers/gpu/drm/omapdrm/dss/video-pll.c

+ 3 - 0
drivers/gpu/drm/omapdrm/dss/dss.h

@@ -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 {

+ 63 - 10
drivers/gpu/drm/omapdrm/dss/pll.c

@@ -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);

+ 1 - 0
drivers/gpu/drm/omapdrm/dss/video-pll.c

@@ -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,