ahci: Support spin-up and link-up separately
Add HDD handling to the SSD-only AHCI driver, by separately dealing with
spin-up and link-up.
Signed-off-by: Marc Jones <marc.jones@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index 719574f..19c5f13 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -53,6 +53,7 @@
#endif
/* Maximum timeouts for each event */
+#define WAIT_MS_SPINUP 10000
#define WAIT_MS_DATAIO 5000
#define WAIT_MS_LINKUP 4
@@ -129,7 +130,7 @@
unsigned short vendor;
#endif
volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base;
- u32 tmp, cap_save;
+ u32 tmp, cap_save, cmd;
int i, j;
volatile u8 *port_mmio;
@@ -137,7 +138,7 @@
cap_save = readl(mmio + HOST_CAP);
cap_save &= ((1 << 28) | (1 << 17));
- cap_save |= (1 << 27);
+ cap_save |= (1 << 27); /* Staggered Spin-up. Not needed. */
/* global controller reset */
tmp = readl(mmio + HOST_CTL);
@@ -201,9 +202,18 @@
msleep(500);
}
- debug("Spinning up port %d... ", i);
- writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
+ /* Add the spinup command to whatever mode bits may
+ * already be on in the command register.
+ */
+ cmd = readl(port_mmio + PORT_CMD);
+ cmd |= PORT_CMD_FIS_RX;
+ cmd |= PORT_CMD_SPIN_UP;
+ writel_with_flush(cmd, port_mmio + PORT_CMD);
+ /* Bring up SATA link.
+ * SATA link bringup time is usually less than 1 ms; only very
+ * rarely has it taken between 1-2 ms. Never seen it above 2 ms.
+ */
j = 0;
while (j < WAIT_MS_LINKUP) {
tmp = readl(port_mmio + PORT_SCR_STAT);
@@ -212,7 +222,30 @@
udelay(1000);
j++;
}
- if (j == WAIT_MS_LINKUP)
+ if (j == WAIT_MS_LINKUP) {
+ printf("SATA link %d timeout.\n", i);
+ continue;
+ } else {
+ debug("SATA link ok.\n");
+ }
+
+ /* Clear error status */
+ tmp = readl(port_mmio + PORT_SCR_ERR);
+ if (tmp)
+ writel(tmp, port_mmio + PORT_SCR_ERR);
+
+ debug("Spinning up device on SATA port %d... ", i);
+
+ j = 0;
+ while (j < WAIT_MS_SPINUP) {
+ tmp = readl(port_mmio + PORT_TFDATA);
+ if (!(tmp & (ATA_STAT_BUSY | ATA_STAT_DRQ)))
+ break;
+ udelay(1000);
+ j++;
+ }
+ printf("Target spinup took %d ms.\n", j);
+ if (j == WAIT_MS_SPINUP)
debug("timeout.\n");
else
debug("ok.\n");