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 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>
This commit is contained in:
parent
225211de52
commit
be1514f547
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue