mmc_host_clk_release(host);
}
-void mmc_finish_tuning(struct mmc_host *host)
-{
- host->ios.finish_tuning_flag = 1;
- mmc_set_ios(host);
- host->ios.finish_tuning_flag = 0;
-}
-
-void mmc_set_tuning(struct mmc_host *host, unsigned int tuning)
-{
- WARN_ON(tuning < host->tuning_min);
- if (tuning > host->tuning_max)
- tuning = host->tuning_max;
-
- host->ios.tuning = tuning;
- host->ios.tuning_flag = 1;
- mmc_set_ios(host);
- host->ios.tuning_flag = 0;
-}
-
#ifdef CONFIG_MMC_CLKGATE
/*
* This gates the clock by setting it to 0 Hz.
void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
-void mmc_set_tuning(struct mmc_host *host, unsigned int tuning);
-void mmc_finish_tuning(struct mmc_host *host);
void mmc_gate_clock(struct mmc_host *host);
void mmc_ungate_clock(struct mmc_host *host);
void mmc_set_ungated(struct mmc_host *host);
goto out;
/* SPI mode doesn't define CMD19 */
-#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
- if (!mmc_host_is_spi(card->host) &&
- (card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) {
- int min, max, avg;
-
- min = card->host->tuning_min;
- while (min < card->host->tuning_max) {
- mmc_set_tuning(card->host, min);
- if (!mmc_send_tuning_cmd(card))
- break;
- min += card->host->tuning_step;
- }
-
- max = min + card->host->tuning_step;
- while (max < card->host->tuning_max) {
- mmc_set_tuning(card->host, max);
- if (mmc_send_tuning_cmd(card)) {
- max -= card->host->tuning_step;
- break;
- }
- max += card->host->tuning_step;
- }
-
- avg = (min + max) / 2;
- mmc_set_tuning(card->host, avg);
- mmc_send_tuning_cmd(card);
- mmc_finish_tuning(card->host);
- }
-#else
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
err = card->host->ops->execute_tuning(card->host);
-#endif
out:
kfree(status);
return 0;
}
-int mmc_send_tuning_cmd(struct mmc_card *card)
-{
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
- struct scatterlist sg;
- char scr[64];
-
- BUG_ON(!card);
- BUG_ON(!card->host);
-
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
- memset(scr, 0, 64);
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = MMC_SEND_TUNING_BLOCK;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, scr, 64);
-
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(card->host, &mrq);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
-}
-
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
{
int err;
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp);
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
-int mmc_send_tuning_cmd(struct mmc_card *card);
#endif
#include <linux/mmc/host.h>
#include <linux/mmc/sdhci-pltfm.h>
#include <linux/mmc/mmc.h>
+#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sd.h>
+#include <linux/scatterlist.h>
#include <mach/hardware.h>
#include <mach/esdhc.h>
#include "sdhci.h"
#define SDHCI_FSL_SVN_300 0x11
+#define SDHCI_TUNING_BLOCK_PATTERN_LEN 64
/*
* There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC:
* Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design,
*/
#define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1)
+static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val);
+static void esdhc_post_tuning(struct sdhci_host *host);
+
struct pltfm_imx_data {
int flags;
u32 scratchpad;
unsigned char uhs_mode;
};
+static void request_done(struct mmc_request *mrq)
+{
+ complete(&mrq->completion);
+}
+
+static int esdhc_send_tuning_cmd(struct sdhci_host *host)
+{
+ struct mmc_command cmd = {0};
+ struct mmc_request mrq = {0};
+ struct mmc_data data = {0};
+ struct scatterlist sg;
+ char tuning_pattern[SDHCI_TUNING_BLOCK_PATTERN_LEN];
+
+ cmd.opcode = MMC_SEND_TUNING_BLOCK;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = SDHCI_TUNING_BLOCK_PATTERN_LEN;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern));
+
+ mrq.cmd = &cmd;
+ mrq.cmd->mrq = &mrq;
+ mrq.data = &data;
+ mrq.data->mrq = &mrq;
+ mrq.cmd->data = mrq.data;
+
+ mrq.done = request_done;
+
+ init_completion(&(mrq.completion));
+ sdhci_request(host->mmc, &mrq);
+ wait_for_completion(&(mrq.completion));
+
+ if (cmd.error)
+ return cmd.error;
+ if (data.error)
+ return data.error;
+
+ return 0;
+}
+
+static int esdhc_execute_tuning(struct sdhci_host *host)
+{
+ int min, max, avg;
+
+ min = host->tuning_min;
+ while (min < host->tuning_max) {
+ esdhc_prepare_tuning(host, min);
+ if (!esdhc_send_tuning_cmd(host))
+ break;
+ min += host->tuning_step;
+ }
+
+ max = min + host->tuning_step;
+ while (max < host->tuning_max) {
+ esdhc_prepare_tuning(host, max);
+ if (esdhc_send_tuning_cmd(host)) {
+ max -= host->tuning_step;
+ break;
+ }
+ max += host->tuning_step;
+ }
+
+ avg = (min + max) / 2;
+ esdhc_prepare_tuning(host, avg);
+ esdhc_send_tuning_cmd(host);
+ esdhc_post_tuning(host);
+ return 0;
+}
+
static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
{
void __iomem *base = host->ioaddr + (reg & ~0x3);
return readw(host->ioaddr + reg);
}
-void esdhc_post_tuning(struct sdhci_host *host)
+static void esdhc_post_tuning(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
}
}
-void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
+static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
{
u32 reg;
.set_clock = esdhc_set_clock,
.get_max_clock = esdhc_pltfm_get_max_clock,
.get_min_clock = esdhc_pltfm_get_min_clock,
- .pre_tuning = esdhc_prepare_tuning,
- .post_tuning = esdhc_post_tuning,
.platform_8bit_width = plt_8bit_width,
.platform_clk_ctrl = plt_clk_ctrl,
};
host->ocr_avail_mmc = MMC_VDD_29_30 | MMC_VDD_30_31 | \
MMC_VDD_32_33 | MMC_VDD_33_34;
+ if (cpu_is_mx6q() || cpu_is_mx6dl())
+ sdhci_esdhc_ops.platform_execute_tuning = esdhc_execute_tuning;
+
if (boarddata->support_18v)
host->ocr_avail_sd |= MMC_VDD_165_195;
if (boarddata->support_8bit)
* *
\*****************************************************************************/
-static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
bool present;
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
- if (ios->finish_tuning_flag) {
- if (host->ops->post_tuning)
- host->ops->post_tuning(host);
- goto out;
- }
-
- if (ios->tuning_flag) {
- /* means this request is for tuning only */
- if (host->ops->pre_tuning)
- host->ops->pre_tuning(host, ios->tuning);
- goto out;
- }
/*
* Reset the chip on each power off.
* Should clear out any weird states.
return 0;
}
+ if (ctrl & SDHCI_CTRL_EXEC_TUNING) {
+ if (host->ops->platform_execute_tuning) {
+ spin_unlock(&host->lock);
+ enable_irq(host->irq);
+ return host->ops->platform_execute_tuning(host);
+ }
+ }
+
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
/*
void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
- void (*pre_tuning)(struct sdhci_host *host, u32 val);
- void (*post_tuning)(struct sdhci_host *host);
void (*platform_clk_ctrl)(struct sdhci_host *host, bool enable);
+ int (*platform_execute_tuning)(struct sdhci_host *host);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);
#endif
+void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq);
+
#endif /* __SDHCI_HW_H */
#define MMC_SET_DRIVER_TYPE_A 1
#define MMC_SET_DRIVER_TYPE_C 2
#define MMC_SET_DRIVER_TYPE_D 3
- unsigned int tuning_flag; /* request tuning only */
- unsigned int finish_tuning_flag;
- unsigned int tuning; /* tuning parameter */
};
struct mmc_host_ops {