diff options
author | Steffen Trumtrar <s.trumtrar@pengutronix.de> | 2022-01-18 15:04:53 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2022-01-20 09:30:06 +0100 |
commit | be222714503f37075a1cc4ee29f47f6734251b67 (patch) | |
tree | 52b10619ce870640e5444f1bf2ed803a58ff11c3 | |
parent | 59d6f015088ae1729259b5e14fa2efecf87f056e (diff) | |
download | barebox-be222714503f37075a1cc4ee29f47f6734251b67.tar.gz barebox-be222714503f37075a1cc4ee29f47f6734251b67.tar.xz |
ata: sata_mv: try probing multiple times
In case of an un-recoverable probe error, try the whole sequence again,
starting with the hard-reset of the core.
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
Link: https://lore.barebox.org/20220118140453.1860909-7-s.trumtrar@pengutronix.de
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | drivers/ata/sata_mv.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 49205d24d8..05b27f1008 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -47,6 +47,7 @@ static void ata_ioports_init(struct ata_ioports *io, #define REG_ATA_BASE 0x2100 #define REG_SSTATUS(n) ((n) * 0x2000 + 0x2300) #define REG_SERROR(n) ((n) * 0x2000 + 0x2304) +#define REG_SERROR_MASK 0x03fe0000 #define REG_SCONTROL(n) ((n) * 0x2000 + 0x2308) #define REG_SCONTROL__DET 0x0000000f #define REG_SCONTROL__DET__INIT 0x00000001 @@ -94,8 +95,10 @@ static int mv_sata_probe(struct device_d *dev) struct resource *iores; void __iomem *base; struct ide_port *ide; + u32 try_again = 0; u32 scontrol; int ret, i; + u32 tmp; iores = dev_request_mem_resource(dev, 0); if (IS_ERR(iores)) { @@ -114,6 +117,7 @@ static int mv_sata_probe(struct device_d *dev) writel(0x7fff0e01, base + REG_WINDOW_CONTROL(0)); writel(0, base + REG_WINDOW_BASE(0)); +again: /* Clear SError */ writel(0x0, base + REG_SERROR(0)); /* disable EDMA */ @@ -175,6 +179,32 @@ static int mv_sata_probe(struct device_d *dev) if (ret) free(ide); + /* + * Under most conditions the above is enough and works as expected. + * With some specific hardware combinations, the setup fails however + * leading to an unusable SATA drive. From the error status bits it + * was not obvious what exactly went wrong. + * The ARMADA-XP datasheet advices to hard-reset the SATA core and + * drive and try again. + * When this happens, just try again multiple times, to give the drive + * some time to reach a stable state. If after 5 (randomly chosen) tries, + * the drive still doesn't work, just give up on it. + */ + tmp = readl(base + REG_SERROR(0)); + if (tmp & REG_SERROR_MASK) { + try_again++; + if (try_again > 5) + return -ENODEV; + dev_dbg(dev, "PHY layer error. Try again. (serror=0x%08x)\n", tmp); + if (ide->port.initialized) { + blockdevice_unregister(&ide->port.blk); + unregister_device(&ide->port.class_dev); + } + + mdelay(100); + goto again; + } + return ret; } |