summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml2
-rw-r--r--Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml1
-rw-r--r--Documentation/devicetree/bindings/mmc/mtk-sd.txt75
-rw-r--r--Documentation/devicetree/bindings/mmc/mtk-sd.yaml176
-rw-r--r--Documentation/devicetree/bindings/mmc/owl-mmc.yaml4
-rw-r--r--drivers/memstick/core/memstick.c1
-rw-r--r--drivers/memstick/core/mspro_block.c2
-rw-r--r--drivers/memstick/host/jmb38x_ms.c2
-rw-r--r--drivers/memstick/host/r592.c12
-rw-r--r--drivers/memstick/host/tifm_ms.c2
-rw-r--r--drivers/misc/cardreader/rts5261.c61
-rw-r--r--drivers/misc/cardreader/rts5261.h39
-rw-r--r--drivers/misc/cardreader/rtsx_pcr.c5
-rw-r--r--drivers/mmc/core/core.c15
-rw-r--r--drivers/mmc/core/host.h6
-rw-r--r--drivers/mmc/core/sd_ops.c49
-rw-r--r--drivers/mmc/core/sd_ops.h1
-rw-r--r--drivers/mmc/host/Kconfig7
-rw-r--r--drivers/mmc/host/davinci_mmc.c2
-rw-r--r--drivers/mmc/host/dw_mmc.c17
-rw-r--r--drivers/mmc/host/meson-gx-mmc.c2
-rw-r--r--drivers/mmc/host/meson-mx-sdio.c5
-rw-r--r--drivers/mmc/host/moxart-mmc.c5
-rw-r--r--drivers/mmc/host/mtk-sd.c125
-rw-r--r--drivers/mmc/host/mxcmmc.c33
-rw-r--r--drivers/mmc/host/mxs-mmc.c18
-rw-r--r--drivers/mmc/host/owl-mmc.c9
-rw-r--r--drivers/mmc/host/pxamci.c1
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c119
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c71
-rw-r--r--drivers/mmc/host/s3cmci.c2
-rw-r--r--drivers/mmc/host/sdhci-acpi.c38
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c91
-rw-r--r--drivers/mmc/host/sdhci-msm.c13
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c4
-rw-r--r--drivers/mmc/host/sdhci-pci-gli.c27
-rw-r--r--drivers/mmc/host/sdhci-pic32.c11
-rw-r--r--drivers/mmc/host/sdhci-sprd.c2
-rw-r--r--drivers/mmc/host/sdhci-st.c2
-rw-r--r--drivers/mmc/host/sdhci-tegra.c2
-rw-r--r--drivers/mmc/host/sdhci-xenon-phy.c40
-rw-r--r--drivers/mmc/host/sdhci-xenon.c91
-rw-r--r--drivers/mmc/host/sdhci-xenon.h12
-rw-r--r--drivers/mmc/host/sdhci.c8
-rw-r--r--drivers/mmc/host/sunxi-mmc.c3
-rw-r--r--drivers/mmc/host/tmio_mmc.c3
-rw-r--r--drivers/mmc/host/tmio_mmc.h6
-rw-r--r--drivers/mmc/host/tmio_mmc_core.c26
-rw-r--r--drivers/mmc/host/uniphier-sd.c1
-rw-r--r--include/linux/mfd/tmio.h7
-rw-r--r--include/linux/mmc/host.h7
-rw-r--r--include/linux/rtsx_pci.h30
52 files changed, 839 insertions, 454 deletions
diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
index 0753289fba84..37a5fe7b26dc 100644
--- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
@@ -147,7 +147,7 @@ properties:
xlnx,mio-bank:
$ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 2]
+ enum: [0, 1, 2]
default: 0
description:
The MIO bank number in which the command and data lines are configured.
diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml
index e71d13c2d109..802c9df23752 100644
--- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml
+++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml
@@ -39,6 +39,7 @@ properties:
- fsl,imx8mn-usdhc
- fsl,imx8mp-usdhc
- fsl,imx8mq-usdhc
+ - fsl,imx8qm-usdhc
- fsl,imx8qxp-usdhc
- const: fsl,imx7d-usdhc
diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.txt b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
deleted file mode 100644
index 26a8f320a156..000000000000
--- a/Documentation/devicetree/bindings/mmc/mtk-sd.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-* MTK MMC controller
-
-The MTK MSDC can act as a MMC controller
-to support MMC, SD, and SDIO types of memory cards.
-
-This file documents differences between the core properties in mmc.txt
-and the properties used by the msdc driver.
-
-Required properties:
-- compatible: value should be either of the following.
- "mediatek,mt8135-mmc": for mmc host ip compatible with mt8135
- "mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
- "mediatek,mt8183-mmc": for mmc host ip compatible with mt8183
- "mediatek,mt8516-mmc": for mmc host ip compatible with mt8516
- "mediatek,mt6779-mmc": for mmc host ip compatible with mt6779
- "mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
- "mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
- "mediatek,mt7622-mmc": for MT7622 SoC
- "mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC
- "mediatek,mt7620-mmc", for MT7621 SoC (and others)
-
-- reg: physical base address of the controller and length
-- interrupts: Should contain MSDC interrupt number
-- clocks: Should contain phandle for the clock feeding the MMC controller
-- clock-names: Should contain the following:
- "source" - source clock (required)
- "hclk" - HCLK which used for host (required)
- "source_cg" - independent source clock gate (required for MT2712)
- "bus_clk" - bus clock used for internal register access (required for MT2712 MSDC0/3)
-- pinctrl-names: should be "default", "state_uhs"
-- pinctrl-0: should contain default/high speed pin ctrl
-- pinctrl-1: should contain uhs mode pin ctrl
-- vmmc-supply: power to the Core
-- vqmmc-supply: power to the IO
-
-Optional properties:
-- assigned-clocks: PLL of the source clock
-- assigned-clock-parents: parent of source clock, used for HS400 mode to get 400Mhz source clock
-- hs400-ds-delay: HS400 DS delay setting
-- mediatek,hs200-cmd-int-delay: HS200 command internal delay setting.
- This field has total 32 stages.
- The value is an integer from 0 to 31.
-- mediatek,hs400-cmd-int-delay: HS400 command internal delay setting
- This field has total 32 stages.
- The value is an integer from 0 to 31.
-- mediatek,hs400-cmd-resp-sel-rising: HS400 command response sample selection
- If present,HS400 command responses are sampled on rising edges.
- If not present,HS400 command responses are sampled on falling edges.
-- mediatek,latch-ck: Some SoCs do not support enhance_rx, need set correct latch-ck to avoid data crc
- error caused by stop clock(fifo full)
- Valid range = [0:0x7]. if not present, default value is 0.
- applied to compatible "mediatek,mt2701-mmc".
-- resets: Phandle and reset specifier pair to softreset line of MSDC IP.
-- reset-names: Should be "hrst".
-
-Examples:
-mmc0: mmc@11230000 {
- compatible = "mediatek,mt8173-mmc", "mediatek,mt8135-mmc";
- reg = <0 0x11230000 0 0x108>;
- 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";
- pinctrl-names = "default", "state_uhs";
- pinctrl-0 = <&mmc0_pins_default>;
- pinctrl-1 = <&mmc0_pins_uhs>;
- assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
- assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
- hs400-ds-delay = <0x14015>;
- mediatek,hs200-cmd-int-delay = <26>;
- mediatek,hs400-cmd-int-delay = <14>;
- mediatek,hs400-cmd-resp-sel-rising;
-};
diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml
new file mode 100644
index 000000000000..01630b0ecea7
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml
@@ -0,0 +1,176 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mmc/mtk-sd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MTK MSDC Storage Host Controller Binding
+
+maintainers:
+ - Chaotian Jing <chaotian.jing@mediatek.com>
+ - Wenbin Mei <wenbin.mei@mediatek.com>
+
+allOf:
+ - $ref: mmc-controller.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - mediatek,mt2701-mmc
+ - mediatek,mt2712-mmc
+ - mediatek,mt6779-mmc
+ - mediatek,mt7620-mmc
+ - mediatek,mt7622-mmc
+ - mediatek,mt8135-mmc
+ - mediatek,mt8173-mmc
+ - mediatek,mt8183-mmc
+ - mediatek,mt8516-mmc
+ - items:
+ - const: mediatek,mt7623-mmc
+ - const: mediatek,mt2701-mmc
+ - items:
+ - const: mediatek,mt8192-mmc
+ - const: mediatek,mt8183-mmc
+
+ clocks:
+ description:
+ Should contain phandle for the clock feeding the MMC controller.
+ minItems: 2
+ maxItems: 8
+ items:
+ - description: source clock (required).
+ - description: HCLK which used for host (required).
+ - description: independent source clock gate (required for MT2712).
+ - description: bus clock used for internal register access (required for MT2712 MSDC0/3).
+ - description: msdc subsys clock gate (required for MT8192).
+ - description: peripheral bus clock gate (required for MT8192).
+ - description: AXI bus clock gate (required for MT8192).
+ - description: AHB bus clock gate (required for MT8192).
+
+ clock-names:
+ minItems: 2
+ maxItems: 8
+ items:
+ - const: source
+ - const: hclk
+ - const: source_cg
+ - const: bus_clk
+ - const: sys_cg
+ - const: pclk_cg
+ - const: axi_cg
+ - const: ahb_cg
+
+ pinctrl-names:
+ items:
+ - const: default
+ - const: state_uhs
+
+ pinctrl-0:
+ description:
+ should contain default/high speed pin ctrl.
+ maxItems: 1
+
+ pinctrl-1:
+ description:
+ should contain uhs mode pin ctrl.
+ maxItems: 1
+
+ assigned-clocks:
+ description:
+ PLL of the source clock.
+ maxItems: 1
+
+ assigned-clock-parents:
+ description:
+ parent of source clock, used for HS400 mode to get 400Mhz source clock.
+ maxItems: 1
+
+ hs400-ds-delay:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ HS400 DS delay setting.
+ minimum: 0
+ maximum: 0xffffffff
+
+ mediatek,hs200-cmd-int-delay:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ HS200 command internal delay setting.
+ This field has total 32 stages.
+ The value is an integer from 0 to 31.
+ minimum: 0
+ maximum: 31
+
+ mediatek,hs400-cmd-int-delay:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ HS400 command internal delay setting.
+ This field has total 32 stages.
+ The value is an integer from 0 to 31.
+ minimum: 0
+ maximum: 31
+
+ mediatek,hs400-cmd-resp-sel-rising:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ HS400 command response sample selection.
+ If present, HS400 command responses are sampled on rising edges.
+ If not present, HS400 command responses are sampled on falling edges.
+
+ mediatek,latch-ck:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Some SoCs do not support enhance_rx, need set correct latch-ck to avoid
+ data crc error caused by stop clock(fifo full) Valid range = [0:0x7].
+ if not present, default value is 0.
+ applied to compatible "mediatek,mt2701-mmc".
+ minimum: 0
+ maximum: 7
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ const: hrst
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - pinctrl-names
+ - pinctrl-0
+ - pinctrl-1
+ - vmmc-supply
+ - vqmmc-supply
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mt8173-clk.h>
+ mmc0: mmc@11230000 {
+ compatible = "mediatek,mt8173-mmc";
+ reg = <0x11230000 0x1000>;
+ 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";
+ pinctrl-names = "default", "state_uhs";
+ pinctrl-0 = <&mmc0_pins_default>;
+ pinctrl-1 = <&mmc0_pins_uhs>;
+ assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
+ hs400-ds-delay = <0x14015>;
+ mediatek,hs200-cmd-int-delay = <26>;
+ mediatek,hs400-cmd-int-delay = <14>;
+ mediatek,hs400-cmd-resp-sel-rising;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/mmc/owl-mmc.yaml b/Documentation/devicetree/bindings/mmc/owl-mmc.yaml
index b6ab527087d5..b0d81ebe0f6e 100644
--- a/Documentation/devicetree/bindings/mmc/owl-mmc.yaml
+++ b/Documentation/devicetree/bindings/mmc/owl-mmc.yaml
@@ -17,7 +17,9 @@ properties:
oneOf:
- const: actions,owl-mmc
- items:
- - const: actions,s700-mmc
+ - enum:
+ - actions,s500-mmc
+ - actions,s700-mmc
- const: actions,owl-mmc
reg:
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index ef03d6fafc5c..12bc3f5a6cbb 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -468,7 +468,6 @@ static void memstick_check(struct work_struct *work)
host->card = card;
if (device_register(&card->dev)) {
put_device(&card->dev);
- kfree(host->card);
host->card = NULL;
}
} else
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index cd6b8d4f2335..afb892e7ffc6 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -276,7 +276,7 @@ static const char *mspro_block_attr_name(unsigned char tag)
return "attr_devinfo";
default:
return NULL;
- };
+ }
}
typedef ssize_t (*sysfs_show_t)(struct device *dev,
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index e83c3ada9389..f9a93b0565e1 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -748,7 +748,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
clock_delay);
host->ifmode = value;
break;
- };
+ }
return 0;
}
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c
index dd3a1f3dcc19..d2ef46337191 100644
--- a/drivers/memstick/host/r592.c
+++ b/drivers/memstick/host/r592.c
@@ -759,8 +759,10 @@ static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto error3;
dev->mmio = pci_ioremap_bar(pdev, 0);
- if (!dev->mmio)
+ if (!dev->mmio) {
+ error = -ENOMEM;
goto error4;
+ }
dev->irq = pdev->irq;
spin_lock_init(&dev->irq_lock);
@@ -786,12 +788,14 @@ static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id)
&dev->dummy_dma_page_physical_address, GFP_KERNEL);
r592_stop_dma(dev , 0);
- if (request_irq(dev->irq, &r592_irq, IRQF_SHARED,
- DRV_NAME, dev))
+ error = request_irq(dev->irq, &r592_irq, IRQF_SHARED,
+ DRV_NAME, dev);
+ if (error)
goto error6;
r592_update_card_detect(dev);
- if (memstick_add_host(host))
+ error = memstick_add_host(host);
+ if (error)
goto error7;
message("driver successfully loaded");
diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c
index 786e46798da2..57145374f6ac 100644
--- a/drivers/memstick/host/tifm_ms.c
+++ b/drivers/memstick/host/tifm_ms.c
@@ -528,7 +528,7 @@ static int tifm_ms_set_param(struct memstick_host *msh,
} else
return -EINVAL;
break;
- };
+ }
return 0;
}
diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c
index 471961487ff8..6c64dade8e1a 100644
--- a/drivers/misc/cardreader/rts5261.c
+++ b/drivers/misc/cardreader/rts5261.c
@@ -26,16 +26,16 @@ static u8 rts5261_get_ic_version(struct rtsx_pcr *pcr)
static void rts5261_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
{
u8 driving_3v3[4][3] = {
- {0x13, 0x13, 0x13},
{0x96, 0x96, 0x96},
- {0x7F, 0x7F, 0x7F},
{0x96, 0x96, 0x96},
+ {0x7F, 0x7F, 0x7F},
+ {0x13, 0x13, 0x13},
};
u8 driving_1v8[4][3] = {
- {0x99, 0x99, 0x99},
+ {0xB3, 0xB3, 0xB3},
{0x3A, 0x3A, 0x3A},
{0xE6, 0xE6, 0xE6},
- {0xB3, 0xB3, 0xB3},
+ {0x99, 0x99, 0x99},
};
u8 (*driving)[3], drive_sel;
@@ -67,12 +67,17 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
if (!rts5261_vendor_setting_valid(reg)) {
+ /* Not support MMC default */
+ pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
pcr_dbg(pcr, "skip fetch vendor setting\n");
return;
}
- pcr->card_drive_sel &= 0x3F;
- pcr->card_drive_sel |= rts5261_reg_to_card_drive_sel(reg);
+ if (!rts5261_reg_check_mmc_support(reg))
+ pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
+
+ /* TO do: need to add rtd3 function */
+ pcr->rtd3_en = rts5261_reg_to_rtd3(reg);
if (rts5261_reg_check_reverse_socket(reg))
pcr->flags |= PCR_REVERSE_SOCKET;
@@ -171,6 +176,8 @@ static int rts5261_card_power_on(struct rtsx_pcr *pcr, int card)
if (option->ocp_en)
rtsx_pci_enable_ocp(pcr);
+ rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
+ CFG_SD_POW_AUTO_PD, CFG_SD_POW_AUTO_PD);
rtsx_pci_write_register(pcr, RTS5261_LDO1_CFG1,
RTS5261_LDO1_TUNE_MASK, RTS5261_LDO1_33);
@@ -272,6 +279,9 @@ static void rts5261_enable_ocp(struct rtsx_pcr *pcr)
u8 val = 0;
val = SD_OCP_INT_EN | SD_DETECT_EN;
+ rtsx_pci_write_register(pcr, RTS5261_LDO1_CFG0,
+ RTS5261_LDO1_OCP_EN | RTS5261_LDO1_OCP_LMT_EN,
+ RTS5261_LDO1_OCP_EN | RTS5261_LDO1_OCP_LMT_EN);
rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val);
}
@@ -295,6 +305,8 @@ static int rts5261_card_power_off(struct rtsx_pcr *pcr, int card)
err = rtsx_pci_write_register(pcr, RTS5261_LDO1233318_POW_CTL,
RTS5261_LDO_POWERON_MASK, 0);
+ rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
+ CFG_SD_POW_AUTO_PD, 0);
if (pcr->option.ocp_en)
rtsx_pci_disable_ocp(pcr);
@@ -340,7 +352,7 @@ static void rts5261_clear_ocpstat(struct rtsx_pcr *pcr)
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
- udelay(10);
+ udelay(1000);
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
}
@@ -353,9 +365,9 @@ static void rts5261_process_ocp(struct rtsx_pcr *pcr)
rtsx_pci_get_ocpstat(pcr, &pcr->ocp_stat);
if (pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) {
+ rts5261_clear_ocpstat(pcr);
rts5261_card_power_off(pcr, RTSX_SD_CARD);
rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
- rts5261_clear_ocpstat(pcr);
pcr->ocp_stat = 0;
}
@@ -467,6 +479,7 @@ static void rts5261_init_from_cfg(struct rtsx_pcr *pcr)
static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &pcr->option;
+ u32 val;
rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG1,
CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
@@ -481,6 +494,10 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
AUX_CLK_ACTIVE_SEL_MASK, MAC_CKSW_DONE);
rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, 0);
+ if (is_version_higher_than(pcr, PID_5261, IC_VER_B)) {
+ val = rtsx_pci_readl(pcr, RTSX_DUM_REG);
+ rtsx_pci_writel(pcr, RTSX_DUM_REG, val | 0x1);
+ }
rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG4,
RTS5261_AUX_CLK_16M_EN, 0);
@@ -502,6 +519,11 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
/* Configure driving */
rts5261_fill_driving(pcr, OUTPUT_3V3);
+ if (pcr->flags & PCR_REVERSE_SOCKET)
+ rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x30);
+ else
+ rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
+
/*
* If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
* to drive low, and we forcibly request clock.
@@ -513,6 +535,7 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
rtsx_pci_write_register(pcr, PETXCFG,
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
+ rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00);
rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL,
FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
@@ -526,22 +549,30 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
static void rts5261_enable_aspm(struct rtsx_pcr *pcr, bool enable)
{
+ u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
+ u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
+
if (pcr->aspm_enabled == enable)
return;
+ val |= (pcr->aspm_en & 0x02);
+ rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPMC, pcr->aspm_en);
pcr->aspm_enabled = enable;
-
}
static void rts5261_disable_aspm(struct rtsx_pcr *pcr, bool enable)
{
+ u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
+ u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
+
if (pcr->aspm_enabled == enable)
return;
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPMC, 0);
+ rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
udelay(10);
pcr->aspm_enabled = enable;
@@ -618,7 +649,7 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
if (initial_mode) {
/* We use 250k(around) here, in initial stage */
- if (is_version(pcr, PID_5261, IC_VER_D)) {
+ if (is_version_higher_than(pcr, PID_5261, IC_VER_C)) {
clk_divider = SD_CLK_DIVIDE_256;
card_clock = 60000000;
} else {
@@ -669,7 +700,7 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
div++;
}
- n = (n / 2);
+ n = (n / 2) - 1;
pcr_dbg(pcr, "n = %d, div = %d\n", n, div);
ssc_depth = depth[ssc_depth];
@@ -738,15 +769,19 @@ void rts5261_init_params(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &pcr->option;
struct rtsx_hw_param *hw_param = &pcr->hw_param;
+ u8 val;
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+ rtsx_pci_read_register(pcr, RTS5261_FW_STATUS, &val);
+ if (!(val & RTS5261_EXPRESS_LINK_FAIL_MASK))
+ pcr->extra_caps |= EXTRA_CAPS_SD_EXPRESS;
pcr->num_slots = 1;
pcr->ops = &rts5261_pcr_ops;
pcr->flags = 0;
pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
- pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
- pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
+ pcr->sd30_drive_sel_1v8 = 0x00;
+ pcr->sd30_drive_sel_3v3 = 0x00;
pcr->aspm_en = ASPM_L1_EN;
pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 11);
pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
diff --git a/drivers/misc/cardreader/rts5261.h b/drivers/misc/cardreader/rts5261.h
index ebfdd236a553..2344c560a637 100644
--- a/drivers/misc/cardreader/rts5261.h
+++ b/drivers/misc/cardreader/rts5261.h
@@ -12,12 +12,13 @@
/*New add*/
#define rts5261_vendor_setting_valid(reg) ((reg) & 0x010000)
-#define rts5261_reg_to_aspm(reg) (((reg) >> 28) ^ 0x03)
+#define rts5261_reg_to_aspm(reg) \
+ (((~(reg) >> 28) & 0x02) | (((reg) >> 28) & 0x01))
#define rts5261_reg_check_reverse_socket(reg) ((reg) & 0x04)
-#define rts5261_reg_to_card_drive_sel(reg) ((((reg) >> 6) & 0x01) << 6)
-#define rts5261_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 22) ^ 0x03)
-#define rts5261_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 16) ^ 0x03)
-
+#define rts5261_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 22) & 0x03)
+#define rts5261_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 16) & 0x03)
+#define rts5261_reg_to_rtd3(reg) ((reg) & 0x08)
+#define rts5261_reg_check_mmc_support(reg) ((reg) & 0x10)
#define RTS5261_AUTOLOAD_CFG0 0xFF7B
#define RTS5261_AUTOLOAD_CFG1 0xFF7C
@@ -60,28 +61,6 @@
/* DMACTL 0xFE2C */
#define RTS5261_DMA_PACK_SIZE_MASK 0xF0
-/* FW config info register */
-#define RTS5261_FW_CFG_INFO0 0xFF50
-#define RTS5261_FW_EXPRESS_TEST_MASK (0x01<<0)
-#define RTS5261_FW_EA_MODE_MASK (0x01<<5)
-
-/* FW config register */
-#define RTS5261_FW_CFG0 0xFF54
-#define RTS5261_FW_ENTER_EXPRESS (0x01<<0)
-
-#define RTS5261_FW_CFG1 0xFF55
-#define RTS5261_SYS_CLK_SEL_MCU_CLK (0x01<<7)
-#define RTS5261_CRC_CLK_SEL_MCU_CLK (0x01<<6)
-#define RTS5261_FAKE_MCU_CLOCK_GATING (0x01<<5)
-/*MCU_bus_mode_sel: 0=real 8051 1=fake mcu*/
-#define RTS5261_MCU_BUS_SEL_MASK (0x01<<4)
-/*MCU_clock_sel:VerA 00=aux16M 01=aux400K 1x=REFCLK100M*/
-/*MCU_clock_sel:VerB 00=aux400K 01=aux16M 10=REFCLK100M*/
-#define RTS5261_MCU_CLOCK_SEL_MASK (0x03<<2)
-#define RTS5261_MCU_CLOCK_SEL_16M (0x01<<2)
-#define RTS5261_MCU_CLOCK_GATING (0x01<<1)
-#define RTS5261_DRIVER_ENABLE_FW (0x01<<0)
-
/* FW status register */
#define RTS5261_FW_STATUS 0xFF56
#define RTS5261_EXPRESS_LINK_FAIL_MASK (0x01<<7)
@@ -121,12 +100,6 @@
#define RTS5261_DV3318_19 (0x04<<4)
#define RTS5261_DV3318_33 (0x07<<4)
-#define RTS5261_LDO1_CFG0 0xFF72
-#define RTS5261_LDO1_OCP_THD_MASK (0x07<<5)
-#define RTS5261_LDO1_OCP_EN (0x01<<4)
-#define RTS5261_LDO1_OCP_LMT_THD_MASK (0x03<<2)
-#define RTS5261_LDO1_OCP_LMT_EN (0x01<<1)
-
/* CRD6603-433 190319 request changed */
#define RTS5261_LDO1_OCP_THD_740 (0x00<<5)
#define RTS5261_LDO1_OCP_THD_800 (0x01<<5)
diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 2700d1997750..2aa6648fa41f 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -1004,6 +1004,11 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
} else {
pcr->card_removed |= SD_EXIST;
pcr->card_inserted &= ~SD_EXIST;
+ if (PCI_PID(pcr) == PID_5261) {
+ rtsx_pci_write_register(pcr, RTS5261_FW_STATUS,
+ RTS5261_EXPRESS_LINK_FAIL_MASK, 0);
+ pcr->extra_caps |= EXTRA_CAPS_SD_EXPRESS;
+ }
}
pcr->dma_error_count = 0;
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d42037f0f10d..19f1ee57fb34 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2147,8 +2147,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
mmc_go_idle(host);
- if (!(host->caps2 & MMC_CAP2_NO_SD))
- mmc_send_if_cond(host, host->ocr_avail);
+ if (!(host->caps2 & MMC_CAP2_NO_SD)) {
+ if (mmc_send_if_cond_pcie(host, host->ocr_avail))
+ goto out;
+ if (mmc_card_sd_express(host))
+ return 0;
+ }
/* Order's important: probe SDIO, then SD, then MMC */
if (!(host->caps2 & MMC_CAP2_NO_SDIO))
@@ -2163,6 +2167,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
if (!mmc_attach_mmc(host))
return 0;
+out:
mmc_power_off(host);
return -EIO;
}
@@ -2290,6 +2295,12 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
+ /* If an SD express card is present, then leave it as is. */
+ if (mmc_card_sd_express(host)) {
+ mmc_release_host(host);
+ goto out;
+ }
+
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
unsigned int freq = freqs[i];
if (freq > host->f_max) {
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 5e3b9534ffb2..ba407617ed23 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -77,5 +77,11 @@ static inline bool mmc_card_hs400es(struct mmc_card *card)
return card->host->ios.enhanced_strobe;
}
+static inline bool mmc_card_sd_express(struct mmc_host *host)
+{
+ return host->ios.timing == MMC_TIMING_SD_EXP ||
+ host->ios.timing == MMC_TIMING_SD_EXP_1_2V;
+}
+
#endif
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 22bf528294b9..d61ff811218c 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -158,7 +158,8 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err;
}
-int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits,
+ u32 *resp)
{
struct mmc_command cmd = {};
int err;
@@ -171,7 +172,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
* SD 1.0 cards.
*/
cmd.opcode = SD_SEND_IF_COND;
- cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | pcie_bits << 8 | test_pattern;
cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, 0);
@@ -186,6 +187,50 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
if (result_pattern != test_pattern)
return -EIO;
+ if (resp)
+ *resp = cmd.resp[0];
+
+ return 0;
+}
+
+int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+{
+ return __mmc_send_if_cond(host, ocr, 0, NULL);
+}
+
+int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr)
+{
+ u32 resp = 0;
+ u8 pcie_bits = 0;
+ int ret;
+
+ if (host->caps2 & MMC_CAP2_SD_EXP) {
+ /* Probe card for SD express support via PCIe. */
+ pcie_bits = 0x10;
+ if (host->caps2 & MMC_CAP2_SD_EXP_1_2V)
+ /* Probe also for 1.2V support. */
+ pcie_bits = 0x30;
+ }
+
+ ret = __mmc_send_if_cond(host, ocr, pcie_bits, &resp);
+ if (ret)
+ return 0;
+
+ /* Continue with the SD express init, if the card supports it. */
+ resp &= 0x3000;
+ if (pcie_bits && resp) {
+ if (resp == 0x3000)
+ host->ios.timing = MMC_TIMING_SD_EXP_1_2V;
+ else
+ host->ios.timing = MMC_TIMING_SD_EXP;
+
+ /*
+ * According to the spec the clock shall also be gated, but
+ * let's leave this to the host driver for more flexibility.
+ */
+ return host->ops->init_sd_express(host, &host->ios);
+ }
+
return 0;
}
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index 2194cabfcfc5..3ba7b3cf4652 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -16,6 +16,7 @@ struct mmc_host;
int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
+int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr);
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
int mmc_app_send_scr(struct mmc_card *card);
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 31481c9fcc2e..596f32637315 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -631,8 +631,8 @@ config MMC_SPI
config MMC_S3C
tristate "Samsung S3C SD/MMC Card Interface support"
- depends on ARCH_S3C24XX
- depends on S3C24XX_DMAC
+ depends on ARCH_S3C24XX || COMPILE_TEST
+ depends on S3C24XX_DMAC || COMPILE_TEST
help
This selects a driver for the MCI interface found in
Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
@@ -664,7 +664,7 @@ config MMC_S3C_PIO
config MMC_S3C_DMA
bool "Use DMA transfers only"
help
- Use DMA to transfer data between memory and the hardare.
+ Use DMA to transfer data between memory and the hardware.
Currently, the DMA support in this driver seems to not be
working properly and needs to be debugged before this
@@ -1023,6 +1023,7 @@ config MMC_BCM2835
config MMC_MTK
tristate "MediaTek SD/MMC Card Interface support"
depends on HAS_DMA
+ depends on COMMON_CLK
select REGULATOR
select MMC_CQHCI
help
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 90cd179625fc..2a757c88f9d2 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -290,7 +290,7 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
default:
s = ", (R? response)";
break;
- }; s; }));
+ } s; }));
host->cmd = cmd;
switch (mmc_resp_type(cmd)) {
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 43c5795691fb..a5244435556b 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2617,7 +2617,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
struct dw_mci *host = dev_id;
u32 pending;
struct dw_mci_slot *slot = host->slot;
- unsigned long irqflags;
pending = mci_readl(host, MINTSTS); /* read-only mask reg */
@@ -2632,15 +2631,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
* Hold the lock; we know cmd11_timer can't be kicked
* off after the lock is released, so safe to delete.
*/
- spin_lock_irqsave(&host->irq_lock, irqflags);
+ spin_lock(&host->irq_lock);
dw_mci_cmd_interrupt(host, pending);
- spin_unlock_irqrestore(&host->irq_lock, irqflags);
+ spin_unlock(&host->irq_lock);
del_timer(&host->cmd11_timer);
}
if (pending & DW_MCI_CMD_ERROR_FLAGS) {
- spin_lock_irqsave(&host->irq_lock, irqflags);
+ spin_lock(&host->irq_lock);
del_timer(&host->cto_timer);
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
@@ -2648,7 +2647,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
smp_wmb(); /* drain writebuffer */
set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
- spin_unlock_irqrestore(&host->irq_lock, irqflags);
+ spin_unlock(&host->irq_lock);
}
if (pending & DW_MCI_DATA_ERROR_FLAGS) {
@@ -2661,7 +2660,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
if (pending & SDMMC_INT_DATA_OVER) {
- spin_lock_irqsave(&host->irq_lock, irqflags);
+ spin_lock(&host->irq_lock);
del_timer(&host->dto_timer);
@@ -2676,7 +2675,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
tasklet_schedule(&host->tasklet);
- spin_unlock_irqrestore(&host->irq_lock, irqflags);
+ spin_unlock(&host->irq_lock);
}
if (pending & SDMMC_INT_RXDR) {
@@ -2692,12 +2691,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
if (pending & SDMMC_INT_CMD_DONE) {
- spin_lock_irqsave(&host->irq_lock, irqflags);
+ spin_lock(&host->irq_lock);
mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
dw_mci_cmd_interrupt(host, pending);
- spin_unlock_irqrestore(&host->irq_lock, irqflags);
+ spin_unlock(&host->irq_lock);
}
if (pending & SDMMC_INT_CD) {
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index 4ec41579940a..13f6a2c0ed04 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -1265,7 +1265,7 @@ static struct platform_driver meson_mmc_driver = {
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(meson_mmc_of_match),
+ .of_match_table = meson_mmc_of_match,
},
};
diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c
index 1c5299cd0cbe..d4a48916bfb6 100644
--- a/drivers/mmc/host/meson-mx-sdio.c
+++ b/drivers/mmc/host/meson-mx-sdio.c
@@ -418,10 +418,9 @@ static irqreturn_t meson_mx_mmc_irq(int irq, void *data)
{
struct meson_mx_mmc_host *host = (void *) data;
u32 irqs, send;
- unsigned long irqflags;
irqreturn_t ret;
- spin_lock_irqsave(&host->irq_lock, irqflags);
+ spin_lock(&host->irq_lock);
irqs = readl(host->base + MESON_MX_SDIO_IRQS);
send = readl(host->base + MESON_MX_SDIO_SEND);
@@ -434,7 +433,7 @@ static irqreturn_t meson_mx_mmc_irq(int irq, void *data)
/* finally ACK all pending interrupts */
writel(irqs, host->base + MESON_MX_SDIO_IRQS);
- spin_unlock_irqrestore(&host->irq_lock, irqflags);
+ spin_unlock(&host->irq_lock);
return ret;
}
diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c
index f25079ba3bca..89bff4e8ec10 100644
--- a/drivers/mmc/host/moxart-mmc.c
+++ b/drivers/mmc/host/moxart-mmc.c
@@ -465,9 +465,8 @@ static irqreturn_t moxart_irq(int irq, void *devid)
{
struct moxart_host *host = (struct moxart_host *)devid;
u32 status;
- unsigned long flags;
- spin_lock_irqsave(&host->lock, flags);
+ spin_lock(&host->lock);
status = readl(host->base + REG_STATUS);
if (status & CARD_CHANGE) {
@@ -484,7 +483,7 @@ static irqreturn_t moxart_irq(int irq, void *devid)
if (status & (FIFO_ORUN | FIFO_URUN) && host->mrq)
moxart_transfer_pio(host);
- spin_unlock_irqrestore(&host->lock, flags);
+ spin_unlock(&host->lock);
return IRQ_HANDLED;
}
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 004fbfc23672..de09c6347524 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -35,6 +35,7 @@
#include "cqhci.h"
#define MAX_BD_NUM 1024
+#define MSDC_NR_CLOCKS 3
/*--------------------------------------------------------------------------*/
/* Common Definition */
@@ -77,9 +78,12 @@
#define MSDC_PAD_TUNE0 0xf0
#define PAD_DS_TUNE 0x188
#define PAD_CMD_TUNE 0x18c
+#define EMMC51_CFG0 0x204
#define EMMC50_CFG0 0x208
+#define EMMC50_CFG1 0x20c
#define EMMC50_CFG3 0x220
#define SDC_FIFO_CFG 0x228
+#define CQHCI_SETTING 0x7fc
/*--------------------------------------------------------------------------*/
/* Top Pad Register Offset */
@@ -260,15 +264,26 @@
#define PAD_CMD_TUNE_RX_DLY3 (0x1f << 1) /* RW */
+/* EMMC51_CFG0 mask */
+#define CMDQ_RDAT_CNT (0x3ff << 12) /* RW */
+
#define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0) /* RW */
#define EMMC50_CFG_CRCSTS_EDGE (0x1 << 3) /* RW */
#define EMMC50_CFG_CFCSTS_SEL (0x1 << 4) /* RW */
+#define EMMC50_CFG_CMD_RESP_SEL (0x1 << 9) /* RW */
+
+/* EMMC50_CFG1 mask */
+#define EMMC50_CFG1_DS_CFG (0x1 << 28) /* RW */
#define EMMC50_CFG3_OUTS_WR (0x1f << 0) /* RW */
#define SDC_FIFO_CFG_WRVALIDSEL (0x1 << 24) /* RW */
#define SDC_FIFO_CFG_RDVALIDSEL (0x1 << 25) /* RW */
+/* CQHCI_SETTING */
+#define CQHCI_RD_CMD_WND_SEL (0x1 << 14) /* RW */
+#define CQHCI_WR_CMD_WND_SEL (0x1 << 15) /* RW */
+
/* EMMC_TOP_CONTROL mask */
#define PAD_RXDLY_SEL (0x1 << 0) /* RW */
#define DELAY_EN (0x1 << 1) /* RW */
@@ -425,6 +440,8 @@ struct msdc_host {
struct clk *h_clk; /* msdc h_clk */
struct clk *bus_clk; /* bus clock which used to access register */
struct clk *src_clk_cg; /* msdc source clock control gate */
+ struct clk *sys_clk_cg; /* msdc subsys clock control gate */
+ struct clk_bulk_data bulk_clks[MSDC_NR_CLOCKS];
u32 mclk; /* mmc subsystem clock frequency */
u32 src_clk_freq; /* source clock frequency */
unsigned char timing;
@@ -785,6 +802,7 @@ static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks)
static void msdc_gate_clock(struct msdc_host *host)
{
+ clk_bulk_disable_unprepare(MSDC_NR_CLOCKS, host->bulk_clks);
clk_disable_unprepare(host->src_clk_cg);
clk_disable_unprepare(host->src_clk);
clk_disable_unprepare(host->bus_clk);
@@ -793,10 +811,18 @@ static void msdc_gate_clock(struct msdc_host *host)
static void msdc_ungate_clock(struct msdc_host *host)
{
+ int ret;
+
clk_prepare_enable(host->h_clk);
clk_prepare_enable(host->bus_clk);
clk_prepare_enable(host->src_clk);
clk_prepare_enable(host->src_clk_cg);
+ ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks);
+ if (ret) {
+ dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n");
+ return;
+ }
+
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
cpu_relax();
}
@@ -1537,13 +1563,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
struct mmc_host *mmc = mmc_from_priv(host);
while (true) {
- unsigned long flags;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
u32 events, event_mask;
- spin_lock_irqsave(&host->lock, flags);
+ spin_lock(&host->lock);
events = readl(host->base + MSDC_INT);
event_mask = readl(host->base + MSDC_INTEN);
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
@@ -1554,7 +1579,7 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
mrq = host->mrq;
cmd = host->cmd;
data = host->data;
- spin_unlock_irqrestore(&host->lock, flags);
+ spin_unlock(&host->lock);
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
sdio_signal_irq(mmc);
@@ -2266,6 +2291,31 @@ static int msdc_get_cd(struct mmc_host *mmc)
return !val;
}
+static void msdc_hs400_enhanced_strobe(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+
+ if (ios->enhanced_strobe) {
+ msdc_prepare_hs400_tuning(mmc, ios);
+ sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_PADCMD_LATCHCK, 1);
+ sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_CMD_RESP_SEL, 1);
+ sdr_set_field(host->base + EMMC50_CFG1, EMMC50_CFG1_DS_CFG, 1);
+
+ sdr_clr_bits(host->base + CQHCI_SETTING, CQHCI_RD_CMD_WND_SEL);
+ sdr_clr_bits(host->base + CQHCI_SETTING, CQHCI_WR_CMD_WND_SEL);
+ sdr_clr_bits(host->base + EMMC51_CFG0, CMDQ_RDAT_CNT);
+ } else {
+ sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_PADCMD_LATCHCK, 0);
+ sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_CMD_RESP_SEL, 0);
+ sdr_set_field(host->base + EMMC50_CFG1, EMMC50_CFG1_DS_CFG, 0);
+
+ sdr_set_bits(host->base + CQHCI_SETTING, CQHCI_RD_CMD_WND_SEL);
+ sdr_set_bits(host->base + CQHCI_SETTING, CQHCI_WR_CMD_WND_SEL);
+ sdr_set_field(host->base + EMMC51_CFG0, CMDQ_RDAT_CNT, 0xb4);
+ }
+}
+
static void msdc_cqe_enable(struct mmc_host *mmc)
{
struct msdc_host *host = mmc_priv(mmc);
@@ -2323,6 +2373,7 @@ static const struct mmc_host_ops mt_msdc_ops = {
.set_ios = msdc_ops_set_ios,
.get_ro = mmc_gpio_get_ro,
.get_cd = msdc_get_cd,
+ .hs400_enhanced_strobe = msdc_hs400_enhanced_strobe,
.enable_sdio_irq = msdc_enable_sdio_irq,
.ack_sdio_irq = msdc_ack_sdio_irq,
.start_signal_voltage_switch = msdc_ops_switch_volt,
@@ -2367,6 +2418,48 @@ static void msdc_of_property_parse(struct platform_device *pdev,
host->cqhci = false;
}
+static int msdc_of_clock_parse(struct platform_device *pdev,
+ struct msdc_host *host)
+{
+ int ret;
+
+ host->src_clk = devm_clk_get(&pdev->dev, "source");
+ if (IS_ERR(host->src_clk))
+ return PTR_ERR(host->src_clk);
+
+ host->h_clk = devm_clk_get(&pdev->dev, "hclk");
+ if (IS_ERR(host->h_clk))
+ return PTR_ERR(host->h_clk);
+
+ host->bus_clk = devm_clk_get_optional(&pdev->dev, "bus_clk");
+ if (IS_ERR(host->bus_clk))
+ host->bus_clk = NULL;
+
+ /*source clock control gate is optional clock*/
+ host->src_clk_cg = devm_clk_get_optional(&pdev->dev, "source_cg");
+ if (IS_ERR(host->src_clk_cg))
+ host->src_clk_cg = NULL;
+
+ host->sys_clk_cg = devm_clk_get_optional(&pdev->dev, "sys_cg");
+ if (IS_ERR(host->sys_clk_cg))
+ host->sys_clk_cg = NULL;
+
+ /* If present, always enable for this clock gate */
+ clk_prepare_enable(host->sys_clk_cg);
+
+ host->bulk_clks[0].id = "pclk_cg";
+ host->bulk_clks[1].id = "axi_cg";
+ host->bulk_clks[2].id = "ahb_cg";
+ ret = devm_clk_bulk_get_optional(&pdev->dev, MSDC_NR_CLOCKS,
+ host->bulk_clks);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot get pclk/axi/ahb clock gates\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int msdc_drv_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
@@ -2406,30 +2499,16 @@ static int msdc_drv_probe(struct platform_device *pdev)
if (ret)
goto host_free;
- host->src_clk = devm_clk_get(&pdev->dev, "source");
- if (IS_ERR(host->src_clk)) {
- ret = PTR_ERR(host->src_clk);
- goto host_free;
- }
-
- host->h_clk = devm_clk_get(&pdev->dev, "hclk");
- if (IS_ERR(host->h_clk)) {
- ret = PTR_ERR(host->h_clk);
+ ret = msdc_of_clock_parse(pdev, host);
+ if (ret)
goto host_free;
- }
-
- host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
- if (IS_ERR(host->bus_clk))
- host->bus_clk = NULL;
- /*source clock control gate is optional clock*/
- host->src_clk_cg = devm_clk_get(&pdev->dev, "source_cg");
- if (IS_ERR(host->src_clk_cg))
- host->src_clk_cg = NULL;
host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
"hrst");
- if (IS_ERR(host->reset))
- return PTR_ERR(host->reset);
+ if (IS_ERR(host->reset)) {
+ ret = PTR_ERR(host->reset);
+ goto host_free;
+ }
host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0) {
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 12ee07285980..2fe6fcdbb1b3 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -157,32 +157,16 @@ struct mxcmci_host {
enum mxcmci_type devtype;
};
-static const struct platform_device_id mxcmci_devtype[] = {
- {
- .name = "imx21-mmc",
- .driver_data = IMX21_MMC,
- }, {
- .name = "imx31-mmc",
- .driver_data = IMX31_MMC,
- }, {
- .name = "mpc512x-sdhc",
- .driver_data = MPC512X_MMC,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, mxcmci_devtype);
-
static const struct of_device_id mxcmci_of_match[] = {
{
.compatible = "fsl,imx21-mmc",
- .data = &mxcmci_devtype[IMX21_MMC],
+ .data = (void *) IMX21_MMC,
}, {
.compatible = "fsl,imx31-mmc",
- .data = &mxcmci_devtype[IMX31_MMC],
+ .data = (void *) IMX31_MMC,
}, {
.compatible = "fsl,mpc5121-sdhc",
- .data = &mxcmci_devtype[MPC512X_MMC],
+ .data = (void *) MPC512X_MMC,
}, {
/* sentinel */
}
@@ -1001,13 +985,10 @@ static int mxcmci_probe(struct platform_device *pdev)
int ret = 0, irq;
bool dat3_card_detect = false;
dma_cap_mask_t mask;
- const struct of_device_id *of_id;
struct imxmmc_platform_data *pdata = pdev->dev.platform_data;
pr_info("i.MX/MPC512x SDHC driver\n");
- of_id = of_match_device(mxcmci_of_match, &pdev->dev);
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -1044,12 +1025,7 @@ static int mxcmci_probe(struct platform_device *pdev)
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;
- if (of_id) {
- const struct platform_device_id *id_entry = of_id->data;
- host->devtype = id_entry->driver_data;
- } else {
- host->devtype = pdev->id_entry->driver_data;
- }
+ host->devtype = (enum mxcmci_type)of_device_get_match_data(&pdev->dev);
/* adjust max_segs after devtype detection */
if (!is_mpc512x_mmc(host))
@@ -1241,7 +1217,6 @@ static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
static struct platform_driver mxcmci_driver = {
.probe = mxcmci_probe,
.remove = mxcmci_remove,
- .id_table = mxcmci_devtype,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 75007f61df97..56bbc6cd9c84 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -545,19 +545,6 @@ static const struct mmc_host_ops mxs_mmc_ops = {
.enable_sdio_irq = mxs_mmc_enable_sdio_irq,
};
-static const struct platform_device_id mxs_ssp_ids[] = {
- {
- .name = "imx23-mmc",
- .driver_data = IMX23_SSP,
- }, {
- .name = "imx28-mmc",
- .driver_data = IMX28_SSP,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, mxs_ssp_ids);
-
static const struct of_device_id mxs_mmc_dt_ids[] = {
{ .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_SSP, },
{ .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_SSP, },
@@ -567,8 +554,6 @@ MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids);
static int mxs_mmc_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id =
- of_match_device(mxs_mmc_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct mxs_mmc_host *host;
struct mmc_host *mmc;
@@ -593,7 +578,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
goto out_mmc_free;
}
- ssp->devid = (enum mxs_ssp_id) of_id->data;
+ ssp->devid = (enum mxs_ssp_id)of_device_get_match_data(&pdev->dev);
host->mmc = mmc;
host->sdio_irq_en = 0;
@@ -723,7 +708,6 @@ static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume);
static struct platform_driver mxs_mmc_driver = {
.probe = mxs_mmc_probe,
.remove = mxs_mmc_remove,
- .id_table = mxs_ssp_ids,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c
index ccf214a89eda..53b81582f1af 100644
--- a/drivers/mmc/host/owl-mmc.c
+++ b/drivers/mmc/host/owl-mmc.c
@@ -134,10 +134,9 @@ static void owl_mmc_update_reg(void __iomem *reg, unsigned int val, bool state)
static irqreturn_t owl_irq_handler(int irq, void *devid)
{
struct owl_mmc_host *owl_host = devid;
- unsigned long flags;
u32 state;
- spin_lock_irqsave(&owl_host->lock, flags);
+ spin_lock(&owl_host->lock);
state = readl(owl_host->base + OWL_REG_SD_STATE);
if (state & OWL_SD_STATE_TEI) {
@@ -147,7 +146,7 @@ static irqreturn_t owl_irq_handler(int irq, void *devid)
complete(&owl_host->sdc_complete);
}
- spin_unlock_irqrestore(&owl_host->lock, flags);
+ spin_unlock(&owl_host->lock);
return IRQ_HANDLED;
}
@@ -522,11 +521,11 @@ static void owl_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* Enable DDR mode if requested */
if (ios->timing == MMC_TIMING_UHS_DDR50) {
- owl_host->ddr_50 = 1;
+ owl_host->ddr_50 = true;
owl_mmc_update_reg(owl_host->base + OWL_REG_SD_EN,
OWL_SD_EN_DDREN, true);
} else {
- owl_host->ddr_50 = 0;
+ owl_host->ddr_50 = false;
}
}
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 29f6180a0036..316393c694d7 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -731,6 +731,7 @@ static int pxamci_probe(struct platform_device *pdev)
host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(host->power)) {
+ ret = PTR_ERR(host->power);
dev_err(dev, "Failed requesting gpio_power\n");
goto out;
}
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index acb9c81a4e45..38f028e70633 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -18,28 +18,39 @@
*
*/
-#include <linux/kernel.h>
#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
-#include <linux/mfd/tmio.h>
-#include <linux/sh_dma.h>
-#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl-state.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
#include <linux/regulator/consumer.h>
+#include <linux/sh_dma.h>
+#include <linux/slab.h>
#include <linux/sys_soc.h>
#include "renesas_sdhi.h"
#include "tmio_mmc.h"
-#define HOST_MODE 0xe4
+#define CTL_HOST_MODE 0xe4
+#define HOST_MODE_GEN2_SDR50_WMODE BIT(0)
+#define HOST_MODE_GEN2_SDR104_WMODE BIT(0)
+#define HOST_MODE_GEN3_WMODE BIT(0)
+#define HOST_MODE_GEN3_BUSWIDTH BIT(8)
+
+#define HOST_MODE_GEN3_16BIT HOST_MODE_GEN3_WMODE
+#define HOST_MODE_GEN3_32BIT (HOST_MODE_GEN3_WMODE | HOST_MODE_GEN3_BUSWIDTH)
+#define HOST_MODE_GEN3_64BIT 0
+
+#define CTL_SDIF_MODE 0xe6
+#define SDIF_MODE_HS400 BIT(0)
#define SDHI_VER_GEN2_SDR50 0x490c
#define SDHI_VER_RZ_A1 0x820b
@@ -60,26 +71,26 @@ static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
*/
switch (sd_ctrl_read16(host, CTL_VERSION)) {
case SDHI_VER_GEN2_SDR50:
- val = (width == 32) ? 0x0001 : 0x0000;
+ val = (width == 32) ? HOST_MODE_GEN2_SDR50_WMODE : 0;
break;
case SDHI_VER_GEN2_SDR104:
- val = (width == 32) ? 0x0000 : 0x0001;
+ val = (width == 32) ? 0 : HOST_MODE_GEN2_SDR104_WMODE;
break;
case SDHI_VER_GEN3_SD:
case SDHI_VER_GEN3_SDMMC:
if (width == 64)
- val = 0x0000;
+ val = HOST_MODE_GEN3_64BIT;
else if (width == 32)
- val = 0x0101;
+ val = HOST_MODE_GEN3_32BIT;
else
- val = 0x0001;
+ val = HOST_MODE_GEN3_16BIT;
break;
default:
/* nothing to do */
return;
}
- sd_ctrl_write16(host, HOST_MODE, val);
+ sd_ctrl_write16(host, CTL_HOST_MODE, val);
}
static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
@@ -373,7 +384,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
/* Set HS400 mode */
- sd_ctrl_write16(host, CTL_SDIF_MODE, 0x0001 |
+ sd_ctrl_write16(host, CTL_SDIF_MODE, SDIF_MODE_HS400 |
sd_ctrl_read16(host, CTL_SDIF_MODE));
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF,
@@ -424,9 +435,11 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
priv->needs_adjust_hs400 = true;
}
-static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host,
- struct renesas_sdhi *priv)
+static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct renesas_sdhi *priv = host_to_priv(host);
+
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
@@ -434,14 +447,6 @@ static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host,
~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
sd_scc_read32(host, priv,
SH_MOBILE_SDHI_SCC_CKSEL));
-}
-
-static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- struct renesas_sdhi *priv = host_to_priv(host);
-
- renesas_sdhi_reset_scc(host, priv);
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
~SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN &
@@ -527,7 +532,7 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
/* Reset HS400 mode */
- sd_ctrl_write16(host, CTL_SDIF_MODE, ~0x0001 &
+ sd_ctrl_write16(host, CTL_SDIF_MODE, ~SDIF_MODE_HS400 &
sd_ctrl_read16(host, CTL_SDIF_MODE));
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos);
@@ -552,24 +557,38 @@ static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_io
return 0;
}
+/* only populated for TMIO_MMC_MIN_RCAR2 */
static void renesas_sdhi_reset(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
+ u16 val;
- renesas_sdhi_reset_scc(host, priv);
- renesas_sdhi_reset_hs400_mode(host, priv);
- priv->needs_adjust_hs400 = false;
+ if (priv->scc_ctl) {
+ renesas_sdhi_disable_scc(host->mmc);
+ renesas_sdhi_reset_hs400_mode(host, priv);
+ priv->needs_adjust_hs400 = false;
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
+ ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+ }
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
- ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
- sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+ sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, TMIO_MASK_INIT_RCAR2);
+
+ if (sd_ctrl_read16(host, CTL_VERSION) >= SDHI_VER_GEN3_SD) {
+ val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
+ val |= CARD_OPT_EXTOP;
+ sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, val);
+ }
+}
+
+static unsigned int renesas_sdhi_gen3_get_cycles(struct tmio_mmc_host *host)
+{
+ u16 num, val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
+
+ num = (val & CARD_OPT_TOP_MASK) >> CARD_OPT_TOP_SHIFT;
+ return 1 << ((val & CARD_OPT_EXTOP ? 14 : 13) + num);
- if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
- sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK,
- TMIO_MASK_INIT_RCAR2);
}
#define SH_MOBILE_SDHI_MIN_TAP_ROW 3
@@ -803,7 +822,7 @@ static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
case CTL_SD_MEM_CARD_OPT:
case CTL_TRANSACTION_CTL:
case CTL_DMA_ENABLE:
- case HOST_MODE:
+ case CTL_HOST_MODE:
if (host->pdata->flags & TMIO_MMC_HAVE_CBSY)
bit = TMIO_STAT_CMD_BUSY;
fallthrough;
@@ -1005,11 +1024,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->ops.start_signal_voltage_switch =
renesas_sdhi_start_signal_voltage_switch;
host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27;
-
- if (of_data && of_data->scc_offset) {
- priv->scc_ctl = host->ctl + of_data->scc_offset;
- host->reset = renesas_sdhi_reset;
- }
+ host->reset = renesas_sdhi_reset;
}
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
@@ -1042,6 +1057,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
/* All SDHI have SDIO status bits which must be 1 */
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
+ /* All SDHI support HW busy detection */
+ mmc_data->flags |= TMIO_MMC_USE_BUSY_TIMEOUT;
+
dev_pm_domain_start(&pdev->dev);
ret = renesas_sdhi_clk_enable(host);
@@ -1065,9 +1083,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
quirks->hs400_calib_table + 1);
}
- ret = tmio_mmc_host_probe(host);
- if (ret < 0)
- goto edisclk;
+ /* these have an EXTOP bit */
+ if (ver >= SDHI_VER_GEN3_SD)
+ host->get_timeout_cycles = renesas_sdhi_gen3_get_cycles;
/* Enable tuning iff we have an SCC and a supported mode */
if (of_data && of_data->scc_offset &&
@@ -1093,6 +1111,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (!hit)
dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n");
+ priv->scc_ctl = host->ctl + of_data->scc_offset;
host->check_retune = renesas_sdhi_check_scc_error;
host->ops.execute_tuning = renesas_sdhi_execute_tuning;
host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning;
@@ -1100,6 +1119,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->ops.hs400_complete = renesas_sdhi_hs400_complete;
}
+ ret = tmio_mmc_host_probe(host);
+ if (ret < 0)
+ goto edisclk;
+
num_irqs = platform_irq_count(pdev);
if (num_irqs < 0) {
ret = num_irqs;
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index a7b5ad17bcf5..e6f5bbce5685 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -48,6 +48,8 @@ struct realtek_pci_sdmmc {
bool using_cookie;
};
+static int sdmmc_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios);
+
static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
{
return &(host->pdev->dev);
@@ -896,7 +898,10 @@ static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
static int sd_power_on(struct realtek_pci_sdmmc *host)
{
struct rtsx_pcr *pcr = host->pcr;
+ struct mmc_host *mmc = host->mmc;
int err;
+ u32 val;
+ u8 test_mode;
if (host->power_state == SDMMC_POWER_ON)
return 0;
@@ -923,6 +928,30 @@ static int sd_power_on(struct realtek_pci_sdmmc *host)
if (err < 0)
return err;
+ if (PCI_PID(pcr) == PID_5261) {
+ /*
+ * If test mode is set switch to SD Express mandatorily,
+ * this is only for factory testing.
+ */
+ rtsx_pci_read_register(pcr, RTS5261_FW_CFG_INFO0, &test_mode);
+ if (test_mode & RTS5261_FW_EXPRESS_TEST_MASK) {
+ sdmmc_init_sd_express(mmc, NULL);
+ return 0;
+ }
+ if (pcr->extra_caps & EXTRA_CAPS_SD_EXPRESS)
+ mmc->caps2 |= MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V;
+ /*
+ * HW read wp status when resuming from S3/S4,
+ * and then picks SD legacy interface if it's set
+ * in read-only mode.
+ */
+ val = rtsx_pci_readl(pcr, RTSX_BIPR);
+ if (val & SD_WRITE_PROTECT) {
+ pcr->extra_caps &= ~EXTRA_CAPS_SD_EXPRESS;
+ mmc->caps2 &= ~(MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V);
+ }
+ }
+
host->power_state = SDMMC_POWER_ON;
return 0;
}
@@ -1309,6 +1338,45 @@ out:
return err;
}
+static int sdmmc_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ u32 relink_time;
+ struct realtek_pci_sdmmc *host = mmc_priv(mmc);
+ struct rtsx_pcr *pcr = host->pcr;
+
+ /* Set relink_time for changing to PCIe card */
+ relink_time = 0x8FFF;
+
+ rtsx_pci_write_register(pcr, 0xFF01, 0xFF, relink_time);
+ rtsx_pci_write_register(pcr, 0xFF02, 0xFF, relink_time >> 8);
+ rtsx_pci_write_register(pcr, 0xFF03, 0x01, relink_time >> 16);
+
+ rtsx_pci_write_register(pcr, PETXCFG, 0x80, 0x80);
+ rtsx_pci_write_register(pcr, LDO_VCC_CFG0,
+ RTS5261_LDO1_OCP_THD_MASK,
+ pcr->option.sd_800mA_ocp_thd);
+
+ if (pcr->ops->disable_auto_blink)
+ pcr->ops->disable_auto_blink(pcr);
+
+ /* For PCIe/NVMe mode can't enter delink issue */
+ pcr->hw_param.interrupt_en &= ~(SD_INT_EN);
+ rtsx_pci_writel(pcr, RTSX_BIER, pcr->hw_param.interrupt_en);
+
+ rtsx_pci_write_register(pcr, RTS5260_AUTOLOAD_CFG4,
+ RTS5261_AUX_CLK_16M_EN, RTS5261_AUX_CLK_16M_EN);
+ rtsx_pci_write_register(pcr, RTS5261_FW_CFG0,
+ RTS5261_FW_ENTER_EXPRESS, RTS5261_FW_ENTER_EXPRESS);
+ rtsx_pci_write_register(pcr, RTS5261_FW_CFG1,
+ RTS5261_MCU_CLOCK_GATING, RTS5261_MCU_CLOCK_GATING);
+ rtsx_pci_write_register(pcr, RTS5261_FW_CFG1,
+ RTS5261_MCU_BUS_SEL_MASK | RTS5261_MCU_CLOCK_SEL_MASK
+ | RTS5261_DRIVER_ENABLE_FW,
+ RTS5261_MCU_CLOCK_SEL_16M | RTS5261_DRIVER_ENABLE_FW);
+ host->eject = true;
+ return 0;
+}
+
static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
.pre_req = sdmmc_pre_req,
.post_req = sdmmc_post_req,
@@ -1318,6 +1386,7 @@ static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
.get_cd = sdmmc_get_cd,
.start_signal_voltage_switch = sdmmc_switch_voltage,
.execute_tuning = sdmmc_execute_tuning,
+ .init_sd_express = sdmmc_init_sd_express,
};
static void init_extra_caps(struct realtek_pci_sdmmc *host)
@@ -1339,6 +1408,8 @@ static void init_extra_caps(struct realtek_pci_sdmmc *host)
mmc->caps |= MMC_CAP_8_BIT_DATA;
if (pcr->extra_caps & EXTRA_CAPS_NO_MMC)
mmc->caps2 |= MMC_CAP2_NO_MMC;
+ if (pcr->extra_caps & EXTRA_CAPS_SD_EXPRESS)
+ mmc->caps2 |= MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V;
}
static void realtek_init_host(struct realtek_pci_sdmmc *host)
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 643d54eceef6..a33a7823c265 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -17,7 +17,7 @@
#include <linux/cpufreq.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 54205e3be9e8..b6574e7fd26b 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -5,6 +5,7 @@
* Copyright (c) 2012, Intel Corporation.
*/
+#include <linux/bitfield.h>
#include <linux/init.h>
#include <linux/export.h>
#include <linux/module.h>
@@ -545,10 +546,41 @@ struct amd_sdhci_host {
static int amd_select_drive_strength(struct mmc_card *card,
unsigned int max_dtr, int host_drv,
- int card_drv, int *drv_type)
+ int card_drv, int *host_driver_strength)
{
- *drv_type = MMC_SET_DRIVER_TYPE_A;
- return MMC_SET_DRIVER_TYPE_A;
+ struct sdhci_host *host = mmc_priv(card->host);
+ u16 preset, preset_driver_strength;
+
+ /*
+ * This method is only called by mmc_select_hs200 so we only need to
+ * read from the HS200 (SDR104) preset register.
+ *
+ * Firmware that has "invalid/default" presets return a driver strength
+ * of A. This matches the previously hard coded value.
+ */
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
+ preset_driver_strength = FIELD_GET(SDHCI_PRESET_DRV_MASK, preset);
+
+ /*
+ * We want the controller driver strength to match the card's driver
+ * strength so they have similar rise/fall times.
+ *
+ * The controller driver strength set by this method is sticky for all
+ * timings after this method is called. This unfortunately means that
+ * while HS400 tuning is in progress we end up with mismatched driver
+ * strengths between the controller and the card. HS400 tuning requires
+ * switching from HS400->DDR52->HS->HS200->HS400. So the driver mismatch
+ * happens while in DDR52 and HS modes. This has not been observed to
+ * cause problems. Enabling presets would fix this issue.
+ */
+ *host_driver_strength = preset_driver_strength;
+
+ /*
+ * The resulting card driver strength is only set when switching the
+ * card's timing to HS200 or HS400. The card will use the default driver
+ * strength (B) for any other mode.
+ */
+ return preset_driver_strength;
}
static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host, bool enable)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index fce8fa7e6b30..16ed19f47939 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -296,22 +296,6 @@ struct pltfm_imx_data {
struct pm_qos_request pm_qos_req;
};
-static const struct platform_device_id imx_esdhc_devtype[] = {
- {
- .name = "sdhci-esdhc-imx25",
- .driver_data = (kernel_ulong_t) &esdhc_imx25_data,
- }, {
- .name = "sdhci-esdhc-imx35",
- .driver_data = (kernel_ulong_t) &esdhc_imx35_data,
- }, {
- .name = "sdhci-esdhc-imx51",
- .driver_data = (kernel_ulong_t) &esdhc_imx51_data,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);
-
static const struct of_device_id imx_esdhc_dt_ids[] = {
{ .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, },
{ .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, },
@@ -1531,72 +1515,6 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
}
#endif
-static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
- struct sdhci_host *host,
- struct pltfm_imx_data *imx_data)
-{
- struct esdhc_platform_data *boarddata = &imx_data->boarddata;
- int err;
-
- if (!host->mmc->parent->platform_data) {
- dev_err(mmc_dev(host->mmc), "no board data!\n");
- return -EINVAL;
- }
-
- imx_data->boarddata = *((struct esdhc_platform_data *)
- host->mmc->parent->platform_data);
- /* write_protect */
- if (boarddata->wp_type == ESDHC_WP_GPIO) {
- host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
-
- err = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0);
- if (err) {
- dev_err(mmc_dev(host->mmc),
- "failed to request write-protect gpio!\n");
- return err;
- }
- }
-
- /* card_detect */
- switch (boarddata->cd_type) {
- case ESDHC_CD_GPIO:
- err = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0);
- if (err) {
- dev_err(mmc_dev(host->mmc),
- "failed to request card-detect gpio!\n");
- return err;
- }
- fallthrough;
-
- case ESDHC_CD_CONTROLLER:
- /* we have a working card_detect back */
- host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
- break;
-
- case ESDHC_CD_PERMANENT:
- host->mmc->caps |= MMC_CAP_NONREMOVABLE;
- break;
-
- case ESDHC_CD_NONE:
- break;
- }
-
- switch (boarddata->max_bus_width) {
- case 8:
- host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
- break;
- case 4:
- host->mmc->caps |= MMC_CAP_4_BIT_DATA;
- break;
- case 1:
- default:
- host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
- break;
- }
-
- return 0;
-}
-
static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
@@ -1616,8 +1534,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data = sdhci_pltfm_priv(pltfm_host);
- imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *)
- pdev->id_entry->driver_data;
+ imx_data->socdata = of_id->data;
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
@@ -1713,10 +1630,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
goto disable_ahb_clk;
}
- if (of_id)
- err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
- else
- err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data);
+ err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
if (err)
goto disable_ahb_clk;
@@ -1929,7 +1843,6 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
.of_match_table = imx_esdhc_dt_ids,
.pm = &sdhci_esdhc_pmops,
},
- .id_table = imx_esdhc_devtype,
.probe = sdhci_esdhc_imx_probe,
.remove = sdhci_esdhc_imx_remove,
};
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 3451eb325513..9c7927b03253 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -248,7 +248,6 @@ struct sdhci_msm_variant_ops {
struct sdhci_msm_variant_info {
bool mci_removed;
bool restore_dll_config;
- bool uses_tassadar_dll;
const struct sdhci_msm_variant_ops *var_ops;
const struct sdhci_msm_offset *offset;
};
@@ -2154,18 +2153,10 @@ static const struct sdhci_msm_variant_info sdm845_sdhci_var = {
.offset = &sdhci_msm_v5_offset,
};
-static const struct sdhci_msm_variant_info sm8250_sdhci_var = {
- .mci_removed = true,
- .uses_tassadar_dll = true,
- .var_ops = &v5_var_ops,
- .offset = &sdhci_msm_v5_offset,
-};
-
static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
- {.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var},
{.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var},
{},
};
@@ -2249,7 +2240,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
msm_host->restore_dll_config = var_info->restore_dll_config;
msm_host->var_ops = var_info->var_ops;
msm_host->offset = var_info->offset;
- msm_host->uses_tassadar_dll = var_info->uses_tassadar_dll;
msm_offset = msm_host->offset;
@@ -2396,6 +2386,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
if (core_major == 1 && core_minor >= 0x49)
msm_host->updated_ddr_cfg = true;
+ if (core_major == 1 && core_minor >= 0x71)
+ msm_host->uses_tassadar_dll = true;
+
ret = sdhci_msm_register_vreg(msm_host);
if (ret)
goto clk_disable;
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 3b8d456e857d..4f3774bcda94 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -624,6 +624,7 @@ static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
case MMC_TIMING_MMC_HS200:
/* For 200MHz clock, 8 Taps are available */
tap_max = 8;
+ break;
default:
break;
}
@@ -692,6 +693,7 @@ static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees)
case MMC_TIMING_MMC_HS200:
/* For 200MHz clock, 30 Taps are available */
tap_max = 30;
+ break;
default:
break;
}
@@ -751,6 +753,7 @@ static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
case MMC_TIMING_MMC_HS200:
/* For 200MHz clock, 8 Taps are available */
tap_max = 8;
+ break;
default:
break;
}
@@ -817,6 +820,7 @@ static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees)
case MMC_TIMING_MMC_HS200:
/* For 200MHz clock, 30 Taps are available */
tap_max = 30;
+ break;
default:
break;
}
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 9887485a4134..b85edd62e7f0 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -87,6 +87,9 @@
#define PCIE_GLI_9763E_SCR 0x8E0
#define GLI_9763E_SCR_AXI_REQ BIT(9)
+#define PCIE_GLI_9763E_MMC_CTRL 0x960
+#define GLI_9763E_HS400_SLOW BIT(3)
+
#define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200
#define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \
SDHCI_TRNS_BLK_CNT_EN | \
@@ -97,6 +100,10 @@
#define GLI_9755_WT_EN_ON 0x1
#define GLI_9755_WT_EN_OFF 0x0
+#define PCI_GLI_9755_PECONF 0x44
+#define PCI_GLI_9755_LFCLK GENMASK(14, 12)
+#define PCI_GLI_9755_DMACLK BIT(29)
+
#define PCI_GLI_9755_PLL 0x64
#define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0)
#define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12)
@@ -519,6 +526,21 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_enable_clk(host, clk);
}
+static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
+{
+ struct pci_dev *pdev = slot->chip->pdev;
+ u32 value;
+
+ gl9755_wt_on(pdev);
+
+ pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, &value);
+ value &= ~PCI_GLI_9755_LFCLK;
+ value &= ~PCI_GLI_9755_DMACLK;
+ pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value);
+
+ gl9755_wt_off(pdev);
+}
+
static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
{
struct sdhci_host *host = slot->host;
@@ -534,6 +556,7 @@ static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
{
struct sdhci_host *host = slot->host;
+ gl9755_hw_setting(slot);
gli_pcie_enable_msi(slot);
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
sdhci_enable_v4_mode(host);
@@ -764,6 +787,10 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
value |= GLI_9763E_SCR_AXI_REQ;
pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value);
+ pci_read_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, &value);
+ value &= ~GLI_9763E_HS400_SLOW;
+ pci_write_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, value);
+
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
value &= ~GLI_9763E_VHS_REV;
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
diff --git a/drivers/mmc/host/sdhci-pic32.c b/drivers/mmc/host/sdhci-pic32.c
index 6ce1519ae177..6696b6bdd88e 100644
--- a/drivers/mmc/host/sdhci-pic32.c
+++ b/drivers/mmc/host/sdhci-pic32.c
@@ -121,10 +121,9 @@ static void pic32_sdhci_shared_bus(struct platform_device *pdev)
writel(bus, host->ioaddr + SDH_SHARED_BUS_CTRL);
}
-static int pic32_sdhci_probe_platform(struct platform_device *pdev,
+static void pic32_sdhci_probe_platform(struct platform_device *pdev,
struct pic32_sdhci_priv *pdata)
{
- int ret = 0;
u32 caps_slot_type;
struct sdhci_host *host = platform_get_drvdata(pdev);
@@ -133,8 +132,6 @@ static int pic32_sdhci_probe_platform(struct platform_device *pdev,
caps_slot_type = (host->caps & SDH_CAPS_SDH_SLOT_TYPE_MASK) >> 30;
if (caps_slot_type == SDH_SLOT_TYPE_SHARED_BUS)
pic32_sdhci_shared_bus(pdev);
-
- return ret;
}
static int pic32_sdhci_probe(struct platform_device *pdev)
@@ -193,11 +190,7 @@ static int pic32_sdhci_probe(struct platform_device *pdev)
if (ret)
goto err_base_clk;
- ret = pic32_sdhci_probe_platform(pdev, sdhci_pdata);
- if (ret) {
- dev_err(&pdev->dev, "failed to probe platform!\n");
- goto err_base_clk;
- }
+ pic32_sdhci_probe_platform(pdev, sdhci_pdata);
ret = sdhci_add_host(host);
if (ret)
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index 58109c5b53e2..f85171edabeb 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -788,7 +788,7 @@ static struct platform_driver sdhci_sprd_driver = {
.driver = {
.name = "sdhci_sprd_r11",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(sdhci_sprd_of_match),
+ .of_match_table = sdhci_sprd_of_match,
.pm = &sdhci_sprd_pm_ops,
},
};
diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c
index 4e9ff3e828ba..962872aec164 100644
--- a/drivers/mmc/host/sdhci-st.c
+++ b/drivers/mmc/host/sdhci-st.c
@@ -523,7 +523,7 @@ static struct platform_driver sdhci_st_driver = {
.name = "sdhci-st",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_st_pmops,
- .of_match_table = of_match_ptr(st_sdhci_match),
+ .of_match_table = st_sdhci_match,
},
};
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index ed12aacb1c73..41d193fa77bb 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -1272,7 +1272,7 @@ static void tegra_sdhci_set_timeout(struct sdhci_host *host,
* busy wait mode.
*/
val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
- if (cmd && cmd->busy_timeout >= 11 * HZ)
+ if (cmd && cmd->busy_timeout >= 11 * MSEC_PER_SEC)
val |= SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT;
else
val &= ~SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT;
diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c
index 03ce57ef4585..8cf3a375de65 100644
--- a/drivers/mmc/host/sdhci-xenon-phy.c
+++ b/drivers/mmc/host/sdhci-xenon-phy.c
@@ -651,11 +651,13 @@ static int get_dt_pad_ctrl_data(struct sdhci_host *host,
struct device_node *np,
struct xenon_emmc_phy_params *params)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret = 0;
const char *name;
struct resource iomem;
- if (of_device_is_compatible(np, "marvell,armada-3700-sdhci"))
+ if (priv->hw_version == XENON_A3700)
params->pad_ctrl.set_soc_pad = armada_3700_soc_pad_voltage_set;
else
return 0;
@@ -689,35 +691,37 @@ static int get_dt_pad_ctrl_data(struct sdhci_host *host,
return ret;
}
-static int xenon_emmc_phy_parse_param_dt(struct sdhci_host *host,
- struct device_node *np,
- struct xenon_emmc_phy_params *params)
+static int xenon_emmc_phy_parse_params(struct sdhci_host *host,
+ struct device *dev,
+ struct xenon_emmc_phy_params *params)
{
u32 value;
params->slow_mode = false;
- if (of_property_read_bool(np, "marvell,xenon-phy-slow-mode"))
+ if (device_property_read_bool(dev, "marvell,xenon-phy-slow-mode"))
params->slow_mode = true;
params->znr = XENON_ZNR_DEF_VALUE;
- if (!of_property_read_u32(np, "marvell,xenon-phy-znr", &value))
+ if (!device_property_read_u32(dev, "marvell,xenon-phy-znr", &value))
params->znr = value & XENON_ZNR_MASK;
params->zpr = XENON_ZPR_DEF_VALUE;
- if (!of_property_read_u32(np, "marvell,xenon-phy-zpr", &value))
+ if (!device_property_read_u32(dev, "marvell,xenon-phy-zpr", &value))
params->zpr = value & XENON_ZPR_MASK;
params->nr_tun_times = XENON_TUN_CONSECUTIVE_TIMES;
- if (!of_property_read_u32(np, "marvell,xenon-phy-nr-success-tun",
- &value))
+ if (!device_property_read_u32(dev, "marvell,xenon-phy-nr-success-tun",
+ &value))
params->nr_tun_times = value & XENON_TUN_CONSECUTIVE_TIMES_MASK;
params->tun_step_divider = XENON_TUNING_STEP_DIVIDER;
- if (!of_property_read_u32(np, "marvell,xenon-phy-tun-step-divider",
- &value))
+ if (!device_property_read_u32(dev, "marvell,xenon-phy-tun-step-divider",
+ &value))
params->tun_step_divider = value & 0xFF;
- return get_dt_pad_ctrl_data(host, np, params);
+ if (dev->of_node)
+ return get_dt_pad_ctrl_data(host, dev->of_node, params);
+ return 0;
}
/* Set SoC PHY Voltage PAD */
@@ -811,7 +815,7 @@ int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios)
return ret;
}
-static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
+static int xenon_add_phy(struct device *dev, struct sdhci_host *host,
const char *phy_name)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -830,15 +834,15 @@ static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
if (ret)
return ret;
- return xenon_emmc_phy_parse_param_dt(host, np, priv->phy_params);
+ return xenon_emmc_phy_parse_params(host, dev, priv->phy_params);
}
-int xenon_phy_parse_dt(struct device_node *np, struct sdhci_host *host)
+int xenon_phy_parse_params(struct device *dev, struct sdhci_host *host)
{
const char *phy_type = NULL;
- if (!of_property_read_string(np, "marvell,xenon-phy-type", &phy_type))
- return xenon_add_phy(np, host, phy_type);
+ if (!device_property_read_string(dev, "marvell,xenon-phy-type", &phy_type))
+ return xenon_add_phy(dev, host, phy_type);
- return xenon_add_phy(np, host, "emmc 5.1 phy");
+ return xenon_add_phy(dev, host, "emmc 5.1 phy");
}
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c
index 24c978de2a3f..c67611fdaa8a 100644
--- a/drivers/mmc/host/sdhci-xenon.c
+++ b/drivers/mmc/host/sdhci-xenon.c
@@ -11,6 +11,7 @@
* Special thanks to Video BG4 project team.
*/
+#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/module.h>
@@ -247,6 +248,16 @@ static void xenon_voltage_switch(struct sdhci_host *host)
sdhci_readw(host, SDHCI_HOST_CONTROL2);
}
+static unsigned int xenon_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ if (pltfm_host->clk)
+ return sdhci_pltfm_clk_get_max_clock(host);
+ else
+ return pltfm_host->clock;
+}
+
static const struct sdhci_ops sdhci_xenon_ops = {
.voltage_switch = xenon_voltage_switch,
.set_clock = sdhci_set_clock,
@@ -254,7 +265,7 @@ static const struct sdhci_ops sdhci_xenon_ops = {
.set_bus_width = sdhci_set_bus_width,
.reset = xenon_reset,
.set_uhs_signaling = xenon_set_uhs_signaling,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .get_max_clock = xenon_get_max_clock,
};
static const struct sdhci_pltfm_data sdhci_xenon_pdata = {
@@ -407,9 +418,9 @@ static void xenon_replace_mmc_host_ops(struct sdhci_host *host)
* Refer to XENON_SYS_CFG_INFO register
* tun-count: the interval between re-tuning
*/
-static int xenon_probe_dt(struct platform_device *pdev)
+static int xenon_probe_params(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
struct sdhci_host *host = platform_get_drvdata(pdev);
struct mmc_host *mmc = host->mmc;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -418,11 +429,11 @@ static int xenon_probe_dt(struct platform_device *pdev)
u32 tuning_count;
/* Disable HS200 on Armada AP806 */
- if (of_device_is_compatible(np, "marvell,armada-ap806-sdhci"))
+ if (priv->hw_version == XENON_AP806)
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
sdhc_id = 0x0;
- if (!of_property_read_u32(np, "marvell,xenon-sdhc-id", &sdhc_id)) {
+ if (!device_property_read_u32(dev, "marvell,xenon-sdhc-id", &sdhc_id)) {
nr_sdhc = sdhci_readl(host, XENON_SYS_CFG_INFO);
nr_sdhc &= XENON_NR_SUPPORTED_SLOT_MASK;
if (unlikely(sdhc_id > nr_sdhc)) {
@@ -434,8 +445,8 @@ static int xenon_probe_dt(struct platform_device *pdev)
priv->sdhc_id = sdhc_id;
tuning_count = XENON_DEF_TUNING_COUNT;
- if (!of_property_read_u32(np, "marvell,xenon-tun-count",
- &tuning_count)) {
+ if (!device_property_read_u32(dev, "marvell,xenon-tun-count",
+ &tuning_count)) {
if (unlikely(tuning_count >= XENON_TMR_RETUN_NO_PRESENT)) {
dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n",
XENON_DEF_TUNING_COUNT);
@@ -444,7 +455,7 @@ static int xenon_probe_dt(struct platform_device *pdev)
}
priv->tuning_count = tuning_count;
- return xenon_phy_parse_dt(np, host);
+ return xenon_phy_parse_params(dev, host);
}
static int xenon_sdhc_prepare(struct sdhci_host *host)
@@ -483,6 +494,7 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host)
static int xenon_probe(struct platform_device *pdev)
{
struct sdhci_pltfm_host *pltfm_host;
+ struct device *dev = &pdev->dev;
struct sdhci_host *host;
struct xenon_priv *priv;
int err;
@@ -495,43 +507,47 @@ static int xenon_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
priv = sdhci_pltfm_priv(pltfm_host);
+ priv->hw_version = (unsigned long)device_get_match_data(&pdev->dev);
+
/*
* Link Xenon specific mmc_host_ops function,
* to replace standard ones in sdhci_ops.
*/
xenon_replace_mmc_host_ops(host);
- pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
- if (IS_ERR(pltfm_host->clk)) {
- err = PTR_ERR(pltfm_host->clk);
- dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
- goto free_pltfm;
- }
- err = clk_prepare_enable(pltfm_host->clk);
- if (err)
- goto free_pltfm;
-
- priv->axi_clk = devm_clk_get(&pdev->dev, "axi");
- if (IS_ERR(priv->axi_clk)) {
- err = PTR_ERR(priv->axi_clk);
- if (err == -EPROBE_DEFER)
- goto err_clk;
- } else {
- err = clk_prepare_enable(priv->axi_clk);
+ if (dev->of_node) {
+ pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(pltfm_host->clk)) {
+ err = PTR_ERR(pltfm_host->clk);
+ dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
+ goto free_pltfm;
+ }
+ err = clk_prepare_enable(pltfm_host->clk);
if (err)
- goto err_clk;
+ goto free_pltfm;
+
+ priv->axi_clk = devm_clk_get(&pdev->dev, "axi");
+ if (IS_ERR(priv->axi_clk)) {
+ err = PTR_ERR(priv->axi_clk);
+ if (err == -EPROBE_DEFER)
+ goto err_clk;
+ } else {
+ err = clk_prepare_enable(priv->axi_clk);
+ if (err)
+ goto err_clk;
+ }
}
err = mmc_of_parse(host->mmc);
if (err)
goto err_clk_axi;
- sdhci_get_of_property(pdev);
+ sdhci_get_property(pdev);
xenon_set_acg(host, false);
- /* Xenon specific dt parse */
- err = xenon_probe_dt(pdev);
+ /* Xenon specific parameters parse */
+ err = xenon_probe_params(pdev);
if (err)
goto err_clk_axi;
@@ -667,18 +683,29 @@ static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
};
static const struct of_device_id sdhci_xenon_dt_ids[] = {
- { .compatible = "marvell,armada-ap806-sdhci",},
- { .compatible = "marvell,armada-cp110-sdhci",},
- { .compatible = "marvell,armada-3700-sdhci",},
+ { .compatible = "marvell,armada-ap806-sdhci", .data = (void *)XENON_AP806},
+ { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110},
+ { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700},
{}
};
MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id sdhci_xenon_acpi_ids[] = {
+ { .id = "MRVL0002", XENON_AP806},
+ { .id = "MRVL0003", XENON_AP807},
+ { .id = "MRVL0004", XENON_CP110},
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, sdhci_xenon_acpi_ids);
+#endif
+
static struct platform_driver sdhci_xenon_driver = {
.driver = {
.name = "xenon-sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_xenon_dt_ids,
+ .acpi_match_table = ACPI_PTR(sdhci_xenon_acpi_ids),
.pm = &sdhci_xenon_dev_pm_ops,
},
.probe = xenon_probe,
diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h
index 593b82d7b68a..3e9c6c908a79 100644
--- a/drivers/mmc/host/sdhci-xenon.h
+++ b/drivers/mmc/host/sdhci-xenon.h
@@ -53,6 +53,13 @@
#define XENON_CTRL_HS200 0x5
#define XENON_CTRL_HS400 0x6
+enum xenon_variant {
+ XENON_A3700,
+ XENON_AP806,
+ XENON_AP807,
+ XENON_CP110
+};
+
struct xenon_priv {
unsigned char tuning_count;
/* idx of SDHC */
@@ -90,11 +97,12 @@ struct xenon_priv {
void *phy_params;
struct xenon_emmc_phy_regs *emmc_phy_regs;
bool restore_needed;
+ enum xenon_variant hw_version;
};
int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
-int xenon_phy_parse_dt(struct device_node *np,
- struct sdhci_host *host);
+int xenon_phy_parse_params(struct device *dev,
+ struct sdhci_host *host);
void xenon_soc_pad_ctrl(struct sdhci_host *host,
unsigned char signal_voltage);
#endif
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3561ae8a481a..646823ddd317 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3994,10 +3994,10 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
if (host->v4_mode)
sdhci_do_enable_v4_mode(host);
- of_property_read_u64(mmc_dev(host->mmc)->of_node,
- "sdhci-caps-mask", &dt_caps_mask);
- of_property_read_u64(mmc_dev(host->mmc)->of_node,
- "sdhci-caps", &dt_caps);
+ device_property_read_u64(mmc_dev(host->mmc),
+ "sdhci-caps-mask", &dt_caps_mask);
+ device_property_read_u64(mmc_dev(host->mmc),
+ "sdhci-caps", &dt_caps);
v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION);
host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index fc62773602ec..6310693f2ac0 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -26,6 +26,7 @@
#include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -1515,7 +1516,7 @@ static struct platform_driver sunxi_mmc_driver = {
.driver = {
.name = "sunxi-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(sunxi_mmc_of_match),
+ .of_match_table = sunxi_mmc_of_match,
.pm = &sunxi_mmc_pm_ops,
},
.probe = sunxi_mmc_probe,
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index d2d3b8df1bbe..b55a29c53d9c 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -174,8 +174,7 @@ static int tmio_mmc_probe(struct platform_device *pdev)
if (ret)
goto host_remove;
- pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
- (unsigned long)host->ctl, irq);
+ pr_info("%s at 0x%p irq %d\n", mmc_hostname(host->mmc), host->ctl, irq);
return 0;
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 9546e542619c..784fa6ed5843 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -42,7 +42,6 @@
#define CTL_DMA_ENABLE 0xd8
#define CTL_RESET_SD 0xe0
#define CTL_VERSION 0xe2
-#define CTL_SDIF_MODE 0xe6
/* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
#define TMIO_STOP_STP BIT(0)
@@ -81,7 +80,11 @@
#define CLK_CTL_SCLKEN BIT(8)
/* Definitions for values the CTL_SD_MEM_CARD_OPT register can take */
+#define CARD_OPT_TOP_MASK 0xf0
+#define CARD_OPT_TOP_SHIFT 4
+#define CARD_OPT_EXTOP BIT(9) /* first appeared on R-Car Gen3 SDHI */
#define CARD_OPT_WIDTH8 BIT(13)
+#define CARD_OPT_ALWAYS1 BIT(14)
#define CARD_OPT_WIDTH BIT(15)
/* Definitions for values the CTL_SDIO_STATUS register can take */
@@ -180,6 +183,7 @@ struct tmio_mmc_host {
void (*reset)(struct tmio_mmc_host *host);
bool (*check_retune)(struct tmio_mmc_host *host);
void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq);
+ unsigned int (*get_timeout_cycles)(struct tmio_mmc_host *host);
void (*prepare_hs400_tuning)(struct tmio_mmc_host *host);
void (*hs400_downgrade)(struct tmio_mmc_host *host);
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index ac4e7874a3f1..942b8375179c 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -796,8 +796,10 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
- if (mrq->cmd->error || (mrq->data && mrq->data->error))
+ if (mrq->cmd->error || (mrq->data && mrq->data->error)) {
+ tmio_mmc_ack_mmc_irqs(host, TMIO_MASK_IRQ); /* Clear all */
tmio_mmc_abort_dma(host);
+ }
/* Error means retune, but executed command was still successful */
if (host->check_retune && host->check_retune(host))
@@ -885,6 +887,22 @@ static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, reg);
}
+static unsigned int tmio_mmc_get_timeout_cycles(struct tmio_mmc_host *host)
+{
+ u16 val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
+
+ val = (val & CARD_OPT_TOP_MASK) >> CARD_OPT_TOP_SHIFT;
+ return 1 << (13 + val);
+}
+
+static void tmio_mmc_max_busy_timeout(struct tmio_mmc_host *host)
+{
+ unsigned int clk_rate = host->mmc->actual_clock ?: host->mmc->f_max;
+
+ host->mmc->max_busy_timeout = host->get_timeout_cycles(host) /
+ (clk_rate / MSEC_PER_SEC);
+}
+
/* Set MMC clock / power.
* Note: This controller uses a simple divider scheme therefore it cannot
* run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
@@ -943,6 +961,9 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break;
}
+ if (host->pdata->flags & TMIO_MMC_USE_BUSY_TIMEOUT)
+ tmio_mmc_max_busy_timeout(host);
+
/* Let things settle. delay taken from winCE driver */
usleep_range(140, 200);
if (PTR_ERR(host->mrq) == -EINTR)
@@ -1099,6 +1120,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT))
_host->write16_hook = NULL;
+ if (pdata->flags & TMIO_MMC_USE_BUSY_TIMEOUT && !_host->get_timeout_cycles)
+ _host->get_timeout_cycles = tmio_mmc_get_timeout_cycles;
+
_host->set_pwr = pdata->set_pwr;
ret = tmio_mmc_init_ocr(_host);
diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c
index 3092466a99ab..a6cd16771d4e 100644
--- a/drivers/mmc/host/uniphier-sd.c
+++ b/drivers/mmc/host/uniphier-sd.c
@@ -586,6 +586,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
tmio_data = &priv->tmio_data;
tmio_data->flags |= TMIO_MMC_32BIT_DATA_PORT;
+ tmio_data->flags |= TMIO_MMC_USE_BUSY_TIMEOUT;
host = tmio_mmc_host_alloc(pdev, tmio_data);
if (IS_ERR(host))
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index 8ba042430d8e..27264fe4b3b9 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -55,7 +55,12 @@
*/
#define TMIO_MMC_HAS_IDLE_WAIT BIT(4)
-/* BIT(5) is unused */
+/*
+ * Use the busy timeout feature. Probably all TMIO versions support it. Yet,
+ * we don't have documentation for old variants, so we enable only known good
+ * variants with this flag. Can be removed once all variants are known good.
+ */
+#define TMIO_MMC_USE_BUSY_TIMEOUT BIT(5)
/*
* Some controllers have CMD12 automatically
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index c079b932330f..01bba36545c5 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -60,6 +60,8 @@ struct mmc_ios {
#define MMC_TIMING_MMC_DDR52 8
#define MMC_TIMING_MMC_HS200 9
#define MMC_TIMING_MMC_HS400 10
+#define MMC_TIMING_SD_EXP 11
+#define MMC_TIMING_SD_EXP_1_2V 12
unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */
@@ -173,6 +175,9 @@ struct mmc_host_ops {
*/
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
+
+ /* Initialize an SD express card, mandatory for MMC_CAP2_SD_EXP. */
+ int (*init_sd_express)(struct mmc_host *host, struct mmc_ios *ios);
};
struct mmc_cqe_ops {
@@ -358,6 +363,8 @@ struct mmc_host {
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
MMC_CAP2_HS200_1_2V_SDR)
+#define MMC_CAP2_SD_EXP (1 << 7) /* SD express via PCIe */
+#define MMC_CAP2_SD_EXP_1_2V (1 << 8) /* SD express 1.2V */
#define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */
#define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */
#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index f895ccabbe29..6f155f99aa16 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -82,6 +82,7 @@
#define MS_OC_INT_EN (1 << 23)
#define SD_OC_INT_EN (1 << 22)
+#define RTSX_DUM_REG 0x1C
/*
* macros for easy use
@@ -658,6 +659,23 @@
#define PM_WAKE_EN 0x01
#define PM_CTRL4 0xFF47
+/* FW config info register */
+#define RTS5261_FW_CFG_INFO0 0xFF50
+#define RTS5261_FW_EXPRESS_TEST_MASK (0x01 << 0)
+#define RTS5261_FW_EA_MODE_MASK (0x01 << 5)
+#define RTS5261_FW_CFG0 0xFF54
+#define RTS5261_FW_ENTER_EXPRESS (0x01 << 0)
+
+#define RTS5261_FW_CFG1 0xFF55
+#define RTS5261_SYS_CLK_SEL_MCU_CLK (0x01 << 7)
+#define RTS5261_CRC_CLK_SEL_MCU_CLK (0x01 << 6)
+#define RTS5261_FAKE_MCU_CLOCK_GATING (0x01 << 5)
+#define RTS5261_MCU_BUS_SEL_MASK (0x01 << 4)
+#define RTS5261_MCU_CLOCK_SEL_MASK (0x03 << 2)
+#define RTS5261_MCU_CLOCK_SEL_16M (0x01 << 2)
+#define RTS5261_MCU_CLOCK_GATING (0x01 << 1)
+#define RTS5261_DRIVER_ENABLE_FW (0x01 << 0)
+
#define REG_CFG_OOBS_OFF_TIMER 0xFEA6
#define REG_CFG_OOBS_ON_TIMER 0xFEA7
#define REG_CFG_VCM_ON_TIMER 0xFEA8
@@ -701,6 +719,13 @@
#define RTS5260_DVCC_TUNE_MASK 0x70
#define RTS5260_DVCC_33 0x70
+/*RTS5261*/
+#define RTS5261_LDO1_CFG0 0xFF72
+#define RTS5261_LDO1_OCP_THD_MASK (0x07 << 5)
+#define RTS5261_LDO1_OCP_EN (0x01 << 4)
+#define RTS5261_LDO1_OCP_LMT_THD_MASK (0x03 << 2)
+#define RTS5261_LDO1_OCP_LMT_EN (0x01 << 1)
+
#define LDO_VCC_CFG1 0xFF73
#define LDO_VCC_REF_TUNE_MASK 0x30
#define LDO_VCC_REF_1V2 0x20
@@ -741,6 +766,8 @@
#define RTS5260_AUTOLOAD_CFG4 0xFF7F
#define RTS5260_MIMO_DISABLE 0x8A
+/*RTS5261*/
+#define RTS5261_AUX_CLK_16M_EN (1 << 5)
#define RTS5260_REG_GPIO_CTL0 0xFC1A
#define RTS5260_REG_GPIO_MASK 0x01
@@ -1193,6 +1220,7 @@ struct rtsx_pcr {
#define EXTRA_CAPS_MMC_HS200 (1 << 4)
#define EXTRA_CAPS_MMC_8BIT (1 << 5)
#define EXTRA_CAPS_NO_MMC (1 << 7)
+#define EXTRA_CAPS_SD_EXPRESS (1 << 8)
u32 extra_caps;
#define IC_VER_A 0
@@ -1247,6 +1275,8 @@ struct rtsx_pcr {
#define PCI_PID(pcr) ((pcr)->pci->device)
#define is_version(pcr, pid, ver) \
(CHK_PCI_PID(pcr, pid) && (pcr)->ic_version == (ver))
+#define is_version_higher_than(pcr, pid, ver) \
+ (CHK_PCI_PID(pcr, pid) && (pcr)->ic_version > (ver))
#define pcr_dbg(pcr, fmt, arg...) \
dev_dbg(&(pcr)->pci->dev, fmt, ##arg)