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>
This commit is contained in:
parent
6ada132864
commit
c618a3a93b
@ -180,6 +180,9 @@ struct dss_pll_hw {
|
|||||||
|
|
||||||
/* DRA7 errata i886: use high N & M to avoid jitter */
|
/* DRA7 errata i886: use high N & M to avoid jitter */
|
||||||
bool errata_i886;
|
bool errata_i886;
|
||||||
|
|
||||||
|
/* DRA7 errata i932: retry pll lock on failure */
|
||||||
|
bool errata_i932;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dss_pll {
|
struct dss_pll {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#define DSS_SUBSYS_NAME "PLL"
|
#define DSS_SUBSYS_NAME "PLL"
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/kernel.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;
|
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,
|
int dss_pll_write_config_type_a(struct dss_pll *pll,
|
||||||
const struct dss_pll_clock_info *cinfo)
|
const struct dss_pll_clock_info *cinfo)
|
||||||
{
|
{
|
||||||
@ -436,6 +453,41 @@ int dss_pll_write_config_type_a(struct dss_pll *pll,
|
|||||||
l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */
|
l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */
|
||||||
writel_relaxed(l, base + PLL_CONFIGURATION2);
|
writel_relaxed(l, base + PLL_CONFIGURATION2);
|
||||||
|
|
||||||
|
if (hw->errata_i932) {
|
||||||
|
int cnt = 0;
|
||||||
|
u32 sleep_time;
|
||||||
|
const u32 max_lock_retries = 20;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate wait time for PLL LOCK
|
||||||
|
* 1000 REFCLK cycles in us.
|
||||||
|
*/
|
||||||
|
sleep_time = DIV_ROUND_UP(1000*1000*1000, cinfo->fint);
|
||||||
|
|
||||||
|
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 */
|
writel_relaxed(1, base + PLL_GO); /* PLL_GO */
|
||||||
|
|
||||||
if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
|
if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
|
||||||
@ -449,6 +501,7 @@ int dss_pll_write_config_type_a(struct dss_pll *pll,
|
|||||||
r = -EIO;
|
r = -EIO;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
l = readl_relaxed(base + PLL_CONFIGURATION2);
|
l = readl_relaxed(base + PLL_CONFIGURATION2);
|
||||||
l = FLD_MOD(l, 1, 14, 14); /* PHY_CLKINEN */
|
l = FLD_MOD(l, 1, 14, 14); /* PHY_CLKINEN */
|
||||||
|
@ -134,6 +134,7 @@ static const struct dss_pll_hw dss_dra7_video_pll_hw = {
|
|||||||
.has_refsel = true,
|
.has_refsel = true,
|
||||||
|
|
||||||
.errata_i886 = true,
|
.errata_i886 = true,
|
||||||
|
.errata_i932 = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dss_pll *dss_video_pll_init(struct dss_device *dss,
|
struct dss_pll *dss_video_pll_init(struct dss_device *dss,
|
||||||
|
Loading…
Reference in New Issue
Block a user