diff options
author | Vaishnav Achath <vaishnav.a@ti.com> | 2023-01-25 13:22:37 +0530 |
---|---|---|
committer | Praneeth Bajjuri <praneeth@ti.com> | 2023-01-25 14:40:04 -0600 |
commit | 6b1ab75271e902682e30e9b98857b7e660d022d1 (patch) | |
tree | 8820c90622da7931ff4fd2c14810126c1de93501 | |
parent | d94f8daea89ea884734a1ddadad00842dfad117f (diff) |
mtd: hbmc-am654: Update HyperBus calibration sequence
Update the HyperBus calibration sequence to fix the instabilities
seen during calibration.The current calibration sequence is same
as described in J721E TRM[1] which is as follows:
1) Ensure FIFO RAM Auto-init is complete
2) Attempt to read 64 bytes of data from CFI region
for 16 iterations and if data is same in 4 successive iterations
then consider Delay Locked Loop(DLL) is stabilized.
3) Verify DLL lock by verifying MDLL_LOCK and SDL_LOCK bit set in
CFG_DLL_STAT register.
4) Confirm calibration by checking for "QRY" string in CFI region.
Also perform minor cleanup and update am654_hyperbus_calibrate()
to return non-zero value on failure.
Signed-off-by: Vaishnav Achath <vaishnav.a@ti.com>
Reviewed-by: Siddharth Vadapalli <s-vadapalli@ti.com>
-rw-r--r-- | drivers/mtd/hbmc-am654.c | 89 |
1 files changed, 75 insertions, 14 deletions
diff --git a/drivers/mtd/hbmc-am654.c b/drivers/mtd/hbmc-am654.c index 846b0e832b..ec375fd54e 100644 --- a/drivers/mtd/hbmc-am654.c +++ b/drivers/mtd/hbmc-am654.c @@ -12,27 +12,32 @@ #define FSS_SYSC_REG 0x4 -#define HYPERBUS_CALIB_COUNT 25 +#define HYPERBUS_CALIB_COUNT 64 +#define HYPERBUS_CALIB_MIN_TRIES 48 +#define HYPERBUS_CALIB_SUCCESS_COUNT 4 +#define HYPERBUS_CALIB_SIZE 64 + +#define HYPERBUS_CFG_DLL_STAT_REG 4 +#define HYPERBUS_CFG_MDLL_LOCK BIT(0) +#define HYPERBUS_CFG_SDLL_LOCK BIT(1) +#define HYPERBUS_CFG_RAM_STAT_REG 8 +#define HYPERBUS_CFG_RAM_FIFO_INIT_DONE BIT(0) struct am654_hbmc_priv { void __iomem *mmiobase; + void __iomem *cfgregbase; bool calibrated; }; -/* Calibrate by looking for "QRY" string within the CFI space */ -static int am654_hyperbus_calibrate(struct udevice *dev) +/* confirm calibration by looking for "QRY" string within the CFI space */ +static int am654_hyperbus_calibrate_check(struct udevice *dev) { struct am654_hbmc_priv *priv = dev_get_priv(dev); int count = HYPERBUS_CALIB_COUNT; int pass_count = 0; + int ret = -EIO; u16 qry[3]; - if (priv->calibrated) - return 0; - - writew(0xF0, priv->mmiobase); - writew(0x98, priv->mmiobase + 0xaa); - while (count--) { qry[0] = readw(priv->mmiobase + 0x20); qry[1] = readw(priv->mmiobase + 0x22); @@ -42,13 +47,67 @@ static int am654_hyperbus_calibrate(struct udevice *dev) pass_count++; else pass_count = 0; - if (pass_count == 5) + + if (pass_count > HYPERBUS_CALIB_SUCCESS_COUNT) + return 0; + } + + return ret; +} + +static int am654_hyperbus_calibrate(struct udevice *dev) +{ + struct am654_hbmc_priv *priv = dev_get_priv(dev); + char verifybuf[HYPERBUS_CALIB_SIZE]; + char rdbuf[HYPERBUS_CALIB_SIZE]; + int tries = HYPERBUS_CALIB_COUNT; + int pass_count = 0; + unsigned int reg; + int ret = -EIO; + + if (priv->calibrated) + return 0; + + if (!priv->cfgregbase || !priv->mmiobase) + return ret; + + reg = readl(priv->cfgregbase + HYPERBUS_CFG_RAM_STAT_REG); + if (!(reg & HYPERBUS_CFG_RAM_FIFO_INIT_DONE)) { + dev_err(dev, "Hyperbus RAM FIFO init failed\n"); + return ret; + } + + writew(0xF0, priv->mmiobase); + writew(0x98, priv->mmiobase + 0xaa); + + /* + * Perform calibration by reading 64 bytes from CFI region and + * compare with previously read data, and ensure Delay Locked Loop(DLL) + * is stabilized. + */ + while (tries--) { + memcpy(rdbuf, priv->mmiobase, HYPERBUS_CALIB_SIZE); + if (!memcmp(rdbuf, verifybuf, HYPERBUS_CALIB_SIZE)) { + reg = readl(priv->cfgregbase + HYPERBUS_CFG_DLL_STAT_REG); + if ((reg & HYPERBUS_CFG_MDLL_LOCK) && + (reg & HYPERBUS_CFG_SDLL_LOCK)) + pass_count++; + else + pass_count = 0; + } + memcpy(verifybuf, rdbuf, HYPERBUS_CALIB_SIZE); + if (pass_count > HYPERBUS_CALIB_SUCCESS_COUNT && + tries < HYPERBUS_CALIB_MIN_TRIES) break; } + + if (tries > 0) + ret = am654_hyperbus_calibrate_check(dev); + writew(0xF0, priv->mmiobase); writew(0xFF, priv->mmiobase); - return pass_count == 5; + return ret; } static int am654_select_hbmc(struct udevice *dev) @@ -68,7 +127,9 @@ static int am654_hbmc_probe(struct udevice *dev) struct am654_hbmc_priv *priv = dev_get_priv(dev); int ret; - priv->mmiobase = devfdt_remap_addr_index(dev, 1); + priv->cfgregbase = devfdt_remap_addr_index(dev, 0); + priv->mmiobase = devfdt_remap_addr_index(dev, 2); + if (dev_read_bool(dev, "mux-controls")) { ret = am654_select_hbmc(dev); if (ret) { @@ -79,9 +140,9 @@ static int am654_hbmc_probe(struct udevice *dev) if (!priv->calibrated) { ret = am654_hyperbus_calibrate(dev); - if (!ret) { + if (IS_ERR_VALUE(ret)) { dev_err(dev, "Calibration Failed\n"); - return -EIO; + return ret; } } priv->calibrated = true; |