* [PATCH 1/4] mmc: mediatek: Add online-tuning support of EMMC/SD
[not found] ` <1439367845-5891-1-git-send-email-chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
@ 2015-08-12 8:24 ` Chaotian Jing
2015-08-17 11:31 ` Ulf Hansson
2015-08-12 8:24 ` [PATCH 2/4] mmc: mediatek: Add HS400 support Chaotian Jing
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Chaotian Jing @ 2015-08-12 8:24 UTC (permalink / raw)
To: Rob Herring, Matthias Brugger, Chris Ball, Ulf Hansson
Cc: Mark Rutland, James Liao, Catalin Marinas, Wenbin Mei,
Will Deacon, Russell King - ARM Linux, Hongzhou Yang,
Chaotian Jing, Joe.C, devicetree-u79uwXL29TY76Z2rM5mHXA,
Arnd Bergmann, bin.zhang-NuS5LvNUpcJWk0Htik3J/w,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Eddie Huang,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Liuquan Ji,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Yong Mao, Sascha Hauer
Schedule a workqueue to do tuning when CRC error
Call mmc_hw_reset to re-init card when data timeout
Signed-off-by: Chaotian Jing <chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
drivers/mmc/host/mtk-sd.c | 162 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 150 insertions(+), 12 deletions(-)
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 7153500..eb44fe1 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -27,6 +27,7 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
@@ -290,6 +291,10 @@ struct msdc_host {
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_uhs;
struct delayed_work req_timeout;
+ struct workqueue_struct *repeat_workqueue;
+ struct work_struct repeat_req;
+ struct mmc_request *repeat_mrq;
+ u32 tune_cmd_counter;
int irq; /* host interrupt */
struct clk *src_clk; /* msdc source clock */
@@ -353,7 +358,10 @@ static void msdc_reset_hw(struct msdc_host *host)
static void msdc_cmd_next(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd);
-static u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
+static const u32 cmd_ints_mask = MSDC_INTEN_CMDRDY | MSDC_INTEN_RSPCRCERR |
+ MSDC_INTEN_CMDTMO | MSDC_INTEN_ACMDRDY |
+ MSDC_INTEN_ACMDCRCERR | MSDC_INTEN_ACMDTMO;
+static const u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
MSDC_INTEN_DATCRCERR | MSDC_INTEN_DMA_BDCSERR |
MSDC_INTEN_DMA_GPDCSERR | MSDC_INTEN_DMA_PROTECT;
@@ -690,6 +698,18 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
msdc_track_cmd_data(host, mrq->cmd, mrq->data);
if (mrq->data)
msdc_unprepare_data(host, mrq);
+ if (host->error && host->mmc->card &&
+ !mmc_card_sdio(host->mmc->card)) {
+ if (mrq->cmd->error == (unsigned int)-EILSEQ ||
+ (mrq->stop && mrq->stop->error == (unsigned int)-EILSEQ) ||
+ (mrq->sbc && mrq->sbc->error == (unsigned int)-EILSEQ) ||
+ (mrq->data && mrq->data->error)) {
+ host->repeat_mrq = mrq;
+ queue_work(host->repeat_workqueue, &host->repeat_req);
+ return;
+ }
+ }
+ host->tune_cmd_counter = 0;
mmc_request_done(host->mmc, mrq);
pm_runtime_mark_last_busy(host->dev);
@@ -725,11 +745,7 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
if (done)
return true;
- sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
- MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
- MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
- MSDC_INTEN_ACMDTMO);
- writel(cmd->arg, host->base + SDC_ARG);
+ sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
@@ -819,10 +835,7 @@ static void msdc_start_command(struct msdc_host *host,
rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
- sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
- MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
- MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
- MSDC_INTEN_ACMDTMO);
+ sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
writel(cmd->arg, host->base + SDC_ARG);
writel(rawcmd, host->base + SDC_CMD);
}
@@ -942,6 +955,8 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
if (events & MSDC_INT_DATTMO)
data->error = -ETIMEDOUT;
+ else if (events & MSDC_INT_DATCRCERR)
+ data->error = -EILSEQ;
dev_err(host->dev, "%s: cmd=%d; blocks=%d",
__func__, mrq->cmd->opcode, data->blocks);
@@ -1113,8 +1128,8 @@ static void msdc_init_hw(struct msdc_host *host)
writel(0, host->base + MSDC_PAD_TUNE);
writel(0, host->base + MSDC_IOCON);
- sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
- writel(0x403c004f, host->base + MSDC_PATCH_BIT);
+ sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
+ writel(0x403c0046, host->base + MSDC_PATCH_BIT);
sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1);
writel(0xffff0089, host->base + MSDC_PATCH_BIT1);
/* Configure to enable SDIO mode.
@@ -1176,6 +1191,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_UP:
if (!IS_ERR(mmc->supply.vmmc)) {
+ msdc_init_hw(host);
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
ios->vdd);
if (ret) {
@@ -1214,6 +1230,120 @@ end:
pm_runtime_put_autosuspend(host->dev);
}
+static void msdc_reset_mrq(struct mmc_request *mrq)
+{
+ mrq->cmd->error = 0;
+ if (mrq->sbc)
+ mrq->sbc->error = 0;
+ if (mrq->data)
+ mrq->data->error = 0;
+ if (mrq->stop)
+ mrq->stop->error = 0;
+}
+
+/* Send CMD12 when tuning, do not check CRC error and timeout */
+static void msdc_send_stop(struct msdc_host *host)
+{
+ u32 opcode = MMC_STOP_TRANSMISSION;
+ u32 arg = 0;
+ u32 rawcmd = 0;
+ u32 intsts = 0;
+
+ /* Reset host first */
+ msdc_reset_hw(host);
+
+ rawcmd = (opcode & 0x3f) | (7 << 7);
+ rawcmd |= (1 << 14); /* stop cmd */
+
+ sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
+ writel(arg, host->base + SDC_ARG);
+ writel(rawcmd, host->base + SDC_CMD);
+
+ while (1) {
+ intsts = readl(host->base + MSDC_INT);
+ if (intsts) {
+ writel(intsts, host->base + MSDC_INT);
+ if (intsts & cmd_ints_mask) {
+ dev_dbg(host->dev, "result of cmd12: %x\n",
+ intsts);
+ break;
+ }
+ }
+ udelay(1);
+ }
+}
+
+/* When tuning, CMD13 may also get crc error, so use MSDC_PS to get card status */
+static void msdc_wait_card_not_busy(struct msdc_host *host)
+{
+ while (1) {
+ if ((readl(host->base + MSDC_PS) & BIT(16)) == 0) { /* check dat0 status */
+ msleep_interruptible(10);
+ dev_dbg(host->dev, "MSDC_PS: %08x, SDC_STS: %08x\n",
+ readl(host->base + MSDC_PS), readl(host->base + SDC_STS));
+ } else
+ break;
+ }
+}
+
+static void msdc_tune_request(struct msdc_host *host)
+{
+ u32 orig_rsmpl, orig_cksel;
+ u32 cur_rsmpl, cur_cksel = 0;
+ u32 ddr, clkmode;
+ struct mmc_ios ios = host->mmc->ios;
+
+ sdr_get_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL, &orig_rsmpl);
+ sdr_get_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL,
+ &orig_cksel);
+ cur_rsmpl = (orig_rsmpl + 1);
+ sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL, cur_rsmpl % 2);
+
+ if (ios.timing != MMC_TIMING_MMC_HS400) {
+ sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DSPL,
+ cur_rsmpl % 2);
+ sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL,
+ cur_rsmpl % 2);
+ }
+
+ if (cur_rsmpl >= 2) {
+ cur_cksel = orig_cksel + 1;
+ sdr_set_field(host->base + MSDC_PATCH_BIT,
+ MSDC_CKGEN_MSDC_DLY_SEL, cur_cksel % 16);
+ }
+
+ if (host->tune_cmd_counter++ >= 2 * 16) {
+ dev_warn(host->dev, "Tune fail at %dhz\n", host->mclk);
+ host->tune_cmd_counter = 0;
+ sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL, 0);
+ sdr_set_field(host->base + MSDC_PATCH_BIT,
+ MSDC_CKGEN_MSDC_DLY_SEL, 0);
+ sdr_get_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD, &clkmode);
+ ddr = (clkmode == 2) ? 1 : 0;
+ msdc_set_mclk(host, ddr, host->mclk / 2);
+ }
+}
+
+static void msdc_repeat_request(struct work_struct *work)
+{
+ struct msdc_host *host = container_of(work, struct msdc_host, repeat_req);
+ struct mmc_request *mrq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ mrq = host->repeat_mrq;
+ host->repeat_mrq = NULL;
+ spin_unlock_irqrestore(&host->lock, flags);
+ msdc_send_stop(host);
+ msdc_wait_card_not_busy(host);
+ if (mrq->data && mrq->data->error == -ETIMEDOUT)
+ mmc_hw_reset(host->mmc);
+ else
+ msdc_tune_request(host);
+ msdc_reset_mrq(mrq);
+ msdc_ops_request(host->mmc, mrq);
+}
+
static struct mmc_host_ops mt_msdc_ops = {
.post_req = msdc_post_req,
.pre_req = msdc_pre_req,
@@ -1324,6 +1454,12 @@ static int msdc_drv_probe(struct platform_device *pdev)
}
msdc_init_gpd_bd(host, &host->dma);
INIT_DELAYED_WORK(&host->req_timeout, msdc_request_timeout);
+ host->repeat_workqueue = create_singlethread_workqueue("repeat_workqueue");
+ if (!host->repeat_workqueue) {
+ ret = -ENOMEM;
+ goto release_mem;
+ }
+ INIT_WORK(&host->repeat_req, msdc_repeat_request);
spin_lock_init(&host->lock);
platform_set_drvdata(pdev, mmc);
@@ -1348,6 +1484,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
end:
pm_runtime_disable(host->dev);
release:
+ destroy_workqueue(host->repeat_workqueue);
platform_set_drvdata(pdev, NULL);
msdc_deinit_hw(host);
msdc_gate_clock(host);
@@ -1383,6 +1520,7 @@ static int msdc_drv_remove(struct platform_device *pdev)
pm_runtime_disable(host->dev);
pm_runtime_put_noidle(host->dev);
+ destroy_workqueue(host->repeat_workqueue);
dma_free_coherent(&pdev->dev,
sizeof(struct mt_gpdma_desc),
host->dma.gpd, host->dma.gpd_addr);
--
1.8.1.1.dirty
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/4] mmc: mediatek: Add online-tuning support of EMMC/SD
2015-08-12 8:24 ` [PATCH 1/4] mmc: mediatek: Add online-tuning support of EMMC/SD Chaotian Jing
@ 2015-08-17 11:31 ` Ulf Hansson
[not found] ` <CAPDyKFpX4Pp1+U9eNBuGd83sBeBgLU17qysAJ-2V-ABZZHYAGQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 10+ messages in thread
From: Ulf Hansson @ 2015-08-17 11:31 UTC (permalink / raw)
To: Chaotian Jing
Cc: Rob Herring, Matthias Brugger, Chris Ball, Mark Rutland,
James Liao, srv_heupstream, Arnd Bergmann,
devicetree@vger.kernel.org, Hongzhou Yang, Catalin Marinas,
linux-mmc, Will Deacon, linux-kernel@vger.kernel.org,
linux-gpio@vger.kernel.org, Sascha Hauer, Joe.C, Eddie Huang,
Bin Zhang (章斌),
linux-arm-kernel@lists.infradead.org
On 12 August 2015 at 10:24, Chaotian Jing <chaotian.jing@mediatek.com> wrote:
> Schedule a workqueue to do tuning when CRC error
> Call mmc_hw_reset to re-init card when data timeout
Thanks to Adrian Hunter, the mmc core already supports re-tuning for
the above scenarios through the mmc_retune_*() APIs.
SDHCI driver has already adopted to use that feature, you should do
that for the mtk-sd driver as well.
Kind regards
Uffe
>
> Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
> ---
> drivers/mmc/host/mtk-sd.c | 162 ++++++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 150 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
> index 7153500..eb44fe1 100644
> --- a/drivers/mmc/host/mtk-sd.c
> +++ b/drivers/mmc/host/mtk-sd.c
> @@ -27,6 +27,7 @@
> #include <linux/pm_runtime.h>
> #include <linux/regulator/consumer.h>
> #include <linux/spinlock.h>
> +#include <linux/workqueue.h>
>
> #include <linux/mmc/card.h>
> #include <linux/mmc/core.h>
> @@ -290,6 +291,10 @@ struct msdc_host {
> struct pinctrl_state *pins_default;
> struct pinctrl_state *pins_uhs;
> struct delayed_work req_timeout;
> + struct workqueue_struct *repeat_workqueue;
> + struct work_struct repeat_req;
> + struct mmc_request *repeat_mrq;
> + u32 tune_cmd_counter;
> int irq; /* host interrupt */
>
> struct clk *src_clk; /* msdc source clock */
> @@ -353,7 +358,10 @@ static void msdc_reset_hw(struct msdc_host *host)
> static void msdc_cmd_next(struct msdc_host *host,
> struct mmc_request *mrq, struct mmc_command *cmd);
>
> -static u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
> +static const u32 cmd_ints_mask = MSDC_INTEN_CMDRDY | MSDC_INTEN_RSPCRCERR |
> + MSDC_INTEN_CMDTMO | MSDC_INTEN_ACMDRDY |
> + MSDC_INTEN_ACMDCRCERR | MSDC_INTEN_ACMDTMO;
> +static const u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
> MSDC_INTEN_DATCRCERR | MSDC_INTEN_DMA_BDCSERR |
> MSDC_INTEN_DMA_GPDCSERR | MSDC_INTEN_DMA_PROTECT;
>
> @@ -690,6 +698,18 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
> msdc_track_cmd_data(host, mrq->cmd, mrq->data);
> if (mrq->data)
> msdc_unprepare_data(host, mrq);
> + if (host->error && host->mmc->card &&
> + !mmc_card_sdio(host->mmc->card)) {
> + if (mrq->cmd->error == (unsigned int)-EILSEQ ||
> + (mrq->stop && mrq->stop->error == (unsigned int)-EILSEQ) ||
> + (mrq->sbc && mrq->sbc->error == (unsigned int)-EILSEQ) ||
> + (mrq->data && mrq->data->error)) {
> + host->repeat_mrq = mrq;
> + queue_work(host->repeat_workqueue, &host->repeat_req);
> + return;
> + }
> + }
> + host->tune_cmd_counter = 0;
> mmc_request_done(host->mmc, mrq);
>
> pm_runtime_mark_last_busy(host->dev);
> @@ -725,11 +745,7 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
> if (done)
> return true;
>
> - sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
> - MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
> - MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
> - MSDC_INTEN_ACMDTMO);
> - writel(cmd->arg, host->base + SDC_ARG);
> + sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
>
> if (cmd->flags & MMC_RSP_PRESENT) {
> if (cmd->flags & MMC_RSP_136) {
> @@ -819,10 +835,7 @@ static void msdc_start_command(struct msdc_host *host,
> rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
> mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
>
> - sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
> - MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
> - MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
> - MSDC_INTEN_ACMDTMO);
> + sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
> writel(cmd->arg, host->base + SDC_ARG);
> writel(rawcmd, host->base + SDC_CMD);
> }
> @@ -942,6 +955,8 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
>
> if (events & MSDC_INT_DATTMO)
> data->error = -ETIMEDOUT;
> + else if (events & MSDC_INT_DATCRCERR)
> + data->error = -EILSEQ;
>
> dev_err(host->dev, "%s: cmd=%d; blocks=%d",
> __func__, mrq->cmd->opcode, data->blocks);
> @@ -1113,8 +1128,8 @@ static void msdc_init_hw(struct msdc_host *host)
>
> writel(0, host->base + MSDC_PAD_TUNE);
> writel(0, host->base + MSDC_IOCON);
> - sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
> - writel(0x403c004f, host->base + MSDC_PATCH_BIT);
> + sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
> + writel(0x403c0046, host->base + MSDC_PATCH_BIT);
> sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1);
> writel(0xffff0089, host->base + MSDC_PATCH_BIT1);
> /* Configure to enable SDIO mode.
> @@ -1176,6 +1191,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> switch (ios->power_mode) {
> case MMC_POWER_UP:
> if (!IS_ERR(mmc->supply.vmmc)) {
> + msdc_init_hw(host);
> ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
> ios->vdd);
> if (ret) {
> @@ -1214,6 +1230,120 @@ end:
> pm_runtime_put_autosuspend(host->dev);
> }
>
> +static void msdc_reset_mrq(struct mmc_request *mrq)
> +{
> + mrq->cmd->error = 0;
> + if (mrq->sbc)
> + mrq->sbc->error = 0;
> + if (mrq->data)
> + mrq->data->error = 0;
> + if (mrq->stop)
> + mrq->stop->error = 0;
> +}
> +
> +/* Send CMD12 when tuning, do not check CRC error and timeout */
> +static void msdc_send_stop(struct msdc_host *host)
> +{
> + u32 opcode = MMC_STOP_TRANSMISSION;
> + u32 arg = 0;
> + u32 rawcmd = 0;
> + u32 intsts = 0;
> +
> + /* Reset host first */
> + msdc_reset_hw(host);
> +
> + rawcmd = (opcode & 0x3f) | (7 << 7);
> + rawcmd |= (1 << 14); /* stop cmd */
> +
> + sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
> + writel(arg, host->base + SDC_ARG);
> + writel(rawcmd, host->base + SDC_CMD);
> +
> + while (1) {
> + intsts = readl(host->base + MSDC_INT);
> + if (intsts) {
> + writel(intsts, host->base + MSDC_INT);
> + if (intsts & cmd_ints_mask) {
> + dev_dbg(host->dev, "result of cmd12: %x\n",
> + intsts);
> + break;
> + }
> + }
> + udelay(1);
> + }
> +}
> +
> +/* When tuning, CMD13 may also get crc error, so use MSDC_PS to get card status */
> +static void msdc_wait_card_not_busy(struct msdc_host *host)
> +{
> + while (1) {
> + if ((readl(host->base + MSDC_PS) & BIT(16)) == 0) { /* check dat0 status */
> + msleep_interruptible(10);
> + dev_dbg(host->dev, "MSDC_PS: %08x, SDC_STS: %08x\n",
> + readl(host->base + MSDC_PS), readl(host->base + SDC_STS));
> + } else
> + break;
> + }
> +}
> +
> +static void msdc_tune_request(struct msdc_host *host)
> +{
> + u32 orig_rsmpl, orig_cksel;
> + u32 cur_rsmpl, cur_cksel = 0;
> + u32 ddr, clkmode;
> + struct mmc_ios ios = host->mmc->ios;
> +
> + sdr_get_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL, &orig_rsmpl);
> + sdr_get_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL,
> + &orig_cksel);
> + cur_rsmpl = (orig_rsmpl + 1);
> + sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL, cur_rsmpl % 2);
> +
> + if (ios.timing != MMC_TIMING_MMC_HS400) {
> + sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DSPL,
> + cur_rsmpl % 2);
> + sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL,
> + cur_rsmpl % 2);
> + }
> +
> + if (cur_rsmpl >= 2) {
> + cur_cksel = orig_cksel + 1;
> + sdr_set_field(host->base + MSDC_PATCH_BIT,
> + MSDC_CKGEN_MSDC_DLY_SEL, cur_cksel % 16);
> + }
> +
> + if (host->tune_cmd_counter++ >= 2 * 16) {
> + dev_warn(host->dev, "Tune fail at %dhz\n", host->mclk);
> + host->tune_cmd_counter = 0;
> + sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL, 0);
> + sdr_set_field(host->base + MSDC_PATCH_BIT,
> + MSDC_CKGEN_MSDC_DLY_SEL, 0);
> + sdr_get_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD, &clkmode);
> + ddr = (clkmode == 2) ? 1 : 0;
> + msdc_set_mclk(host, ddr, host->mclk / 2);
> + }
> +}
> +
> +static void msdc_repeat_request(struct work_struct *work)
> +{
> + struct msdc_host *host = container_of(work, struct msdc_host, repeat_req);
> + struct mmc_request *mrq;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&host->lock, flags);
> + mrq = host->repeat_mrq;
> + host->repeat_mrq = NULL;
> + spin_unlock_irqrestore(&host->lock, flags);
> + msdc_send_stop(host);
> + msdc_wait_card_not_busy(host);
> + if (mrq->data && mrq->data->error == -ETIMEDOUT)
> + mmc_hw_reset(host->mmc);
> + else
> + msdc_tune_request(host);
> + msdc_reset_mrq(mrq);
> + msdc_ops_request(host->mmc, mrq);
> +}
> +
> static struct mmc_host_ops mt_msdc_ops = {
> .post_req = msdc_post_req,
> .pre_req = msdc_pre_req,
> @@ -1324,6 +1454,12 @@ static int msdc_drv_probe(struct platform_device *pdev)
> }
> msdc_init_gpd_bd(host, &host->dma);
> INIT_DELAYED_WORK(&host->req_timeout, msdc_request_timeout);
> + host->repeat_workqueue = create_singlethread_workqueue("repeat_workqueue");
> + if (!host->repeat_workqueue) {
> + ret = -ENOMEM;
> + goto release_mem;
> + }
> + INIT_WORK(&host->repeat_req, msdc_repeat_request);
> spin_lock_init(&host->lock);
>
> platform_set_drvdata(pdev, mmc);
> @@ -1348,6 +1484,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
> end:
> pm_runtime_disable(host->dev);
> release:
> + destroy_workqueue(host->repeat_workqueue);
> platform_set_drvdata(pdev, NULL);
> msdc_deinit_hw(host);
> msdc_gate_clock(host);
> @@ -1383,6 +1520,7 @@ static int msdc_drv_remove(struct platform_device *pdev)
>
> pm_runtime_disable(host->dev);
> pm_runtime_put_noidle(host->dev);
> + destroy_workqueue(host->repeat_workqueue);
> dma_free_coherent(&pdev->dev,
> sizeof(struct mt_gpdma_desc),
> host->dma.gpd, host->dma.gpd_addr);
> --
> 1.8.1.1.dirty
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2/4] mmc: mediatek: Add HS400 support
[not found] ` <1439367845-5891-1-git-send-email-chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2015-08-12 8:24 ` [PATCH 1/4] mmc: mediatek: Add online-tuning support of EMMC/SD Chaotian Jing
@ 2015-08-12 8:24 ` Chaotian Jing
2015-08-12 8:24 ` [PATCH 3/4] arm64: dts: mediatek: Support SD/EMMC SDR104/HS200/HS400 Chaotian Jing
2015-08-12 8:24 ` [PATCH 4/4] mmc: dt-bindings: Add 400Mhz clock source Chaotian Jing
3 siblings, 0 replies; 10+ messages in thread
From: Chaotian Jing @ 2015-08-12 8:24 UTC (permalink / raw)
To: Rob Herring, Matthias Brugger, Chris Ball, Ulf Hansson
Cc: Mark Rutland, James Liao, Catalin Marinas, Wenbin Mei,
Will Deacon, Russell King - ARM Linux, Hongzhou Yang,
Chaotian Jing, Joe.C, devicetree-u79uwXL29TY76Z2rM5mHXA,
Arnd Bergmann, bin.zhang-NuS5LvNUpcJWk0Htik3J/w,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Eddie Huang,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Liuquan Ji,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Yong Mao, Sascha Hauer
Support HS400 mode in driver
Signed-off-by: Chaotian Jing <chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
drivers/mmc/host/mtk-sd.c | 108 ++++++++++++++++++++++++++++++++++++----------
1 file changed, 86 insertions(+), 22 deletions(-)
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index eb44fe1..457d919 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -72,6 +72,8 @@
#define MSDC_PATCH_BIT 0xb0
#define MSDC_PATCH_BIT1 0xb4
#define MSDC_PAD_TUNE 0xec
+#define PAD_DS_TUNE 0x188
+#define EMMC50_CFG0 0x208
/*--------------------------------------------------------------------------*/
/* Register Mask */
@@ -205,6 +207,14 @@
#define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */
#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */
+#define PAD_DS_TUNE_DLY1 (0x1f << 2)
+#define PAD_DS_TUNE_DLY2 (0x1f << 7)
+#define PAD_DS_TUNE_DLY3 (0x1f << 12)
+
+#define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0)
+#define EMMC50_CFG_CRCSTS_EDGE (0x1 << 3)
+#define EMMC50_CFG_CFCSTS_SEL (0x1 << 4)
+
#define REQ_CMD_EIO (0x1 << 0)
#define REQ_CMD_TMO (0x1 << 1)
#define REQ_DAT_ERR (0x1 << 2)
@@ -266,6 +276,8 @@ struct msdc_save_para {
u32 pad_tune;
u32 patch_bit0;
u32 patch_bit1;
+ u32 pad_ds_tune;
+ u32 emmc50_cfg0;
};
struct msdc_host {
@@ -295,14 +307,17 @@ struct msdc_host {
struct work_struct repeat_req;
struct mmc_request *repeat_mrq;
u32 tune_cmd_counter;
+ u32 tune_hs400_rw_counter;
int irq; /* host interrupt */
struct clk *src_clk; /* msdc source clock */
+ struct clk *src_clk_parent; /* src_clk's parent */
+ struct clk *hs400_src; /* 400Mhz source clock */
struct clk *h_clk; /* msdc h_clk */
u32 mclk; /* mmc subsystem clock frequency */
u32 src_clk_freq; /* source clock frequency */
u32 sclk; /* SD/MS bus clock frequency */
- bool ddr;
+ unsigned char timing;
bool vqmmc_enabled;
struct msdc_save_para save_para; /* used when gate HCLK */
};
@@ -493,7 +508,7 @@ static void msdc_ungate_clock(struct msdc_host *host)
cpu_relax();
}
-static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
+static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
{
u32 mode;
u32 flags;
@@ -509,8 +524,13 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
flags = readl(host->base + MSDC_INTEN);
sdr_clr_bits(host->base + MSDC_INTEN, flags);
- if (ddr) { /* may need to modify later */
- mode = 0x2; /* ddr mode and use divisor */
+ if (timing == MMC_TIMING_UHS_DDR50 ||
+ timing == MMC_TIMING_MMC_DDR52 ||
+ timing == MMC_TIMING_MMC_HS400) { /* may need to modify later */
+ if (timing == MMC_TIMING_MMC_HS400)
+ mode = 0x3;
+ else
+ mode = 0x2; /* ddr mode and use divisor */
if (hz >= (host->src_clk_freq >> 2)) {
div = 0; /* mean div = 1/4 */
sclk = host->src_clk_freq >> 2; /* sclk = clk / 4 */
@@ -540,12 +560,12 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
cpu_relax();
host->sclk = sclk;
host->mclk = hz;
- host->ddr = ddr;
+ host->timing = timing;
/* need because clk changed. */
msdc_set_timeout(host, host->timeout_ns, host->timeout_clks);
sdr_set_bits(host->base + MSDC_INTEN, flags);
- dev_dbg(host->dev, "sclk: %d, ddr: %d\n", host->sclk, ddr);
+ dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing);
}
static inline u32 msdc_cmd_find_resp(struct msdc_host *host,
@@ -710,6 +730,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
}
}
host->tune_cmd_counter = 0;
+ host->tune_hs400_rw_counter = 0;
mmc_request_done(host->mmc, mrq);
pm_runtime_mark_last_busy(host->dev);
@@ -1132,6 +1153,7 @@ static void msdc_init_hw(struct msdc_host *host)
writel(0x403c0046, host->base + MSDC_PATCH_BIT);
sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1);
writel(0xffff0089, host->base + MSDC_PATCH_BIT1);
+ sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
/* Configure to enable SDIO mode.
* it's must otherwise sdio cmd5 failed
*/
@@ -1163,11 +1185,14 @@ static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma)
struct mt_bdma_desc *bd = dma->bd;
int i;
- memset(gpd, 0, sizeof(struct mt_gpdma_desc));
+ memset(gpd, 0, sizeof(struct mt_gpdma_desc) * 2);
gpd->gpd_info = GPDMA_DESC_BDP; /* hwo, cs, bd pointer */
gpd->ptr = (u32)dma->bd_addr; /* physical address */
-
+ /* gpd->next is must set for desc DMA
+ * That's why must alloc 2 gpd structure.
+ */
+ gpd->next = (u32)dma->gpd_addr + sizeof(struct mt_gpdma_desc);
memset(bd, 0, sizeof(struct mt_bdma_desc) * MAX_BD_NUM);
for (i = 0; i < (MAX_BD_NUM - 1); i++)
bd[i].next = (u32)dma->bd_addr + sizeof(*bd) * (i + 1);
@@ -1177,14 +1202,9 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct msdc_host *host = mmc_priv(mmc);
int ret;
- u32 ddr = 0;
pm_runtime_get_sync(host->dev);
- if (ios->timing == MMC_TIMING_UHS_DDR50 ||
- ios->timing == MMC_TIMING_MMC_DDR52)
- ddr = 1;
-
msdc_set_buswidth(host, ios->bus_width);
/* Suspend/Resume will do power off/on */
@@ -1222,8 +1242,8 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break;
}
- if (host->mclk != ios->clock || host->ddr != ddr)
- msdc_set_mclk(host, ddr, ios->clock);
+ if (host->mclk != ios->clock || host->timing != ios->timing)
+ msdc_set_mclk(host, ios->timing, ios->clock);
end:
pm_runtime_mark_last_busy(host->dev);
@@ -1290,7 +1310,6 @@ static void msdc_tune_request(struct msdc_host *host)
{
u32 orig_rsmpl, orig_cksel;
u32 cur_rsmpl, cur_cksel = 0;
- u32 ddr, clkmode;
struct mmc_ios ios = host->mmc->ios;
sdr_get_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL, &orig_rsmpl);
@@ -1318,9 +1337,38 @@ static void msdc_tune_request(struct msdc_host *host)
sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL, 0);
sdr_set_field(host->base + MSDC_PATCH_BIT,
MSDC_CKGEN_MSDC_DLY_SEL, 0);
- sdr_get_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD, &clkmode);
- ddr = (clkmode == 2) ? 1 : 0;
- msdc_set_mclk(host, ddr, host->mclk / 2);
+ msdc_set_mclk(host, host->timing, host->mclk / 2);
+ }
+}
+
+static void emmc_hs400_tune_rw(struct msdc_host *host)
+{
+ int cur_ds_dly1, cur_ds_dly3, orig_ds_dly1, orig_ds_dly3;
+
+ sdr_get_field(host->base + PAD_DS_TUNE, PAD_DS_TUNE_DLY1, &orig_ds_dly1);
+ sdr_get_field(host->base + PAD_DS_TUNE, PAD_DS_TUNE_DLY3, &orig_ds_dly3);
+
+ cur_ds_dly1 = orig_ds_dly1 - 1;
+ cur_ds_dly3 = orig_ds_dly3;
+ if (cur_ds_dly1 < 0) {
+ cur_ds_dly1 = 31;
+ cur_ds_dly3 = orig_ds_dly3 + 1;
+ if (cur_ds_dly3 >= 32)
+ cur_ds_dly3 = 0;
+ }
+
+ if (++host->tune_hs400_rw_counter >= 32 * 32) {
+ dev_warn(host->dev, "HS400 tune fail at %dhz\n", host->mclk);
+ host->tune_hs400_rw_counter = 0;
+ msdc_set_mclk(host, host->timing, host->mclk / 2);
+ } else {
+ sdr_set_field(host->base + PAD_DS_TUNE, PAD_DS_TUNE_DLY1, cur_ds_dly1);
+ if (cur_ds_dly3 != orig_ds_dly3) {
+ sdr_set_field(host->base + PAD_DS_TUNE, PAD_DS_TUNE_DLY3,
+ cur_ds_dly3);
+ }
+ dev_dbg(host->dev, "cur_ds_dly1<0x%x>, cur_ds_dly3<0x%x>\n",
+ cur_ds_dly1, cur_ds_dly3);
}
}
@@ -1336,10 +1384,15 @@ static void msdc_repeat_request(struct work_struct *work)
spin_unlock_irqrestore(&host->lock, flags);
msdc_send_stop(host);
msdc_wait_card_not_busy(host);
- if (mrq->data && mrq->data->error == -ETIMEDOUT)
+ if (mrq->data && mrq->data->error == -ETIMEDOUT) {
mmc_hw_reset(host->mmc);
- else
- msdc_tune_request(host);
+ } else {
+ if (mrq->data && mrq->data->error == -EILSEQ &&
+ host->timing == MMC_TIMING_MMC_HS400)
+ emmc_hs400_tune_rw(host);
+ else
+ msdc_tune_request(host);
+ }
msdc_reset_mrq(mrq);
msdc_ops_request(host->mmc, mrq);
}
@@ -1389,6 +1442,13 @@ static int msdc_drv_probe(struct platform_device *pdev)
if (IS_ERR(host->src_clk)) {
ret = PTR_ERR(host->src_clk);
goto host_free;
+ } else {
+ host->src_clk_parent = clk_get_parent(host->src_clk);
+ host->hs400_src = devm_clk_get(&pdev->dev, "400Mhz_clk");
+ if (IS_ERR(host->hs400_src))
+ dev_dbg(&pdev->dev, "Cannot find 400Mhz_clk at dts!\n");
+ else if (clk_set_parent(host->src_clk_parent, host->hs400_src) < 0)
+ dev_err(host->dev, "Failed to set 400Mhz source clock!\n");
}
host->h_clk = devm_clk_get(&pdev->dev, "hclk");
@@ -1541,6 +1601,8 @@ static void msdc_save_reg(struct msdc_host *host)
host->save_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT);
host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1);
+ host->save_para.pad_ds_tune = readl(host->base + PAD_DS_TUNE);
+ host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0);
}
static void msdc_restore_reg(struct msdc_host *host)
@@ -1551,6 +1613,8 @@ static void msdc_restore_reg(struct msdc_host *host)
writel(host->save_para.pad_tune, host->base + MSDC_PAD_TUNE);
writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT);
writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1);
+ writel(host->save_para.pad_ds_tune, host->base + PAD_DS_TUNE);
+ writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0);
}
static int msdc_runtime_suspend(struct device *dev)
--
1.8.1.1.dirty
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/4] arm64: dts: mediatek: Support SD/EMMC SDR104/HS200/HS400
[not found] ` <1439367845-5891-1-git-send-email-chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2015-08-12 8:24 ` [PATCH 1/4] mmc: mediatek: Add online-tuning support of EMMC/SD Chaotian Jing
2015-08-12 8:24 ` [PATCH 2/4] mmc: mediatek: Add HS400 support Chaotian Jing
@ 2015-08-12 8:24 ` Chaotian Jing
2015-08-12 8:24 ` [PATCH 4/4] mmc: dt-bindings: Add 400Mhz clock source Chaotian Jing
3 siblings, 0 replies; 10+ messages in thread
From: Chaotian Jing @ 2015-08-12 8:24 UTC (permalink / raw)
To: Rob Herring, Matthias Brugger, Chris Ball, Ulf Hansson
Cc: Mark Rutland, James Liao, Catalin Marinas, Wenbin Mei,
Will Deacon, Russell King - ARM Linux, Hongzhou Yang,
Chaotian Jing, Joe.C, devicetree-u79uwXL29TY76Z2rM5mHXA,
Arnd Bergmann, bin.zhang-NuS5LvNUpcJWk0Htik3J/w,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Eddie Huang,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Liuquan Ji,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Yong Mao, Sascha Hauer
Add 400Mhz source clock for EMMC HS400 mode
Support EMMC DDR50/HS200/HS400 of mt8173-evb
Support SD SDR25/SDR50/DDR50/SDR104 of mt8173-evb
Signed-off-by: Chaotian Jing <chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 10 ++++++++--
arch/arm64/boot/dts/mediatek/mt8173.dtsi | 5 +++--
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 4be66ca..cd5317f 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -70,8 +70,11 @@
pinctrl-0 = <&mmc0_pins_default>;
pinctrl-1 = <&mmc0_pins_uhs>;
bus-width = <8>;
- max-frequency = <50000000>;
+ max-frequency = <200000000>;
cap-mmc-highspeed;
+ mmc-ddr-1_8v;
+ mmc-hs200-1_8v;
+ mmc-hs400-1_8v;
vmmc-supply = <&mt6397_vemc_3v3_reg>;
vqmmc-supply = <&mt6397_vio18_reg>;
non-removable;
@@ -83,9 +86,12 @@
pinctrl-0 = <&mmc1_pins_default>;
pinctrl-1 = <&mmc1_pins_uhs>;
bus-width = <4>;
- max-frequency = <50000000>;
+ max-frequency = <200000000>;
cap-sd-highspeed;
sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-ddr50;
+ sd-uhs-sdr104;
cd-gpios = <&pio 132 0>;
vmmc-supply = <&mt6397_vmch_reg>;
vqmmc-supply = <&mt6397_vmc_reg>;
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index d18ee42..495ed94 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -450,8 +450,9 @@
reg = <0 0x11230000 0 0x1000>;
interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_MSDC30_0>,
- <&topckgen CLK_TOP_MSDC50_0_H_SEL>;
- clock-names = "source", "hclk";
+ <&topckgen CLK_TOP_MSDC50_0_H_SEL>,
+ <&topckgen CLK_TOP_MSDCPLL_D2>;
+ clock-names = "source", "hclk", "400Mhz_clk";
status = "disabled";
};
--
1.8.1.1.dirty
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/4] mmc: dt-bindings: Add 400Mhz clock source
[not found] ` <1439367845-5891-1-git-send-email-chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
` (2 preceding siblings ...)
2015-08-12 8:24 ` [PATCH 3/4] arm64: dts: mediatek: Support SD/EMMC SDR104/HS200/HS400 Chaotian Jing
@ 2015-08-12 8:24 ` Chaotian Jing
3 siblings, 0 replies; 10+ messages in thread
From: Chaotian Jing @ 2015-08-12 8:24 UTC (permalink / raw)
To: Rob Herring, Matthias Brugger, Chris Ball, Ulf Hansson
Cc: Mark Rutland, James Liao, Catalin Marinas, Wenbin Mei,
Will Deacon, Russell King - ARM Linux, Hongzhou Yang,
Chaotian Jing, Joe.C, devicetree-u79uwXL29TY76Z2rM5mHXA,
Arnd Bergmann, bin.zhang-NuS5LvNUpcJWk0Htik3J/w,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Eddie Huang,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Liuquan Ji,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Yong Mao, Sascha Hauer
Add 400Mhz clock source for HS400 mode
Signed-off-by: Chaotian Jing <chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
Documentation/devicetree/bindings/mmc/mtk-sd.txt | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.txt b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
index a1adfa4..2c28305 100644
--- a/Documentation/devicetree/bindings/mmc/mtk-sd.txt
+++ b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
@@ -17,6 +17,10 @@ Required properties:
- vmmc-supply: power to the Core
- vqmmc-supply: power to the IO
+Optional properties:
+- clocks: 400Mhz clk, used for HS400 mode, 400Mhz source clock
+- clock-name: "400Mhz_clk"
+
Examples:
mmc0: mmc@11230000 {
compatible = "mediatek,mt8173-mmc", "mediatek,mt8135-mmc";
@@ -24,8 +28,10 @@ mmc0: mmc@11230000 {
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
vmmc-supply = <&mt6397_vemc_3v3_reg>;
vqmmc-supply = <&mt6397_vio18_reg>;
- clocks = <&pericfg CLK_PERI_MSDC30_0>, <&topckgen CLK_TOP_MSDC50_0_H_SEL>;
- clock-names = "source", "hclk";
+ clocks = <&pericfg CLK_PERI_MSDC30_0>,
+ <&topckgen CLK_TOP_MSDC50_0_H_SEL>,
+ <&topckgen CLK_TOP_MSDCPLL_D2>;
+ clock-names = "source", "hclk", "400Mhz_clk";
pinctrl-names = "default", "state_uhs";
pinctrl-0 = <&mmc0_pins_default>;
pinctrl-1 = <&mmc0_pins_uhs>;
--
1.8.1.1.dirty
^ permalink raw reply related [flat|nested] 10+ messages in thread