clock-frequency = <50000000>;
};
+ mmc_clock: mmc_clock@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <48000000>;
+ };
+
+ mmc_fixed_3v3: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "mmc_power";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ mmc_fixed_1v8_io: fixedregulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "mmc_io";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
palmbus: palmbus@1E000000 {
compatible = "palmbus";
reg = <0x1E000000 0x100000>;
sdhci: sdhci@1E130000 {
status = "disabled";
- compatible = "ralink,mt7620-sdhci";
+ compatible = "mediatek,mt7620-mmc";
reg = <0x1E130000 0x4000>;
- interrupt-parent = <&gic>;
- interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>;
+ bus-width = <4>;
+ max-frequency = <48000000>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ vmmc-supply = <&mmc_fixed_3v3>;
+ vqmmc-supply = <&mmc_fixed_1v8_io>;
+ disable-wp;
- pinctrl-names = "default";
+ pinctrl-names = "default", "state_uhs";
pinctrl-0 = <&sdhci_pins>;
+ pinctrl-1 = <&sdhci_pins>;
+
+ clocks = <&mmc_clock &mmc_clock>;
+ clock-names = "source", "hclk";
+
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>;
};
xhci: xhci@1E1C0000 {
--- /dev/null
+From afb7c7910bf3c42b56f99c9d6bb82099d0a0794d Mon Sep 17 00:00:00 2001
+From: NeilBrown <neil@brown.name>
+Date: Sat, 4 May 2019 20:24:56 +1000
+Subject: mmc: mtk-sd: add support for config found in mt7620 family SOCs.
+
+mt7620 family MIPS SOCs contain the mtk-sd silicon.
+Add support for this.
+
+Signed-off-by: NeilBrown <neil@brown.name>
+Reviewed-by: Chaotian Jing <chaotian.jing@mediatek.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/mtk-sd.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+(limited to 'drivers/mmc/host/mtk-sd.c')
+
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -465,12 +465,24 @@ static const struct mtk_mmc_compatible m
+ .support_64g = false,
+ };
+
++static const struct mtk_mmc_compatible mt7620_compat = {
++ .clk_div_bits = 8,
++ .hs400_tune = false,
++ .pad_tune_reg = MSDC_PAD_TUNE,
++ .async_fifo = false,
++ .data_tune = false,
++ .busy_check = false,
++ .stop_clk_fix = false,
++ .enhance_rx = false,
++};
++
+ static const struct of_device_id msdc_of_ids[] = {
+ { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
+ { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
+ { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},
+ { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},
+ { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
++ { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
+ {}
+ };
+ MODULE_DEVICE_TABLE(of, msdc_of_ids);
--- /dev/null
+From 42edb0d5ac3ee1ac247e3f56be4263f14ed99f11 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neil@brown.name>
+Date: Sat, 4 May 2019 20:24:56 +1000
+Subject: mmc: mtk-sd: don't hard-code interrupt trigger type
+
+When using devicetree for configuration, interrupt trigger type
+should be described in the dts file, not hard-coded in the C code.
+
+The mtk-sd silicon in the mt7621 soc uses an active-high interrupt
+and so cannot be used with the current code.
+
+So replace IRQF_TRIGGER_LOW with IRQF_TRIGGER_NONE.
+
+Also IRQF_ONESHOT is not needed - it is used for threaded interrupt
+handlers, and this driver does not used a threaded interrupt handler.
+So remove that setting.
+
+Signed-off-by: NeilBrown <neil@brown.name>
+Reviewed-by: Chaotian Jing <chaotian.jing@mediatek.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/mtk-sd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+(limited to 'drivers/mmc/host/mtk-sd.c')
+
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -1990,7 +1990,7 @@ static int msdc_drv_probe(struct platfor
+ msdc_init_hw(host);
+
+ ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,
+- IRQF_TRIGGER_LOW | IRQF_ONESHOT, pdev->name, host);
++ IRQF_TRIGGER_NONE, pdev->name, host);
+ if (ret)
+ goto release;
+
--- /dev/null
+From d087bde516053bd8dab4f79665586200b6a98c77 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neil@brown.name>
+Date: Sat, 4 May 2019 20:24:57 +1000
+Subject: mmc: mtk-sd: enable internal card-detect logic.
+
+The mtk-sd silicon has integrated card-detect logic that is
+enabled on the MT7621. The circuit is phased out on newer hardware so
+we should be careful to only enabled it on hardware known to support
+it. This a new "use_internal_cd" flag in struct mtk_mmc_compatible.
+
+If the sdhci isn't marked non-removable and doesn't have a
+cd-gpio configured, and if use_internal_cd is set, then assume the
+internal cd logic should be used as recommended by
+ Documentation/devicetree/bindings/mmc/mmc.txt
+
+Signed-off-by: NeilBrown <neil@brown.name>
+Reviewed-by: Chaotian Jing <chaotian.jing@mediatek.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/mtk-sd.c | 64 ++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 60 insertions(+), 4 deletions(-)
+
+(limited to 'drivers/mmc/host/mtk-sd.c')
+
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -276,6 +276,8 @@
+ #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */
+ #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */
+
++#define DEFAULT_DEBOUNCE (8) /* 8 cycles CD debounce */
++
+ #define PAD_DELAY_MAX 32 /* PAD delay cells */
+ /*--------------------------------------------------------------------------*/
+ /* Descriptor Structure */
+@@ -345,6 +347,7 @@ struct mtk_mmc_compatible {
+ bool stop_clk_fix;
+ bool enhance_rx;
+ bool support_64g;
++ bool use_internal_cd;
+ };
+
+ struct msdc_tune_para {
+@@ -400,6 +403,7 @@ struct msdc_host {
+ bool hs400_cmd_resp_sel_rising;
+ /* cmd response sample selection for HS400 */
+ bool hs400_mode; /* current eMMC will run at hs400 mode */
++ bool internal_cd; /* Use internal card-detect logic */
+ struct msdc_save_para save_para; /* used when gate HCLK */
+ struct msdc_tune_para def_tune_para; /* default tune setting */
+ struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
+@@ -474,6 +478,7 @@ static const struct mtk_mmc_compatible m
+ .busy_check = false,
+ .stop_clk_fix = false,
+ .enhance_rx = false,
++ .use_internal_cd = true,
+ };
+
+ static const struct of_device_id msdc_of_ids[] = {
+@@ -1322,6 +1327,12 @@ static irqreturn_t msdc_irq(int irq, voi
+ data = host->data;
+ spin_unlock_irqrestore(&host->lock, flags);
+
++ if ((events & event_mask) & MSDC_INT_CDSC) {
++ if (host->internal_cd)
++ mmc_detect_change(host->mmc, msecs_to_jiffies(20));
++ events &= ~MSDC_INT_CDSC;
++ }
++
+ if (!(events & event_mask))
+ break;
+
+@@ -1355,14 +1366,24 @@ static void msdc_init_hw(struct msdc_hos
+ /* Reset */
+ msdc_reset_hw(host);
+
+- /* Disable card detection */
+- sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
+-
+ /* Disable and clear all interrupts */
+ writel(0, host->base + MSDC_INTEN);
+ val = readl(host->base + MSDC_INT);
+ writel(val, host->base + MSDC_INT);
+
++ /* Configure card detection */
++ if (host->internal_cd) {
++ sdr_set_field(host->base + MSDC_PS, MSDC_PS_CDDEBOUNCE,
++ DEFAULT_DEBOUNCE);
++ sdr_set_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
++ sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC);
++ sdr_set_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP);
++ } else {
++ sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP);
++ sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
++ sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC);
++ }
++
+ writel(0, host->base + tune_reg);
+ writel(0, host->base + MSDC_IOCON);
+ sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
+@@ -1434,6 +1455,13 @@ static void msdc_init_hw(struct msdc_hos
+ static void msdc_deinit_hw(struct msdc_host *host)
+ {
+ u32 val;
++
++ if (host->internal_cd) {
++ /* Disabled card-detect */
++ sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
++ sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP);
++ }
++
+ /* Disable and clear all interrupts */
+ writel(0, host->base + MSDC_INTEN);
+
+@@ -1831,13 +1859,31 @@ static void msdc_hw_reset(struct mmc_hos
+ sdr_clr_bits(host->base + EMMC_IOCON, 1);
+ }
+
++static int msdc_get_cd(struct mmc_host *mmc)
++{
++ struct msdc_host *host = mmc_priv(mmc);
++ int val;
++
++ if (mmc->caps & MMC_CAP_NONREMOVABLE)
++ return 1;
++
++ if (!host->internal_cd)
++ return mmc_gpio_get_cd(mmc);
++
++ val = readl(host->base + MSDC_PS) & MSDC_PS_CDSTS;
++ if (mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH)
++ return !!val;
++ else
++ return !val;
++}
++
+ static const struct mmc_host_ops mt_msdc_ops = {
+ .post_req = msdc_post_req,
+ .pre_req = msdc_pre_req,
+ .request = msdc_ops_request,
+ .set_ios = msdc_ops_set_ios,
+ .get_ro = mmc_gpio_get_ro,
+- .get_cd = mmc_gpio_get_cd,
++ .get_cd = msdc_get_cd,
+ .start_signal_voltage_switch = msdc_ops_switch_volt,
+ .card_busy = msdc_card_busy,
+ .execute_tuning = msdc_execute_tuning,
+@@ -1957,6 +2003,16 @@ static int msdc_drv_probe(struct platfor
+ else
+ mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095);
+
++ if (!(mmc->caps & MMC_CAP_NONREMOVABLE) &&
++ !mmc_can_gpio_cd(mmc) &&
++ host->dev_comp->use_internal_cd) {
++ /*
++ * Is removable but no GPIO declared, so
++ * use internal functionality.
++ */
++ host->internal_cd = true;
++ }
++
+ mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
+ /* MMC core transfer sizes tunable parameters */
+ mmc->max_segs = MAX_BD_NUM;