|
@@ -15,7 +15,9 @@
|
|
#include <linux/mmc/slot-gpio.h>
|
|
#include <linux/mmc/slot-gpio.h>
|
|
#include "sdhci-pltfm.h"
|
|
#include "sdhci-pltfm.h"
|
|
|
|
|
|
|
|
+#define SDHCI_CLK_DELAY_SETTING 0x4C
|
|
#define SDHCI_SIRF_8BITBUS BIT(3)
|
|
#define SDHCI_SIRF_8BITBUS BIT(3)
|
|
|
|
+#define SIRF_TUNING_COUNT 128
|
|
|
|
|
|
struct sdhci_sirf_priv {
|
|
struct sdhci_sirf_priv {
|
|
struct clk *clk;
|
|
struct clk *clk;
|
|
@@ -49,7 +51,76 @@ static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
|
|
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
|
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
|
|
|
|
+{
|
|
|
|
+ int tuning_seq_cnt = 3;
|
|
|
|
+ u8 phase, tuned_phases[SIRF_TUNING_COUNT];
|
|
|
|
+ u8 tuned_phase_cnt = 0;
|
|
|
|
+ int rc, longest_range = 0;
|
|
|
|
+ int start = -1, end = 0, tuning_value = -1, range = 0;
|
|
|
|
+ u16 clock_setting;
|
|
|
|
+ struct mmc_host *mmc = host->mmc;
|
|
|
|
+
|
|
|
|
+ clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING);
|
|
|
|
+ clock_setting &= ~0x3fff;
|
|
|
|
+
|
|
|
|
+retry:
|
|
|
|
+ phase = 0;
|
|
|
|
+ do {
|
|
|
|
+ sdhci_writel(host,
|
|
|
|
+ clock_setting | phase | (phase << 7) | (phase << 16),
|
|
|
|
+ SDHCI_CLK_DELAY_SETTING);
|
|
|
|
+
|
|
|
|
+ if (!mmc_send_tuning(mmc)) {
|
|
|
|
+ /* Tuning is successful at this tuning point */
|
|
|
|
+ tuned_phases[tuned_phase_cnt++] = phase;
|
|
|
|
+ dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
|
|
|
|
+ mmc_hostname(mmc), phase);
|
|
|
|
+ if (start == -1)
|
|
|
|
+ start = phase;
|
|
|
|
+ end = phase;
|
|
|
|
+ range++;
|
|
|
|
+ if (phase == (SIRF_TUNING_COUNT - 1)
|
|
|
|
+ && range > longest_range)
|
|
|
|
+ tuning_value = (start + end) / 2;
|
|
|
|
+ } else {
|
|
|
|
+ dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n",
|
|
|
|
+ mmc_hostname(mmc), phase);
|
|
|
|
+ if (range > longest_range) {
|
|
|
|
+ tuning_value = (start + end) / 2;
|
|
|
|
+ longest_range = range;
|
|
|
|
+ }
|
|
|
|
+ start = -1;
|
|
|
|
+ end = range = 0;
|
|
|
|
+ }
|
|
|
|
+ } while (++phase < ARRAY_SIZE(tuned_phases));
|
|
|
|
+
|
|
|
|
+ if (tuned_phase_cnt && tuning_value > 0) {
|
|
|
|
+ /*
|
|
|
|
+ * Finally set the selected phase in delay
|
|
|
|
+ * line hw block.
|
|
|
|
+ */
|
|
|
|
+ phase = tuning_value;
|
|
|
|
+ sdhci_writel(host,
|
|
|
|
+ clock_setting | phase | (phase << 7) | (phase << 16),
|
|
|
|
+ SDHCI_CLK_DELAY_SETTING);
|
|
|
|
+
|
|
|
|
+ dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
|
|
|
|
+ mmc_hostname(mmc), phase);
|
|
|
|
+ } else {
|
|
|
|
+ if (--tuning_seq_cnt)
|
|
|
|
+ goto retry;
|
|
|
|
+ /* Tuning failed */
|
|
|
|
+ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
|
|
|
|
+ mmc_hostname(mmc));
|
|
|
|
+ rc = -EIO;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
static struct sdhci_ops sdhci_sirf_ops = {
|
|
static struct sdhci_ops sdhci_sirf_ops = {
|
|
|
|
+ .platform_execute_tuning = sdhci_sirf_execute_tuning,
|
|
.set_clock = sdhci_set_clock,
|
|
.set_clock = sdhci_set_clock,
|
|
.get_max_clock = sdhci_sirf_get_max_clk,
|
|
.get_max_clock = sdhci_sirf_get_max_clk,
|
|
.set_bus_width = sdhci_sirf_set_bus_width,
|
|
.set_bus_width = sdhci_sirf_set_bus_width,
|