You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'mmc-updates-for-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC updates from Chris Ball: "MMC highlights for 3.15: Core: - CONFIG_MMC_UNSAFE_RESUME=y is now default behavior - DT bindings for SDHCI UHS, eMMC HS200, high-speed DDR, at 1.8/1.2V - Add GPIO descriptor based slot-gpio card detect API Drivers: - dw_mmc: Refactor SOCFPGA support as a variant inside dw_mmc-pltfm.c - mmci: Support HW busy detection on ux500 - omap: Support MMC_ERASE - omap_hsmmc: Support MMC_PM_KEEP_POWER, MMC_PM_WAKE_SDIO_IRQ, (a)cmd23 - rtsx: Support pre-req/post-req async - sdhci: Add support for Realtek RTS5250 controllers - sdhci-acpi: Add support for 80860F16, fix 80860F14/SDIO card detect - sdhci-msm: Add new driver for Qualcomm SDHCI chipset support - sdhci-pxav3: Add support for Marvell Armada 380 and 385 SoCs" * tag 'mmc-updates-for-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (102 commits) mmc: sdhci-acpi: Intel SDIO has broken card detect mmc: sdhci-pxav3: add support for the Armada 38x SDHCI controller mmc: sdhci-msm: Add platform_execute_tuning implementation mmc: sdhci-msm: Initial support for Qualcomm chipsets mmc: sdhci-msm: Qualcomm SDHCI binding documentation sdhci: only reprogram retuning timer when flag is set mmc: rename ARCH_BCM to ARCH_BCM_MOBILE mmc: sdhci: Allow for irq being shared mmc: sdhci-acpi: Add device id 80860F16 mmc: sdhci-acpi: Fix broken card detect for ACPI HID 80860F14 mmc: slot-gpio: Add GPIO descriptor based CD GPIO API mmc: slot-gpio: Split out CD IRQ request into a separate function mmc: slot-gpio: Record GPIO descriptors instead of GPIO numbers Revert "dts: socfpga: Add support for SD/MMC on the SOCFPGA platform" mmc: sdhci-spear: use generic card detection gpio support mmc: sdhci-spear: remove support for power gpio mmc: sdhci-spear: simplify resource handling mmc: sdhci-spear: fix platform_data usage mmc: sdhci-spear: fix error handling paths for DT mmc: sdhci-bcm-kona: fix build errors when built-in ...
This commit is contained in:
@@ -26,9 +26,18 @@ Optional properties:
|
||||
this system, even if the controller claims it is.
|
||||
- cap-sd-highspeed: SD high-speed timing is supported
|
||||
- cap-mmc-highspeed: MMC high-speed timing is supported
|
||||
- sd-uhs-sdr12: SD UHS SDR12 speed is supported
|
||||
- sd-uhs-sdr25: SD UHS SDR25 speed is supported
|
||||
- sd-uhs-sdr50: SD UHS SDR50 speed is supported
|
||||
- sd-uhs-sdr104: SD UHS SDR104 speed is supported
|
||||
- sd-uhs-ddr50: SD UHS DDR50 speed is supported
|
||||
- cap-power-off-card: powering off the card is safe
|
||||
- cap-sdio-irq: enable SDIO IRQ signalling on this interface
|
||||
- full-pwr-cycle: full power cycle of the card is supported
|
||||
- mmc-highspeed-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported
|
||||
- mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
|
||||
- mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
|
||||
- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
|
||||
|
||||
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
|
||||
polarity properties, we have to fix the meaning of the "normal" and "inverted"
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
* Qualcomm SDHCI controller (sdhci-msm)
|
||||
|
||||
This file documents differences between the core properties in mmc.txt
|
||||
and the properties used by the sdhci-msm driver.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain "qcom,sdhci-msm-v4".
|
||||
- reg: Base address and length of the register in the following order:
|
||||
- Host controller register map (required)
|
||||
- SD Core register map (required)
|
||||
- interrupts: Should contain an interrupt-specifiers for the interrupts:
|
||||
- Host controller interrupt (required)
|
||||
- pinctrl-names: Should contain only one value - "default".
|
||||
- pinctrl-0: Should specify pin control groups used for this controller.
|
||||
- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
|
||||
- clock-names: Should contain the following:
|
||||
"iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required)
|
||||
"core" - SDC MMC clock (MCLK) (required)
|
||||
"bus" - SDCC bus voter clock (optional)
|
||||
|
||||
Example:
|
||||
|
||||
sdhc_1: sdhci@f9824900 {
|
||||
compatible = "qcom,sdhci-msm-v4";
|
||||
reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
|
||||
interrupts = <0 123 0>;
|
||||
bus-width = <8>;
|
||||
non-removable;
|
||||
|
||||
vmmc = <&pm8941_l20>;
|
||||
vqmmc = <&pm8941_s3>;
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdc1_clk &sdc1_cmd &sdc1_data>;
|
||||
|
||||
clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>;
|
||||
clock-names = "core", "iface";
|
||||
};
|
||||
|
||||
sdhc_2: sdhci@f98a4900 {
|
||||
compatible = "qcom,sdhci-msm-v4";
|
||||
reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
|
||||
interrupts = <0 125 0>;
|
||||
bus-width = <4>;
|
||||
cd-gpios = <&msmgpio 62 0x1>;
|
||||
|
||||
vmmc = <&pm8941_l21>;
|
||||
vqmmc = <&pm8941_l13>;
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdc2_clk &sdc2_cmd &sdc2_data>;
|
||||
|
||||
clocks = <&gcc GCC_SDCC2_APPS_CLK>, <&gcc GCC_SDCC2_AHB_CLK>;
|
||||
clock-names = "core", "iface";
|
||||
};
|
||||
@@ -4,7 +4,14 @@ This file documents differences between the core properties in mmc.txt
|
||||
and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "mrvl,pxav2-mmc" or "mrvl,pxav3-mmc".
|
||||
- compatible: Should be "mrvl,pxav2-mmc", "mrvl,pxav3-mmc" or
|
||||
"marvell,armada-380-sdhci".
|
||||
- reg:
|
||||
* for "mrvl,pxav2-mmc" and "mrvl,pxav3-mmc", one register area for
|
||||
the SDHCI registers.
|
||||
* for "marvell,armada-380-sdhci", two register areas. The first one
|
||||
for the SDHCI registers themselves, and the second one for the
|
||||
AXI/Mbus bridge registers of the SDHCI unit.
|
||||
|
||||
Optional properties:
|
||||
- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
|
||||
@@ -19,3 +26,11 @@ sdhci@d4280800 {
|
||||
non-removable;
|
||||
mrvl,clk-delay-cycles = <31>;
|
||||
};
|
||||
|
||||
sdhci@d8000 {
|
||||
compatible = "marvell,armada-380-sdhci";
|
||||
reg = <0xd8000 0x1000>, <0xdc000 0x100>;
|
||||
interrupts = <0 25 0x4>;
|
||||
clocks = <&gateclk 17>;
|
||||
mrvl,clk-delay-cycles = <0x1F>;
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ Required properties:
|
||||
- compatible:
|
||||
Should be "ti,omap2-hsmmc", for OMAP2 controllers
|
||||
Should be "ti,omap3-hsmmc", for OMAP3 controllers
|
||||
Should be "ti,omap3-pre-es3-hsmmc" for OMAP3 controllers pre ES3.0
|
||||
Should be "ti,omap4-hsmmc", for OMAP4 controllers
|
||||
- ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
PBIAS internal regulator for SD card dual voltage i/o pads on OMAP SoCs.
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
- "ti,pbias-omap" for OMAP2, OMAP3, OMAP4, OMAP5, DRA7.
|
||||
- reg: pbias register offset from syscon base and size of pbias register.
|
||||
- syscon : phandle of the system control module
|
||||
- regulator-name : should be
|
||||
pbias_mmc_omap2430 for OMAP2430, OMAP3 SoCs
|
||||
pbias_sim_omap3 for OMAP3 SoCs
|
||||
pbias_mmc_omap4 for OMAP4 SoCs
|
||||
pbias_mmc_omap5 for OMAP5 and DRA7 SoC
|
||||
|
||||
Optional properties:
|
||||
- Any optional property defined in bindings/regulator/regulator.txt
|
||||
|
||||
Example:
|
||||
|
||||
pbias_regulator: pbias_regulator {
|
||||
compatible = "ti,pbias-omap";
|
||||
reg = <0 0x4>;
|
||||
syscon = <&omap5_padconf_global>;
|
||||
pbias_mmc_reg: pbias_mmc_omap5 {
|
||||
regulator-name = "pbias_mmc_omap5";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
};
|
||||
@@ -5930,6 +5930,7 @@ F: include/linux/mfd/
|
||||
|
||||
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
|
||||
M: Chris Ball <chris@printf.net>
|
||||
M: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
|
||||
S: Maintained
|
||||
|
||||
@@ -154,6 +154,22 @@
|
||||
ti,hwmods = "counter_32k";
|
||||
};
|
||||
|
||||
dra7_ctrl_general: tisyscon@4a002e00 {
|
||||
compatible = "syscon";
|
||||
reg = <0x4a002e00 0x7c>;
|
||||
};
|
||||
|
||||
pbias_regulator: pbias_regulator {
|
||||
compatible = "ti,pbias-omap";
|
||||
reg = <0 0x4>;
|
||||
syscon = <&dra7_ctrl_general>;
|
||||
pbias_mmc_reg: pbias_mmc_omap5 {
|
||||
regulator-name = "pbias_mmc_omap5";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
};
|
||||
};
|
||||
|
||||
dra7_pmx_core: pinmux@4a003400 {
|
||||
compatible = "pinctrl-single";
|
||||
reg = <0x4a003400 0x0464>;
|
||||
@@ -543,6 +559,7 @@
|
||||
dmas = <&sdma 61>, <&sdma 62>;
|
||||
dma-names = "tx", "rx";
|
||||
status = "disabled";
|
||||
pbias-supply = <&pbias_mmc_reg>;
|
||||
};
|
||||
|
||||
mmc2: mmc@480b4000 {
|
||||
|
||||
@@ -29,6 +29,22 @@
|
||||
pinctrl-single,function-mask = <0x3f>;
|
||||
};
|
||||
|
||||
omap2_scm_general: tisyscon@49002270 {
|
||||
compatible = "syscon";
|
||||
reg = <0x49002270 0x240>;
|
||||
};
|
||||
|
||||
pbias_regulator: pbias_regulator {
|
||||
compatible = "ti,pbias-omap";
|
||||
reg = <0x230 0x4>;
|
||||
syscon = <&omap2_scm_general>;
|
||||
pbias_mmc_reg: pbias_mmc_omap2430 {
|
||||
regulator-name = "pbias_mmc_omap2430";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio1: gpio@4900c000 {
|
||||
compatible = "ti,omap2-gpio";
|
||||
reg = <0x4900c000 0x200>;
|
||||
@@ -188,6 +204,7 @@
|
||||
ti,dual-volt;
|
||||
dmas = <&sdma 61>, <&sdma 62>;
|
||||
dma-names = "tx", "rx";
|
||||
pbias-supply = <&pbias_mmc_reg>;
|
||||
};
|
||||
|
||||
mmc2: mmc@480b4000 {
|
||||
|
||||
@@ -174,8 +174,20 @@
|
||||
};
|
||||
|
||||
&mmc1 {
|
||||
/* See 35xx errata 2.1.1.128 in SPRZ278F */
|
||||
compatible = "ti,omap3-pre-es3-hsmmc";
|
||||
vmmc-supply = <&vmmc1>;
|
||||
bus-width = <4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&mmc1_pins>;
|
||||
};
|
||||
|
||||
&mmc2 {
|
||||
status="disabled";
|
||||
};
|
||||
|
||||
&mmc3 {
|
||||
status="disabled";
|
||||
};
|
||||
|
||||
&omap3_pmx_core {
|
||||
@@ -209,6 +221,17 @@
|
||||
0x174 (PIN_OUTPUT | MUX_MODE0) /* hsusb0_stp.hsusb0_stp */
|
||||
>;
|
||||
};
|
||||
|
||||
mmc1_pins: pinmux_mmc1_pins {
|
||||
pinctrl-single,pins = <
|
||||
OMAP3_CORE1_IOPAD(0x2144, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.mmc1_clk */
|
||||
OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.mmc1_cmd */
|
||||
OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.mmc1_dat0 */
|
||||
OMAP3_CORE1_IOPAD(0x214A, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.mmc1_dat1 */
|
||||
OMAP3_CORE1_IOPAD(0x214C, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.mmc1_dat2 */
|
||||
OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.mmc1_dat3 */
|
||||
>;
|
||||
};
|
||||
};
|
||||
|
||||
&usb_otg_hs {
|
||||
|
||||
@@ -181,6 +181,22 @@
|
||||
pinctrl-single,function-mask = <0xff1f>;
|
||||
};
|
||||
|
||||
omap3_scm_general: tisyscon@48002270 {
|
||||
compatible = "syscon";
|
||||
reg = <0x48002270 0x2f0>;
|
||||
};
|
||||
|
||||
pbias_regulator: pbias_regulator {
|
||||
compatible = "ti,pbias-omap";
|
||||
reg = <0x2b0 0x4>;
|
||||
syscon = <&omap3_scm_general>;
|
||||
pbias_mmc_reg: pbias_mmc_omap2430 {
|
||||
regulator-name = "pbias_mmc_omap2430";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio1: gpio@48310000 {
|
||||
compatible = "ti,omap3-gpio";
|
||||
reg = <0x48310000 0x200>;
|
||||
@@ -395,6 +411,7 @@
|
||||
ti,dual-volt;
|
||||
dmas = <&sdma 61>, <&sdma 62>;
|
||||
dma-names = "tx", "rx";
|
||||
pbias-supply = <&pbias_mmc_reg>;
|
||||
};
|
||||
|
||||
mmc2: mmc@480b4000 {
|
||||
|
||||
@@ -191,6 +191,22 @@
|
||||
pinctrl-single,function-mask = <0x7fff>;
|
||||
};
|
||||
|
||||
omap4_padconf_global: tisyscon@4a1005a0 {
|
||||
compatible = "syscon";
|
||||
reg = <0x4a1005a0 0x170>;
|
||||
};
|
||||
|
||||
pbias_regulator: pbias_regulator {
|
||||
compatible = "ti,pbias-omap";
|
||||
reg = <0x60 0x4>;
|
||||
syscon = <&omap4_padconf_global>;
|
||||
pbias_mmc_reg: pbias_mmc_omap4 {
|
||||
regulator-name = "pbias_mmc_omap4";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
};
|
||||
};
|
||||
|
||||
sdma: dma-controller@4a056000 {
|
||||
compatible = "ti,omap4430-sdma";
|
||||
reg = <0x4a056000 0x1000>;
|
||||
@@ -427,6 +443,7 @@
|
||||
ti,needs-special-reset;
|
||||
dmas = <&sdma 61>, <&sdma 62>;
|
||||
dma-names = "tx", "rx";
|
||||
pbias-supply = <&pbias_mmc_reg>;
|
||||
};
|
||||
|
||||
mmc2: mmc@480b4000 {
|
||||
|
||||
@@ -198,6 +198,22 @@
|
||||
pinctrl-single,function-mask = <0x7fff>;
|
||||
};
|
||||
|
||||
omap5_padconf_global: tisyscon@4a002da0 {
|
||||
compatible = "syscon";
|
||||
reg = <0x4A002da0 0xec>;
|
||||
};
|
||||
|
||||
pbias_regulator: pbias_regulator {
|
||||
compatible = "ti,pbias-omap";
|
||||
reg = <0x60 0x4>;
|
||||
syscon = <&omap5_padconf_global>;
|
||||
pbias_mmc_reg: pbias_mmc_omap5 {
|
||||
regulator-name = "pbias_mmc_omap5";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
};
|
||||
};
|
||||
|
||||
sdma: dma-controller@4a056000 {
|
||||
compatible = "ti,omap4430-sdma";
|
||||
reg = <0x4a056000 0x1000>;
|
||||
@@ -480,6 +496,7 @@
|
||||
ti,needs-special-reset;
|
||||
dmas = <&sdma 61>, <&sdma 62>;
|
||||
dma-names = "tx", "rx";
|
||||
pbias-supply = <&pbias_mmc_reg>;
|
||||
};
|
||||
|
||||
mmc2: mmc@480b4000 {
|
||||
|
||||
@@ -170,6 +170,7 @@ CONFIG_DRA752_THERMAL=y
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_OMAP_WATCHDOG=y
|
||||
CONFIG_TWL4030_WATCHDOG=y
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MFD_PALMAS=y
|
||||
CONFIG_MFD_TPS65217=y
|
||||
CONFIG_MFD_TPS65910=y
|
||||
@@ -181,6 +182,7 @@ CONFIG_REGULATOR_TPS6507X=y
|
||||
CONFIG_REGULATOR_TPS65217=y
|
||||
CONFIG_REGULATOR_TPS65910=y
|
||||
CONFIG_REGULATOR_TWL4030=y
|
||||
CONFIG_REGULATOR_PBIAS=y
|
||||
CONFIG_FB=y
|
||||
CONFIG_FIRMWARE_EDID=y
|
||||
CONFIG_FB_MODE_HELPERS=y
|
||||
|
||||
+91
-41
@@ -338,58 +338,28 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
|
||||
int num_sg, bool read, int timeout)
|
||||
{
|
||||
struct completion trans_done;
|
||||
u8 dir;
|
||||
int err = 0, i, count;
|
||||
int err = 0, count;
|
||||
long timeleft;
|
||||
unsigned long flags;
|
||||
struct scatterlist *sg;
|
||||
enum dma_data_direction dma_dir;
|
||||
u32 val;
|
||||
dma_addr_t addr;
|
||||
unsigned int len;
|
||||
|
||||
dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg);
|
||||
|
||||
/* don't transfer data during abort processing */
|
||||
if (pcr->remove_pci)
|
||||
return -EINVAL;
|
||||
|
||||
if ((sglist == NULL) || (num_sg <= 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (read) {
|
||||
dir = DEVICE_TO_HOST;
|
||||
dma_dir = DMA_FROM_DEVICE;
|
||||
} else {
|
||||
dir = HOST_TO_DEVICE;
|
||||
dma_dir = DMA_TO_DEVICE;
|
||||
}
|
||||
|
||||
count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
|
||||
count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read);
|
||||
if (count < 1) {
|
||||
dev_err(&(pcr->pci->dev), "scatterlist map failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count);
|
||||
|
||||
val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
|
||||
pcr->sgi = 0;
|
||||
for_each_sg(sglist, sg, count, i) {
|
||||
addr = sg_dma_address(sg);
|
||||
len = sg_dma_len(sg);
|
||||
rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pcr->lock, flags);
|
||||
|
||||
pcr->done = &trans_done;
|
||||
pcr->trans_result = TRANS_NOT_READY;
|
||||
init_completion(&trans_done);
|
||||
rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
|
||||
rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
|
||||
|
||||
spin_unlock_irqrestore(&pcr->lock, flags);
|
||||
|
||||
rtsx_pci_dma_transfer(pcr, sglist, count, read);
|
||||
|
||||
timeleft = wait_for_completion_interruptible_timeout(
|
||||
&trans_done, msecs_to_jiffies(timeout));
|
||||
if (timeleft <= 0) {
|
||||
@@ -413,7 +383,7 @@ out:
|
||||
pcr->done = NULL;
|
||||
spin_unlock_irqrestore(&pcr->lock, flags);
|
||||
|
||||
dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
|
||||
rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read);
|
||||
|
||||
if ((err < 0) && (err != -ENODEV))
|
||||
rtsx_pci_stop_cmd(pcr);
|
||||
@@ -425,6 +395,73 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
|
||||
|
||||
int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
|
||||
int num_sg, bool read)
|
||||
{
|
||||
enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
|
||||
if (pcr->remove_pci)
|
||||
return -EINVAL;
|
||||
|
||||
if ((sglist == NULL) || num_sg < 1)
|
||||
return -EINVAL;
|
||||
|
||||
return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg);
|
||||
|
||||
int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
|
||||
int num_sg, bool read)
|
||||
{
|
||||
enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
|
||||
if (pcr->remove_pci)
|
||||
return -EINVAL;
|
||||
|
||||
if (sglist == NULL || num_sg < 1)
|
||||
return -EINVAL;
|
||||
|
||||
dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir);
|
||||
return num_sg;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg);
|
||||
|
||||
int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
|
||||
int sg_count, bool read)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
dma_addr_t addr;
|
||||
unsigned int len;
|
||||
int i;
|
||||
u32 val;
|
||||
u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE;
|
||||
unsigned long flags;
|
||||
|
||||
if (pcr->remove_pci)
|
||||
return -EINVAL;
|
||||
|
||||
if ((sglist == NULL) || (sg_count < 1))
|
||||
return -EINVAL;
|
||||
|
||||
val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
|
||||
pcr->sgi = 0;
|
||||
for_each_sg(sglist, sg, sg_count, i) {
|
||||
addr = sg_dma_address(sg);
|
||||
len = sg_dma_len(sg);
|
||||
rtsx_pci_add_sg_tbl(pcr, addr, len, i == sg_count - 1);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pcr->lock, flags);
|
||||
|
||||
rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
|
||||
rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
|
||||
|
||||
spin_unlock_irqrestore(&pcr->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer);
|
||||
|
||||
int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
|
||||
{
|
||||
int err;
|
||||
@@ -836,6 +873,8 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
|
||||
int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
|
||||
/* Clear interrupt flag */
|
||||
rtsx_pci_writel(pcr, RTSX_BIPR, int_reg);
|
||||
dev_dbg(&pcr->pci->dev, "=========== BIPR 0x%8x ==========\n", int_reg);
|
||||
|
||||
if ((int_reg & pcr->bier) == 0) {
|
||||
spin_unlock(&pcr->lock);
|
||||
return IRQ_NONE;
|
||||
@@ -866,17 +905,28 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
|
||||
if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
|
||||
if (int_reg & (TRANS_FAIL_INT | DELINK_INT))
|
||||
pcr->trans_result = TRANS_RESULT_FAIL;
|
||||
if (pcr->done)
|
||||
complete(pcr->done);
|
||||
} else if (int_reg & TRANS_OK_INT) {
|
||||
else if (int_reg & TRANS_OK_INT)
|
||||
pcr->trans_result = TRANS_RESULT_OK;
|
||||
if (pcr->done)
|
||||
complete(pcr->done);
|
||||
|
||||
if (pcr->done)
|
||||
complete(pcr->done);
|
||||
|
||||
if (int_reg & SD_EXIST) {
|
||||
struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
|
||||
if (slot && slot->done_transfer)
|
||||
slot->done_transfer(slot->p_dev);
|
||||
}
|
||||
|
||||
if (int_reg & MS_EXIST) {
|
||||
struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
|
||||
if (slot && slot->done_transfer)
|
||||
slot->done_transfer(slot->p_dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (pcr->card_inserted || pcr->card_removed)
|
||||
schedule_delayed_work(&pcr->carddet_work,
|
||||
msecs_to_jiffies(200));
|
||||
|
||||
+115
-66
@@ -415,8 +415,7 @@ static int ioctl_do_sanitize(struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!(mmc_can_sanitize(card) &&
|
||||
(card->host->caps2 & MMC_CAP2_SANITIZE))) {
|
||||
if (!mmc_can_sanitize(card)) {
|
||||
pr_warn("%s: %s - SANITIZE is not supported\n",
|
||||
mmc_hostname(card->host), __func__);
|
||||
err = -EOPNOTSUPP;
|
||||
@@ -722,19 +721,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
|
||||
return result;
|
||||
}
|
||||
|
||||
static int send_stop(struct mmc_card *card, u32 *status)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
int err;
|
||||
|
||||
cmd.opcode = MMC_STOP_TRANSMISSION;
|
||||
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, 5);
|
||||
if (err == 0)
|
||||
*status = cmd.resp[0];
|
||||
return err;
|
||||
}
|
||||
|
||||
static int get_card_status(struct mmc_card *card, u32 *status, int retries)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
@@ -750,6 +736,99 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
|
||||
bool hw_busy_detect, struct request *req, int *gen_err)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
int err = 0;
|
||||
u32 status;
|
||||
|
||||
do {
|
||||
err = get_card_status(card, &status, 5);
|
||||
if (err) {
|
||||
pr_err("%s: error %d requesting status\n",
|
||||
req->rq_disk->disk_name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (status & R1_ERROR) {
|
||||
pr_err("%s: %s: error sending status cmd, status %#x\n",
|
||||
req->rq_disk->disk_name, __func__, status);
|
||||
*gen_err = 1;
|
||||
}
|
||||
|
||||
/* We may rely on the host hw to handle busy detection.*/
|
||||
if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) &&
|
||||
hw_busy_detect)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Timeout if the device never becomes ready for data and never
|
||||
* leaves the program state.
|
||||
*/
|
||||
if (time_after(jiffies, timeout)) {
|
||||
pr_err("%s: Card stuck in programming state! %s %s\n",
|
||||
mmc_hostname(card->host),
|
||||
req->rq_disk->disk_name, __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some cards mishandle the status bits,
|
||||
* so make sure to check both the busy
|
||||
* indication and the card state.
|
||||
*/
|
||||
} while (!(status & R1_READY_FOR_DATA) ||
|
||||
(R1_CURRENT_STATE(status) == R1_STATE_PRG));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int send_stop(struct mmc_card *card, unsigned int timeout_ms,
|
||||
struct request *req, int *gen_err, u32 *stop_status)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
struct mmc_command cmd = {0};
|
||||
int err;
|
||||
bool use_r1b_resp = rq_data_dir(req) == WRITE;
|
||||
|
||||
/*
|
||||
* Normally we use R1B responses for WRITE, but in cases where the host
|
||||
* has specified a max_busy_timeout we need to validate it. A failure
|
||||
* means we need to prevent the host from doing hw busy detection, which
|
||||
* is done by converting to a R1 response instead.
|
||||
*/
|
||||
if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout))
|
||||
use_r1b_resp = false;
|
||||
|
||||
cmd.opcode = MMC_STOP_TRANSMISSION;
|
||||
if (use_r1b_resp) {
|
||||
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.busy_timeout = timeout_ms;
|
||||
} else {
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
|
||||
}
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 5);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*stop_status = cmd.resp[0];
|
||||
|
||||
/* No need to check card status in case of READ. */
|
||||
if (rq_data_dir(req) == READ)
|
||||
return 0;
|
||||
|
||||
if (!mmc_host_is_spi(host) &&
|
||||
(*stop_status & R1_ERROR)) {
|
||||
pr_err("%s: %s: general error sending stop command, resp %#x\n",
|
||||
req->rq_disk->disk_name, __func__, *stop_status);
|
||||
*gen_err = 1;
|
||||
}
|
||||
|
||||
return card_busy_detect(card, timeout_ms, use_r1b_resp, req, gen_err);
|
||||
}
|
||||
|
||||
#define ERR_NOMEDIUM 3
|
||||
#define ERR_RETRY 2
|
||||
#define ERR_ABORT 1
|
||||
@@ -866,26 +945,21 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
|
||||
*/
|
||||
if (R1_CURRENT_STATE(status) == R1_STATE_DATA ||
|
||||
R1_CURRENT_STATE(status) == R1_STATE_RCV) {
|
||||
err = send_stop(card, &stop_status);
|
||||
if (err)
|
||||
err = send_stop(card,
|
||||
DIV_ROUND_UP(brq->data.timeout_ns, 1000000),
|
||||
req, gen_err, &stop_status);
|
||||
if (err) {
|
||||
pr_err("%s: error %d sending stop command\n",
|
||||
req->rq_disk->disk_name, err);
|
||||
|
||||
/*
|
||||
* If the stop cmd also timed out, the card is probably
|
||||
* not present, so abort. Other errors are bad news too.
|
||||
*/
|
||||
if (err)
|
||||
/*
|
||||
* If the stop cmd also timed out, the card is probably
|
||||
* not present, so abort. Other errors are bad news too.
|
||||
*/
|
||||
return ERR_ABORT;
|
||||
}
|
||||
|
||||
if (stop_status & R1_CARD_ECC_FAILED)
|
||||
*ecc_err = 1;
|
||||
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ)
|
||||
if (stop_status & R1_ERROR) {
|
||||
pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n",
|
||||
req->rq_disk->disk_name, __func__,
|
||||
stop_status);
|
||||
*gen_err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for set block count errors */
|
||||
@@ -1157,8 +1231,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
|
||||
* program mode, which we have to wait for it to complete.
|
||||
*/
|
||||
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
|
||||
u32 status;
|
||||
unsigned long timeout;
|
||||
int err;
|
||||
|
||||
/* Check stop command response */
|
||||
if (brq->stop.resp[0] & R1_ERROR) {
|
||||
@@ -1168,39 +1241,10 @@ static int mmc_blk_err_check(struct mmc_card *card,
|
||||
gen_err = 1;
|
||||
}
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
|
||||
do {
|
||||
int err = get_card_status(card, &status, 5);
|
||||
if (err) {
|
||||
pr_err("%s: error %d requesting status\n",
|
||||
req->rq_disk->disk_name, err);
|
||||
return MMC_BLK_CMD_ERR;
|
||||
}
|
||||
|
||||
if (status & R1_ERROR) {
|
||||
pr_err("%s: %s: general error sending status command, card status %#x\n",
|
||||
req->rq_disk->disk_name, __func__,
|
||||
status);
|
||||
gen_err = 1;
|
||||
}
|
||||
|
||||
/* Timeout if the device never becomes ready for data
|
||||
* and never leaves the program state.
|
||||
*/
|
||||
if (time_after(jiffies, timeout)) {
|
||||
pr_err("%s: Card stuck in programming state!"\
|
||||
" %s %s\n", mmc_hostname(card->host),
|
||||
req->rq_disk->disk_name, __func__);
|
||||
|
||||
return MMC_BLK_CMD_ERR;
|
||||
}
|
||||
/*
|
||||
* Some cards mishandle the status bits,
|
||||
* so make sure to check both the busy
|
||||
* indication and the card state.
|
||||
*/
|
||||
} while (!(status & R1_READY_FOR_DATA) ||
|
||||
(R1_CURRENT_STATE(status) == R1_STATE_PRG));
|
||||
err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, false, req,
|
||||
&gen_err);
|
||||
if (err)
|
||||
return MMC_BLK_CMD_ERR;
|
||||
}
|
||||
|
||||
/* if general error occurs, retry the write operation. */
|
||||
@@ -1335,7 +1379,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
||||
brq->data.blksz = 512;
|
||||
brq->stop.opcode = MMC_STOP_TRANSMISSION;
|
||||
brq->stop.arg = 0;
|
||||
brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
|
||||
brq->data.blocks = blk_rq_sectors(req);
|
||||
|
||||
/*
|
||||
@@ -1378,9 +1421,15 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
||||
if (rq_data_dir(req) == READ) {
|
||||
brq->cmd.opcode = readcmd;
|
||||
brq->data.flags |= MMC_DATA_READ;
|
||||
if (brq->mrq.stop)
|
||||
brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |
|
||||
MMC_CMD_AC;
|
||||
} else {
|
||||
brq->cmd.opcode = writecmd;
|
||||
brq->data.flags |= MMC_DATA_WRITE;
|
||||
if (brq->mrq.stop)
|
||||
brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B |
|
||||
MMC_CMD_AC;
|
||||
}
|
||||
|
||||
if (do_rel_wr)
|
||||
|
||||
@@ -2,21 +2,6 @@
|
||||
# MMC core configuration
|
||||
#
|
||||
|
||||
config MMC_UNSAFE_RESUME
|
||||
bool "Assume MMC/SD cards are non-removable (DANGEROUS)"
|
||||
help
|
||||
If you say Y here, the MMC layer will assume that all cards
|
||||
stayed in their respective slots during the suspend. The
|
||||
normal behaviour is to remove them at suspend and
|
||||
redetecting them at resume. Breaking this assumption will
|
||||
in most cases result in data corruption.
|
||||
|
||||
This option is usually just for embedded systems which use
|
||||
a MMC/SD card for rootfs. Most people should say N here.
|
||||
|
||||
This option sets a default which can be overridden by the
|
||||
module parameter "removable=0" or "removable=1".
|
||||
|
||||
config MMC_CLKGATE
|
||||
bool "MMC host clock gating"
|
||||
help
|
||||
|
||||
+2
-10
@@ -185,24 +185,16 @@ static int mmc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct mmc_card *card = mmc_dev_to_card(dev);
|
||||
struct mmc_host *host = card->host;
|
||||
int ret = 0;
|
||||
|
||||
if (host->bus_ops->runtime_suspend)
|
||||
ret = host->bus_ops->runtime_suspend(host);
|
||||
|
||||
return ret;
|
||||
return host->bus_ops->runtime_suspend(host);
|
||||
}
|
||||
|
||||
static int mmc_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct mmc_card *card = mmc_dev_to_card(dev);
|
||||
struct mmc_host *host = card->host;
|
||||
int ret = 0;
|
||||
|
||||
if (host->bus_ops->runtime_resume)
|
||||
ret = host->bus_ops->runtime_resume(host);
|
||||
|
||||
return ret;
|
||||
return host->bus_ops->runtime_resume(host);
|
||||
}
|
||||
|
||||
static int mmc_runtime_idle(struct device *dev)
|
||||
|
||||
+15
-72
@@ -34,6 +34,7 @@
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/sd.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "bus.h"
|
||||
@@ -64,23 +65,6 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
|
||||
bool use_spi_crc = 1;
|
||||
module_param(use_spi_crc, bool, 0);
|
||||
|
||||
/*
|
||||
* We normally treat cards as removed during suspend if they are not
|
||||
* known to be on a non-removable bus, to avoid the risk of writing
|
||||
* back data to a different card after resume. Allow this to be
|
||||
* overridden if necessary.
|
||||
*/
|
||||
#ifdef CONFIG_MMC_UNSAFE_RESUME
|
||||
bool mmc_assume_removable;
|
||||
#else
|
||||
bool mmc_assume_removable = 1;
|
||||
#endif
|
||||
EXPORT_SYMBOL(mmc_assume_removable);
|
||||
module_param_named(removable, mmc_assume_removable, bool, 0644);
|
||||
MODULE_PARM_DESC(
|
||||
removable,
|
||||
"MMC/SD cards are removable and may be removed during suspend");
|
||||
|
||||
/*
|
||||
* Internal function. Schedule delayed work in the MMC work queue.
|
||||
*/
|
||||
@@ -302,7 +286,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
|
||||
}
|
||||
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true);
|
||||
EXT_CSD_BKOPS_START, 1, timeout,
|
||||
use_busy_signal, true, false);
|
||||
if (err) {
|
||||
pr_warn("%s: Error %d starting bkops\n",
|
||||
mmc_hostname(card->host), err);
|
||||
@@ -1950,7 +1935,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
cmd.opcode = MMC_ERASE;
|
||||
cmd.arg = arg;
|
||||
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
|
||||
cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, 0);
|
||||
if (err) {
|
||||
pr_err("mmc_erase: erase error %d, status %#x\n",
|
||||
@@ -2137,7 +2122,7 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
|
||||
y = 0;
|
||||
for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
|
||||
timeout = mmc_erase_timeout(card, arg, qty + x);
|
||||
if (timeout > host->max_discard_to)
|
||||
if (timeout > host->max_busy_timeout)
|
||||
break;
|
||||
if (timeout < last_timeout)
|
||||
break;
|
||||
@@ -2169,7 +2154,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
|
||||
struct mmc_host *host = card->host;
|
||||
unsigned int max_discard, max_trim;
|
||||
|
||||
if (!host->max_discard_to)
|
||||
if (!host->max_busy_timeout)
|
||||
return UINT_MAX;
|
||||
|
||||
/*
|
||||
@@ -2189,7 +2174,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
|
||||
max_discard = 0;
|
||||
}
|
||||
pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
|
||||
mmc_hostname(host), max_discard, host->max_discard_to);
|
||||
mmc_hostname(host), max_discard, host->max_busy_timeout);
|
||||
return max_discard;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_calc_max_discard);
|
||||
@@ -2248,9 +2233,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
|
||||
{
|
||||
struct mmc_card *card = host->card;
|
||||
|
||||
if (!host->bus_ops->power_restore)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -2352,7 +2334,7 @@ int _mmc_detect_card_removed(struct mmc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
|
||||
if (host->caps & MMC_CAP_NONREMOVABLE)
|
||||
return 0;
|
||||
|
||||
if (!host->card || mmc_card_removed(host->card))
|
||||
@@ -2435,7 +2417,7 @@ void mmc_rescan(struct work_struct *work)
|
||||
* if there is a _removable_ card registered, check whether it is
|
||||
* still present
|
||||
*/
|
||||
if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
|
||||
if (host->bus_ops && !host->bus_dead
|
||||
&& !(host->caps & MMC_CAP_NONREMOVABLE))
|
||||
host->bus_ops->detect(host);
|
||||
|
||||
@@ -2490,6 +2472,7 @@ void mmc_start_host(struct mmc_host *host)
|
||||
mmc_power_off(host);
|
||||
else
|
||||
mmc_power_up(host, host->ocr_avail);
|
||||
mmc_gpiod_request_cd_irq(host);
|
||||
_mmc_detect_change(host, 0, false);
|
||||
}
|
||||
|
||||
@@ -2501,6 +2484,8 @@ void mmc_stop_host(struct mmc_host *host)
|
||||
host->removed = 1;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
#endif
|
||||
if (host->slot.cd_irq >= 0)
|
||||
disable_irq(host->slot.cd_irq);
|
||||
|
||||
host->rescan_disable = 1;
|
||||
cancel_delayed_work_sync(&host->detect);
|
||||
@@ -2537,7 +2522,7 @@ int mmc_power_save_host(struct mmc_host *host)
|
||||
|
||||
mmc_bus_get(host);
|
||||
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
|
||||
if (!host->bus_ops || host->bus_dead) {
|
||||
mmc_bus_put(host);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2563,7 +2548,7 @@ int mmc_power_restore_host(struct mmc_host *host)
|
||||
|
||||
mmc_bus_get(host);
|
||||
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
|
||||
if (!host->bus_ops || host->bus_dead) {
|
||||
mmc_bus_put(host);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2582,12 +2567,8 @@ EXPORT_SYMBOL(mmc_power_restore_host);
|
||||
*/
|
||||
int mmc_flush_cache(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
int err = 0;
|
||||
|
||||
if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
|
||||
return err;
|
||||
|
||||
if (mmc_card_mmc(card) &&
|
||||
(card->ext_csd.cache_size > 0) &&
|
||||
(card->ext_csd.cache_ctrl & 1)) {
|
||||
@@ -2602,44 +2583,6 @@ int mmc_flush_cache(struct mmc_card *card)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_flush_cache);
|
||||
|
||||
/*
|
||||
* Turn the cache ON/OFF.
|
||||
* Turning the cache OFF shall trigger flushing of the data
|
||||
* to the non-volatile storage.
|
||||
* This function should be called with host claimed
|
||||
*/
|
||||
int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
||||
{
|
||||
struct mmc_card *card = host->card;
|
||||
unsigned int timeout;
|
||||
int err = 0;
|
||||
|
||||
if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
|
||||
mmc_card_is_removable(host))
|
||||
return err;
|
||||
|
||||
if (card && mmc_card_mmc(card) &&
|
||||
(card->ext_csd.cache_size > 0)) {
|
||||
enable = !!enable;
|
||||
|
||||
if (card->ext_csd.cache_ctrl ^ enable) {
|
||||
timeout = enable ? card->ext_csd.generic_cmd6_time : 0;
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_CACHE_CTRL, enable, timeout);
|
||||
if (err)
|
||||
pr_err("%s: cache %s error %d\n",
|
||||
mmc_hostname(card->host),
|
||||
enable ? "on" : "off",
|
||||
err);
|
||||
else
|
||||
card->ext_csd.cache_ctrl = enable;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_cache_ctrl);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/* Do the card removal on suspend if card is assumed removeable
|
||||
@@ -2668,7 +2611,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
|
||||
/* Validate prerequisites for suspend */
|
||||
if (host->bus_ops->pre_suspend)
|
||||
err = host->bus_ops->pre_suspend(host);
|
||||
if (!err && host->bus_ops->suspend)
|
||||
if (!err)
|
||||
break;
|
||||
|
||||
/* Calling bus_ops->remove() with a claimed host can deadlock */
|
||||
|
||||
@@ -419,6 +419,16 @@ int mmc_of_parse(struct mmc_host *host)
|
||||
host->caps |= MMC_CAP_SD_HIGHSPEED;
|
||||
if (of_find_property(np, "cap-mmc-highspeed", &len))
|
||||
host->caps |= MMC_CAP_MMC_HIGHSPEED;
|
||||
if (of_find_property(np, "sd-uhs-sdr12", &len))
|
||||
host->caps |= MMC_CAP_UHS_SDR12;
|
||||
if (of_find_property(np, "sd-uhs-sdr25", &len))
|
||||
host->caps |= MMC_CAP_UHS_SDR25;
|
||||
if (of_find_property(np, "sd-uhs-sdr50", &len))
|
||||
host->caps |= MMC_CAP_UHS_SDR50;
|
||||
if (of_find_property(np, "sd-uhs-sdr104", &len))
|
||||
host->caps |= MMC_CAP_UHS_SDR104;
|
||||
if (of_find_property(np, "sd-uhs-ddr50", &len))
|
||||
host->caps |= MMC_CAP_UHS_DDR50;
|
||||
if (of_find_property(np, "cap-power-off-card", &len))
|
||||
host->caps |= MMC_CAP_POWER_OFF_CARD;
|
||||
if (of_find_property(np, "cap-sdio-irq", &len))
|
||||
@@ -429,6 +439,14 @@ int mmc_of_parse(struct mmc_host *host)
|
||||
host->pm_caps |= MMC_PM_KEEP_POWER;
|
||||
if (of_find_property(np, "enable-sdio-wakeup", &len))
|
||||
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
|
||||
if (of_find_property(np, "mmc-ddr-1_8v", &len))
|
||||
host->caps |= MMC_CAP_1_8V_DDR;
|
||||
if (of_find_property(np, "mmc-ddr-1_2v", &len))
|
||||
host->caps |= MMC_CAP_1_2V_DDR;
|
||||
if (of_find_property(np, "mmc-hs200-1_8v", &len))
|
||||
host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
|
||||
if (of_find_property(np, "mmc-hs200-1_2v", &len))
|
||||
host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
+28
-37
@@ -856,8 +856,10 @@ static int mmc_select_hs200(struct mmc_card *card)
|
||||
|
||||
/* switch to HS200 mode if bus width set successfully */
|
||||
if (!err)
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, 2, 0);
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, 2,
|
||||
card->ext_csd.generic_cmd6_time,
|
||||
true, true, true);
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
@@ -1074,9 +1076,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
host->caps2 & MMC_CAP2_HS200)
|
||||
err = mmc_select_hs200(card);
|
||||
else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, 1,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, 1,
|
||||
card->ext_csd.generic_cmd6_time,
|
||||
true, true, true);
|
||||
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
@@ -1287,8 +1290,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
* If cache size is higher than 0, this indicates
|
||||
* the existence of cache and it can be turned on.
|
||||
*/
|
||||
if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
|
||||
card->ext_csd.cache_size > 0) {
|
||||
if (card->ext_csd.cache_size > 0) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_CACHE_CTRL, 1,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
@@ -1356,11 +1358,9 @@ static int mmc_sleep(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_card *card = host->card;
|
||||
unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
|
||||
int err;
|
||||
|
||||
if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
|
||||
return 0;
|
||||
|
||||
err = mmc_deselect_cards(host);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -1369,7 +1369,19 @@ static int mmc_sleep(struct mmc_host *host)
|
||||
cmd.arg = card->rca << 16;
|
||||
cmd.arg |= 1 << 15;
|
||||
|
||||
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
|
||||
/*
|
||||
* If the max_busy_timeout of the host is specified, validate it against
|
||||
* the sleep cmd timeout. A failure means we need to prevent the host
|
||||
* from doing hw busy detection, which is done by converting to a R1
|
||||
* response instead of a R1B.
|
||||
*/
|
||||
if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) {
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
} else {
|
||||
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.busy_timeout = timeout_ms;
|
||||
}
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -1380,8 +1392,8 @@ static int mmc_sleep(struct mmc_host *host)
|
||||
* SEND_STATUS command to poll the status because that command (and most
|
||||
* others) is invalid while the card sleeps.
|
||||
*/
|
||||
if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
|
||||
mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
|
||||
if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
|
||||
mmc_delay(timeout_ms);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1404,7 +1416,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
|
||||
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_POWER_OFF_NOTIFICATION,
|
||||
notify_type, timeout, true, false);
|
||||
notify_type, timeout, true, false, false);
|
||||
if (err)
|
||||
pr_err("%s: Power Off Notification timed out, %u\n",
|
||||
mmc_hostname(card->host), timeout);
|
||||
@@ -1484,7 +1496,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = mmc_cache_ctrl(host, 0);
|
||||
err = mmc_flush_cache(host->card);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@@ -1634,16 +1646,6 @@ static int mmc_power_restore(struct mmc_host *host)
|
||||
}
|
||||
|
||||
static const struct mmc_bus_ops mmc_ops = {
|
||||
.remove = mmc_remove,
|
||||
.detect = mmc_detect,
|
||||
.suspend = NULL,
|
||||
.resume = NULL,
|
||||
.power_restore = mmc_power_restore,
|
||||
.alive = mmc_alive,
|
||||
.shutdown = mmc_shutdown,
|
||||
};
|
||||
|
||||
static const struct mmc_bus_ops mmc_ops_unsafe = {
|
||||
.remove = mmc_remove,
|
||||
.detect = mmc_detect,
|
||||
.suspend = mmc_suspend,
|
||||
@@ -1655,17 +1657,6 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
|
||||
.shutdown = mmc_shutdown,
|
||||
};
|
||||
|
||||
static void mmc_attach_bus_ops(struct mmc_host *host)
|
||||
{
|
||||
const struct mmc_bus_ops *bus_ops;
|
||||
|
||||
if (!mmc_card_is_removable(host))
|
||||
bus_ops = &mmc_ops_unsafe;
|
||||
else
|
||||
bus_ops = &mmc_ops;
|
||||
mmc_attach_bus(host, bus_ops);
|
||||
}
|
||||
|
||||
/*
|
||||
* Starting point for MMC card init.
|
||||
*/
|
||||
@@ -1685,7 +1676,7 @@ int mmc_attach_mmc(struct mmc_host *host)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mmc_attach_bus_ops(host);
|
||||
mmc_attach_bus(host, &mmc_ops);
|
||||
if (host->ocr_avail_mmc)
|
||||
host->ocr_avail = host->ocr_avail_mmc;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user