|
@@ -33,6 +33,10 @@
|
|
#include <asm/arch/mmc_host_def.h>
|
|
#include <asm/arch/mmc_host_def.h>
|
|
#include <asm/arch/sys_proto.h>
|
|
#include <asm/arch/sys_proto.h>
|
|
|
|
|
|
|
|
+/* common definitions for all OMAPs */
|
|
|
|
+#define SYSCTL_SRC (1 << 25)
|
|
|
|
+#define SYSCTL_SRD (1 << 26)
|
|
|
|
+
|
|
/* If we fail after 1 second wait, something is really bad */
|
|
/* If we fail after 1 second wait, something is really bad */
|
|
#define MAX_RETRY_MS 1000
|
|
#define MAX_RETRY_MS 1000
|
|
|
|
|
|
@@ -195,6 +199,27 @@ static int mmc_init_setup(struct mmc *mmc)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * MMC controller internal finite state machine reset
|
|
|
|
+ *
|
|
|
|
+ * Used to reset command or data internal state machines, using respectively
|
|
|
|
+ * SRC or SRD bit of SYSCTL register
|
|
|
|
+ */
|
|
|
|
+static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
|
|
|
|
+{
|
|
|
|
+ ulong start;
|
|
|
|
+
|
|
|
|
+ mmc_reg_out(&mmc_base->sysctl, bit, bit);
|
|
|
|
+
|
|
|
|
+ start = get_timer(0);
|
|
|
|
+ while ((readl(&mmc_base->sysctl) & bit) != 0) {
|
|
|
|
+ if (get_timer(0) - start > MAX_RETRY_MS) {
|
|
|
|
+ printf("%s: timedout waiting for sysctl %x to clear\n",
|
|
|
|
+ __func__, bit);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
|
static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
|
struct mmc_data *data)
|
|
struct mmc_data *data)
|
|
@@ -284,9 +309,10 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
|
}
|
|
}
|
|
} while (!mmc_stat);
|
|
} while (!mmc_stat);
|
|
|
|
|
|
- if ((mmc_stat & IE_CTO) != 0)
|
|
|
|
|
|
+ if ((mmc_stat & IE_CTO) != 0) {
|
|
|
|
+ mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
|
|
return TIMEOUT;
|
|
return TIMEOUT;
|
|
- else if ((mmc_stat & ERRI_MASK) != 0)
|
|
|
|
|
|
+ } else if ((mmc_stat & ERRI_MASK) != 0)
|
|
return -1;
|
|
return -1;
|
|
|
|
|
|
if (mmc_stat & CC_MASK) {
|
|
if (mmc_stat & CC_MASK) {
|
|
@@ -337,6 +363,9 @@ static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size)
|
|
}
|
|
}
|
|
} while (mmc_stat == 0);
|
|
} while (mmc_stat == 0);
|
|
|
|
|
|
|
|
+ if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
|
|
|
|
+ mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
|
|
|
|
+
|
|
if ((mmc_stat & ERRI_MASK) != 0)
|
|
if ((mmc_stat & ERRI_MASK) != 0)
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
@@ -389,6 +418,9 @@ static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
|
|
}
|
|
}
|
|
} while (mmc_stat == 0);
|
|
} while (mmc_stat == 0);
|
|
|
|
|
|
|
|
+ if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
|
|
|
|
+ mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
|
|
|
|
+
|
|
if ((mmc_stat & ERRI_MASK) != 0)
|
|
if ((mmc_stat & ERRI_MASK) != 0)
|
|
return 1;
|
|
return 1;
|
|
|
|
|