mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge tag 'mmc-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Decrease polling rate for erase/trim/discard
- Allow non-sleeping GPIOs for card detect
- Improve mmc block removal path
- Enable support for mmc_sw_reset() for SDIO cards
- Add mmc_sw_reset() to allow users to do a soft reset of the card
- Allow power delay to be tunable via DT
- Allow card detect debounce delay to be tunable via DT
- Enable new quirk to limit clock rate for Marvell 8887 chip
- Don't show eMMC RPMB and BOOT areas in /proc/partitions
- Add capability to avoid 3.3V signaling for fragile HWs
MMC host:
- Improve/fixup support for handle highmem pages
- Remove depends on HAS_DMA in case of platform dependency
- mvsdio: Enable support for erase/trim/discard
- rtsx_usb: Enable support for erase/trim/discard
- renesas_sdhi: Fix WP logic regressions
- renesas_sdhi: Add r8a77965 support
- renesas_sdhi: Add R8A77980 to whitelist
- meson: Add optional support for device reset
- meson: Add support for the Meson-AXG platform
- dw_mmc: Add new driver for BlueField DW variant
- mediatek: Add support for 64G DRAM DMA
- sunxi: Deploy runtime PM support
- jz4740: Add support for JZ4780
- jz4740: Enable support for DT based platforms
- sdhci: Various improvement to timeout handling
- sdhci: Disable support for HS200/HS400/UHS when no 1.8V support
- sdhci-omap: Add support for controller in k2g SoC
- sdhci-omap: Add workarounds for a couple of Erratas
- sdhci-omap: Enable support for generic sdhci DT properties
- sdhci-cadence: Re-send tune request to deal with errata
- sdhci-pci: Fix 3.3V voltage switch for some BYT-based Intel controllers
- sdhci-pci: Avoid 3.3V signaling on some NI 904x
- sdhci-esdhc-imx: Use watermark levels for PIO access
- sdhci-msm: Improve card detection handling
- sdhci-msm: Add support voltage pad switching"
* tag 'mmc-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (104 commits)
mmc: renesas_sdhi: really fix WP logic regressions
mmc: mvsdio: Enable MMC_CAP_ERASE
mmc: mvsdio: Respect card busy time out from mmc core
mmc: sdhci-msm: Remove NO_CARD_NO_RESET quirk
mmc: sunxi: Use ifdef rather than __maybe_unused
mmc: mxmmc: Use ifdef rather than __maybe_unused
mmc: mxmmc: include linux/highmem.h
mmc: sunxi: mark PM functions as __maybe_unused
mmc: Throttle calls to MMC_SEND_STATUS during mmc_do_erase()
mmc: au1xmmc: handle highmem pages
mmc: Allow non-sleeping GPIO cd
mmc: sdhci-*: Don't emit error msg if sdhci_add_host() fails
mmc: sd: Define name for default speed dtr
mmc: core: Move calls to ->prepare_hs400_tuning() closer to mmc code
mmc: sdhci-xenon: use match_string() helper
mmc: wbsd: handle highmem pages
mmc: ushc: handle highmem pages
mmc: mxcmmc: handle highmem pages
mmc: atmel-mci: use sg_copy_{from,to}_buffer
mmc: android-goldfish: use sg_copy_{from,to}_buffer
...
This commit is contained in:
@@ -12,6 +12,7 @@ Required properties:
|
||||
- "amlogic,meson-gxbb-mmc"
|
||||
- "amlogic,meson-gxl-mmc"
|
||||
- "amlogic,meson-gxm-mmc"
|
||||
- "amlogic,meson-axg-mmc"
|
||||
- clocks : A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
|
||||
- clock-names: Should contain the following:
|
||||
"core" - Main peripheral bus clock
|
||||
@@ -19,6 +20,7 @@ Required properties:
|
||||
"clkin1" - Other parent clock of internal mux
|
||||
The driver has an internal mux clock which switches between clkin0 and clkin1 depending on the
|
||||
clock rate requested by the MMC core.
|
||||
- resets : phandle of the internal reset line
|
||||
|
||||
Example:
|
||||
|
||||
@@ -29,4 +31,5 @@ Example:
|
||||
clocks = <&clkc CLKID_SD_EMMC_A>, <&xtal>, <&clkc CLKID_FCLK_DIV2>;
|
||||
clock-names = "core", "clkin0", "clkin1";
|
||||
pinctrl-0 = <&emmc_pins>;
|
||||
resets = <&reset RESET_SD_EMMC_A>;
|
||||
};
|
||||
|
||||
29
Documentation/devicetree/bindings/mmc/bluefield-dw-mshc.txt
Normal file
29
Documentation/devicetree/bindings/mmc/bluefield-dw-mshc.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
* Mellanox Bluefield SoC specific extensions to the Synopsys Designware
|
||||
Mobile Storage Host Controller
|
||||
|
||||
Read synopsys-dw-mshc.txt for more details
|
||||
|
||||
The Synopsys designware mobile storage host controller is used to interface
|
||||
a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
|
||||
differences between the core Synopsys dw mshc controller properties described
|
||||
by synopsys-dw-mshc.txt and the properties used by the Mellanox Bluefield SoC
|
||||
specific extensions to the Synopsys Designware Mobile Storage Host Controller.
|
||||
|
||||
Required Properties:
|
||||
|
||||
* compatible: should be one of the following.
|
||||
- "mellanox,bluefield-dw-mshc": for controllers with Mellanox Bluefield SoC
|
||||
specific extensions.
|
||||
|
||||
Example:
|
||||
|
||||
/* Mellanox Bluefield SoC MMC */
|
||||
mmc@6008000 {
|
||||
compatible = "mellanox,bluefield-dw-mshc";
|
||||
reg = <0x6008000 0x400>;
|
||||
interrupts = <32>;
|
||||
fifo-depth = <0x100>;
|
||||
clock-frequency = <24000000>;
|
||||
bus-width = <8>;
|
||||
cap-mmc-highspeed;
|
||||
};
|
||||
38
Documentation/devicetree/bindings/mmc/jz4740.txt
Normal file
38
Documentation/devicetree/bindings/mmc/jz4740.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
* Ingenic JZ47xx MMC controllers
|
||||
|
||||
This file documents the device tree properties used for the MMC controller in
|
||||
Ingenic JZ4740/JZ4780 SoCs. These are in addition to the core MMC properties
|
||||
described in mmc.txt.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
- "ingenic,jz4740-mmc" for the JZ4740
|
||||
- "ingenic,jz4780-mmc" for the JZ4780
|
||||
- reg: Should contain the MMC controller registers location and length.
|
||||
- interrupts: Should contain the interrupt specifier of the MMC controller.
|
||||
- clocks: Clock for the MMC controller.
|
||||
|
||||
Optional properties:
|
||||
- dmas: List of DMA specifiers with the controller specific format
|
||||
as described in the generic DMA client binding. A tx and rx
|
||||
specifier is required.
|
||||
- dma-names: RX and TX DMA request names.
|
||||
Should be "rx" and "tx", in that order.
|
||||
|
||||
For additional details on DMA client bindings see ../dma/dma.txt.
|
||||
|
||||
Example:
|
||||
|
||||
mmc0: mmc@13450000 {
|
||||
compatible = "ingenic,jz4780-mmc";
|
||||
reg = <0x13450000 0x1000>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <37>;
|
||||
|
||||
clocks = <&cgu JZ4780_CLK_MSC0>;
|
||||
clock-names = "mmc";
|
||||
|
||||
dmas = <&dma JZ4780_DMA_MSC0_RX 0xffffffff>, <&dma JZ4780_DMA_MSC0_TX 0xffffffff>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
@@ -19,6 +19,8 @@ Optional properties:
|
||||
- wp-gpios: Specify GPIOs for write protection, see gpio binding
|
||||
- cd-inverted: when present, polarity on the CD line is inverted. See the note
|
||||
below for the case, when a GPIO is used for the CD line
|
||||
- cd-debounce-delay-ms: Set delay time before detecting card after card insert interrupt.
|
||||
It's only valid when cd-gpios is present.
|
||||
- wp-inverted: when present, polarity on the WP line is inverted. See the note
|
||||
below for the case, when a GPIO is used for the WP line
|
||||
- disable-wp: When set no physical WP line is present. This property should
|
||||
@@ -56,6 +58,10 @@ Optional properties:
|
||||
- fixed-emmc-driver-type: for non-removable eMMC, enforce this driver type.
|
||||
The value <n> is the driver type as specified in the eMMC specification
|
||||
(table 206 in spec version 5.1).
|
||||
- post-power-on-delay-ms : It was invented for MMC pwrseq-simple which could
|
||||
be referred to mmc-pwrseq-simple.txt. But now it's reused as a tunable delay
|
||||
waiting for I/O signalling and card power supply to be stable, regardless of
|
||||
whether pwrseq-simple is used. Default to 10ms if no available.
|
||||
|
||||
*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"
|
||||
|
||||
@@ -4,7 +4,14 @@ Refer to mmc.txt for standard MMC bindings.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
|
||||
Should be "ti,k2g-sdhci" for K2G
|
||||
- ti,hwmods: Must be "mmc<n>", <n> is controller instance starting 1
|
||||
(Not required for K2G).
|
||||
- pinctrl-names: Should be subset of "default", "hs", "sdr12", "sdr25", "sdr50",
|
||||
"ddr50-rev11", "sdr104-rev11", "ddr50", "sdr104",
|
||||
"ddr_1_8v-rev11", "ddr_1_8v" or "ddr_3_3v", "hs200_1_8v-rev11",
|
||||
"hs200_1_8v",
|
||||
- pinctrl-<n> : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt
|
||||
|
||||
Example:
|
||||
mmc1: mmc@4809c000 {
|
||||
|
||||
@@ -26,6 +26,8 @@ Required properties:
|
||||
"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
|
||||
"renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
|
||||
"renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
|
||||
"renesas,sdhi-r8a77965" - SDHI IP on R8A77965 SoC
|
||||
"renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC
|
||||
"renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC
|
||||
"renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
|
||||
"renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
|
||||
|
||||
@@ -36,6 +36,28 @@
|
||||
clock-frequency = <48000000>;
|
||||
};
|
||||
|
||||
&mmc0 {
|
||||
status = "okay";
|
||||
|
||||
bus-width = <4>;
|
||||
max-frequency = <50000000>;
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pins_mmc0>;
|
||||
|
||||
cd-gpios = <&gpf 20 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
&mmc1 {
|
||||
status = "okay";
|
||||
|
||||
bus-width = <4>;
|
||||
max-frequency = <50000000>;
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pins_mmc1>;
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
|
||||
@@ -203,4 +225,16 @@
|
||||
groups = "nemc-cs6";
|
||||
bias-disable;
|
||||
};
|
||||
|
||||
pins_mmc0: mmc0 {
|
||||
function = "mmc0";
|
||||
groups = "mmc0-1bit-e", "mmc0-4bit-e";
|
||||
bias-disable;
|
||||
};
|
||||
|
||||
pins_mmc1: mmc1 {
|
||||
function = "mmc1";
|
||||
groups = "mmc1-1bit-d", "mmc1-4bit-d";
|
||||
bias-disable;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <dt-bindings/clock/jz4780-cgu.h>
|
||||
#include <dt-bindings/dma/jz4780-dma.h>
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
@@ -241,6 +242,57 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
dma: dma@13420000 {
|
||||
compatible = "ingenic,jz4780-dma";
|
||||
reg = <0x13420000 0x10000>;
|
||||
#dma-cells = <2>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <10>;
|
||||
|
||||
clocks = <&cgu JZ4780_CLK_PDMA>;
|
||||
};
|
||||
|
||||
mmc0: mmc@13450000 {
|
||||
compatible = "ingenic,jz4780-mmc";
|
||||
reg = <0x13450000 0x1000>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <37>;
|
||||
|
||||
clocks = <&cgu JZ4780_CLK_MSC0>;
|
||||
clock-names = "mmc";
|
||||
|
||||
cap-sd-highspeed;
|
||||
cap-mmc-highspeed;
|
||||
cap-sdio-irq;
|
||||
dmas = <&dma JZ4780_DMA_MSC0_RX 0xffffffff>,
|
||||
<&dma JZ4780_DMA_MSC0_TX 0xffffffff>;
|
||||
dma-names = "rx", "tx";
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mmc1: mmc@13460000 {
|
||||
compatible = "ingenic,jz4780-mmc";
|
||||
reg = <0x13460000 0x1000>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <36>;
|
||||
|
||||
clocks = <&cgu JZ4780_CLK_MSC1>;
|
||||
clock-names = "mmc";
|
||||
|
||||
cap-sd-highspeed;
|
||||
cap-mmc-highspeed;
|
||||
cap-sdio-irq;
|
||||
dmas = <&dma JZ4780_DMA_MSC1_RX 0xffffffff>,
|
||||
<&dma JZ4780_DMA_MSC1_TX 0xffffffff>;
|
||||
dma-names = "rx", "tx";
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
bch: bch@134d0000 {
|
||||
compatible = "ingenic,jz4780-bch";
|
||||
reg = <0x134d0000 0x10000>;
|
||||
|
||||
@@ -104,10 +104,14 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
# CONFIG_HID is not set
|
||||
# CONFIG_USB_SUPPORT is not set
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_JZ4740=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_JZ4740=y
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_JZ4780=y
|
||||
# CONFIG_IOMMU_SUPPORT is not set
|
||||
CONFIG_MEMORY=y
|
||||
CONFIG_EXT4_FS=y
|
||||
# CONFIG_DNOTIFY is not set
|
||||
CONFIG_PROC_KCORE=y
|
||||
# CONFIG_PROC_PAGE_MONITOR is not set
|
||||
|
||||
@@ -2351,7 +2351,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
||||
set_disk_ro(md->disk, md->read_only || default_ro);
|
||||
md->disk->flags = GENHD_FL_EXT_DEVT;
|
||||
if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
|
||||
md->disk->flags |= GENHD_FL_NO_PART_SCAN;
|
||||
md->disk->flags |= GENHD_FL_NO_PART_SCAN
|
||||
| GENHD_FL_SUPPRESS_PARTITION_INFO;
|
||||
|
||||
/*
|
||||
* As discussed on lkml, GENHD_FL_REMOVABLE should:
|
||||
@@ -2965,9 +2966,11 @@ static void mmc_blk_remove(struct mmc_card *card)
|
||||
mmc_blk_remove_debugfs(card, md);
|
||||
mmc_blk_remove_parts(card, md);
|
||||
pm_runtime_get_sync(&card->dev);
|
||||
mmc_claim_host(card->host);
|
||||
mmc_blk_part_switch(card, md->part_type);
|
||||
mmc_release_host(card->host);
|
||||
if (md->part_curr != md->part_type) {
|
||||
mmc_claim_host(card->host);
|
||||
mmc_blk_part_switch(card, md->part_type);
|
||||
mmc_release_host(card->host);
|
||||
}
|
||||
if (card->type != MMC_TYPE_SD_COMBO)
|
||||
pm_runtime_disable(&card->dev);
|
||||
pm_runtime_put_noidle(&card->dev);
|
||||
|
||||
@@ -149,6 +149,12 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
|
||||
card->quirks &= ~data;
|
||||
}
|
||||
|
||||
static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card,
|
||||
int data)
|
||||
{
|
||||
card->quirk_max_rate = data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quirk add/remove for MMC products.
|
||||
*/
|
||||
|
||||
@@ -50,9 +50,6 @@
|
||||
#include "sd_ops.h"
|
||||
#include "sdio_ops.h"
|
||||
|
||||
/* If the device is not responding */
|
||||
#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
|
||||
|
||||
/* The max erase timeout, used when host->max_busy_timeout isn't specified */
|
||||
#define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */
|
||||
|
||||
@@ -1484,6 +1481,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
|
||||
}
|
||||
|
||||
void mmc_set_initial_signal_voltage(struct mmc_host *host)
|
||||
{
|
||||
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
|
||||
if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
|
||||
else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
|
||||
else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
|
||||
}
|
||||
|
||||
int mmc_host_set_uhs_voltage(struct mmc_host *host)
|
||||
{
|
||||
u32 clock;
|
||||
@@ -1646,19 +1654,13 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
|
||||
/* Set initial state and call mmc_set_ios */
|
||||
mmc_set_initial_state(host);
|
||||
|
||||
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
|
||||
if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
|
||||
else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
|
||||
else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
|
||||
mmc_set_initial_signal_voltage(host);
|
||||
|
||||
/*
|
||||
* This delay should be sufficient to allow the power supply
|
||||
* to reach the minimum voltage.
|
||||
*/
|
||||
mmc_delay(10);
|
||||
mmc_delay(host->ios.power_delay_ms);
|
||||
|
||||
mmc_pwrseq_post_power_on(host);
|
||||
|
||||
@@ -1671,7 +1673,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
|
||||
* This delay must be at least 74 clock sizes, or 1 ms, or the
|
||||
* time required to reach a stable voltage.
|
||||
*/
|
||||
mmc_delay(10);
|
||||
mmc_delay(host->ios.power_delay_ms);
|
||||
}
|
||||
|
||||
void mmc_power_off(struct mmc_host *host)
|
||||
@@ -1967,6 +1969,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
unsigned int qty = 0, busy_timeout = 0;
|
||||
bool use_r1b_resp = false;
|
||||
unsigned long timeout;
|
||||
int loop_udelay=64, udelay_max=32768;
|
||||
int err;
|
||||
|
||||
mmc_retune_hold(card->host);
|
||||
@@ -2091,9 +2094,15 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
if ((cmd.resp[0] & R1_READY_FOR_DATA) &&
|
||||
R1_CURRENT_STATE(cmd.resp[0]) != R1_STATE_PRG)
|
||||
break;
|
||||
|
||||
usleep_range(loop_udelay, loop_udelay*2);
|
||||
if (loop_udelay < udelay_max)
|
||||
loop_udelay *= 2;
|
||||
} while (1);
|
||||
|
||||
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
|
||||
(R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
|
||||
out:
|
||||
mmc_retune_release(card->host);
|
||||
return err;
|
||||
@@ -2435,22 +2444,46 @@ int mmc_hw_reset(struct mmc_host *host)
|
||||
return -EINVAL;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) {
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) {
|
||||
mmc_bus_put(host);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = host->bus_ops->reset(host);
|
||||
ret = host->bus_ops->hw_reset(host);
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (ret)
|
||||
pr_warn("%s: tried to reset card, got error %d\n",
|
||||
pr_warn("%s: tried to HW reset card, got error %d\n",
|
||||
mmc_hostname(host), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_hw_reset);
|
||||
|
||||
int mmc_sw_reset(struct mmc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!host->card)
|
||||
return -EINVAL;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) {
|
||||
mmc_bus_put(host);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = host->bus_ops->sw_reset(host);
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (ret)
|
||||
pr_warn("%s: tried to SW reset card, got error %d\n",
|
||||
mmc_hostname(host), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_sw_reset);
|
||||
|
||||
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
|
||||
{
|
||||
host->f_init = freq;
|
||||
|
||||
@@ -32,7 +32,8 @@ struct mmc_bus_ops {
|
||||
int (*power_restore)(struct mmc_host *);
|
||||
int (*alive)(struct mmc_host *);
|
||||
int (*shutdown)(struct mmc_host *);
|
||||
int (*reset)(struct mmc_host *);
|
||||
int (*hw_reset)(struct mmc_host *);
|
||||
int (*sw_reset)(struct mmc_host *);
|
||||
};
|
||||
|
||||
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
|
||||
@@ -51,6 +52,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_host_set_uhs_voltage(struct mmc_host *host);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
void mmc_set_initial_signal_voltage(struct mmc_host *host);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
|
||||
|
||||
@@ -143,9 +143,6 @@ int mmc_retune(struct mmc_host *host)
|
||||
goto out;
|
||||
|
||||
return_to_hs400 = true;
|
||||
|
||||
if (host->ops->prepare_hs400_tuning)
|
||||
host->ops->prepare_hs400_tuning(host, &host->ios);
|
||||
}
|
||||
|
||||
err = mmc_execute_tuning(host->card);
|
||||
@@ -179,7 +176,7 @@ static void mmc_retune_timer(struct timer_list *t)
|
||||
int mmc_of_parse(struct mmc_host *host)
|
||||
{
|
||||
struct device *dev = host->parent;
|
||||
u32 bus_width, drv_type;
|
||||
u32 bus_width, drv_type, cd_debounce_delay_ms;
|
||||
int ret;
|
||||
bool cd_cap_invert, cd_gpio_invert = false;
|
||||
bool ro_cap_invert, ro_gpio_invert = false;
|
||||
@@ -230,11 +227,16 @@ int mmc_of_parse(struct mmc_host *host)
|
||||
} else {
|
||||
cd_cap_invert = device_property_read_bool(dev, "cd-inverted");
|
||||
|
||||
if (device_property_read_u32(dev, "cd-debounce-delay-ms",
|
||||
&cd_debounce_delay_ms))
|
||||
cd_debounce_delay_ms = 200;
|
||||
|
||||
if (device_property_read_bool(dev, "broken-cd"))
|
||||
host->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
ret = mmc_gpiod_request_cd(host, "cd", 0, true,
|
||||
0, &cd_gpio_invert);
|
||||
cd_debounce_delay_ms,
|
||||
&cd_gpio_invert);
|
||||
if (!ret)
|
||||
dev_info(host->parent, "Got CD GPIO\n");
|
||||
else if (ret != -ENOENT && ret != -ENOSYS)
|
||||
@@ -338,6 +340,9 @@ int mmc_of_parse(struct mmc_host *host)
|
||||
host->dsr_req = 0;
|
||||
}
|
||||
|
||||
device_property_read_u32(dev, "post-power-on-delay-ms",
|
||||
&host->ios.power_delay_ms);
|
||||
|
||||
return mmc_pwrseq_alloc(host);
|
||||
}
|
||||
|
||||
@@ -403,6 +408,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
||||
host->max_blk_count = PAGE_SIZE / 512;
|
||||
|
||||
host->fixed_drv_type = -EINVAL;
|
||||
host->ios.power_delay_ms = 10;
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
@@ -1282,6 +1282,10 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
|
||||
|
||||
mmc_set_bus_speed(card);
|
||||
|
||||
/* Prepare tuning for HS400 mode. */
|
||||
if (host->ops->prepare_hs400_tuning)
|
||||
host->ops->prepare_hs400_tuning(host, &host->ios);
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
@@ -1830,6 +1834,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
}
|
||||
}
|
||||
|
||||
if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
|
||||
host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
|
||||
pr_err("%s: Host failed to negotiate down from 3.3V\n",
|
||||
mmc_hostname(host));
|
||||
err = -EINVAL;
|
||||
goto free_card;
|
||||
}
|
||||
|
||||
if (!oldcard)
|
||||
host->card = card;
|
||||
|
||||
@@ -2117,7 +2129,7 @@ static int mmc_can_reset(struct mmc_card *card)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mmc_reset(struct mmc_host *host)
|
||||
static int _mmc_hw_reset(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_card *card = host->card;
|
||||
|
||||
@@ -2151,7 +2163,7 @@ static const struct mmc_bus_ops mmc_ops = {
|
||||
.runtime_resume = mmc_runtime_resume,
|
||||
.alive = mmc_alive,
|
||||
.shutdown = mmc_shutdown,
|
||||
.reset = mmc_reset,
|
||||
.hw_reset = _mmc_hw_reset,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -40,14 +40,18 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
|
||||
struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
|
||||
|
||||
if (!IS_ERR(reset_gpios)) {
|
||||
int i;
|
||||
int values[reset_gpios->ndescs];
|
||||
int i, *values;
|
||||
int nvalues = reset_gpios->ndescs;
|
||||
|
||||
for (i = 0; i < reset_gpios->ndescs; i++)
|
||||
values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL);
|
||||
if (!values)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nvalues; i++)
|
||||
values[i] = value;
|
||||
|
||||
gpiod_set_array_value_cansleep(
|
||||
reset_gpios->ndescs, reset_gpios->desc, values);
|
||||
gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values);
|
||||
kfree(values);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,9 @@ static const struct mmc_fixup sdio_fixup_methods[] = {
|
||||
SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0,
|
||||
add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING),
|
||||
|
||||
SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887WLAN,
|
||||
add_limit_rate_quirk, 150000000),
|
||||
|
||||
END_FIXUP
|
||||
};
|
||||
|
||||
|
||||
@@ -1058,6 +1058,14 @@ retry:
|
||||
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
|
||||
}
|
||||
}
|
||||
|
||||
if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
|
||||
host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
|
||||
pr_err("%s: Host failed to negotiate down from 3.3V\n",
|
||||
mmc_hostname(host));
|
||||
err = -EINVAL;
|
||||
goto free_card;
|
||||
}
|
||||
done:
|
||||
host->card = card;
|
||||
return 0;
|
||||
@@ -1214,7 +1222,7 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_sd_reset(struct mmc_host *host)
|
||||
static int mmc_sd_hw_reset(struct mmc_host *host)
|
||||
{
|
||||
mmc_power_cycle(host, host->card->ocr);
|
||||
return mmc_sd_init_card(host, host->card->ocr, host->card);
|
||||
@@ -1229,7 +1237,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
|
||||
.resume = mmc_sd_resume,
|
||||
.alive = mmc_sd_alive,
|
||||
.shutdown = mmc_sd_suspend,
|
||||
.reset = mmc_sd_reset,
|
||||
.hw_reset = mmc_sd_hw_reset,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -444,6 +444,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
unsigned int bus_speed, timing;
|
||||
int err;
|
||||
unsigned char speed;
|
||||
unsigned int max_rate;
|
||||
|
||||
/*
|
||||
* If the host doesn't support any of the UHS-I modes, fallback on
|
||||
@@ -500,9 +501,12 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
max_rate = min_not_zero(card->quirk_max_rate,
|
||||
card->sw_caps.uhs_max_dtr);
|
||||
|
||||
if (bus_speed) {
|
||||
mmc_set_timing(card->host, timing);
|
||||
mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
|
||||
mmc_set_clock(card->host, max_rate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -788,6 +792,14 @@ try_again:
|
||||
if (err)
|
||||
goto remove;
|
||||
}
|
||||
|
||||
if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
|
||||
host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
|
||||
pr_err("%s: Host failed to negotiate down from 3.3V\n",
|
||||
mmc_hostname(host));
|
||||
err = -EINVAL;
|
||||
goto remove;
|
||||
}
|
||||
finish:
|
||||
if (!oldcard)
|
||||
host->card = card;
|
||||
@@ -801,6 +813,22 @@ err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
mmc_send_if_cond(host, host->card->ocr);
|
||||
|
||||
ret = mmc_send_io_op_cond(host, 0, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mmc_sdio_init_card(host, host->card->ocr, host->card,
|
||||
powered_resume);
|
||||
}
|
||||
|
||||
/*
|
||||
* Host is being removed. Free up the current card.
|
||||
*/
|
||||
@@ -948,14 +976,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
|
||||
|
||||
/* No need to reinitialize powered-resumed nonremovable cards */
|
||||
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
mmc_send_if_cond(host, host->card->ocr);
|
||||
err = mmc_send_io_op_cond(host, 0, NULL);
|
||||
if (!err)
|
||||
err = mmc_sdio_init_card(host, host->card->ocr,
|
||||
host->card,
|
||||
mmc_card_keep_power(host));
|
||||
err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
|
||||
} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
|
||||
/* We may have switched to 1-bit mode during suspend */
|
||||
err = sdio_enable_4bit_bus(host->card);
|
||||
@@ -978,8 +999,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mmc_claim_host(host);
|
||||
|
||||
/*
|
||||
* Reset the card by performing the same steps that are taken by
|
||||
* mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
|
||||
@@ -997,20 +1016,12 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
|
||||
*
|
||||
*/
|
||||
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
mmc_send_if_cond(host, host->card->ocr);
|
||||
mmc_claim_host(host);
|
||||
|
||||
ret = mmc_send_io_op_cond(host, 0, NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
|
||||
mmc_card_keep_power(host));
|
||||
ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
|
||||
if (!ret && host->sdio_irqs)
|
||||
mmc_signal_sdio_irq(host);
|
||||
|
||||
out:
|
||||
mmc_release_host(host);
|
||||
|
||||
return ret;
|
||||
@@ -1039,12 +1050,24 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mmc_sdio_reset(struct mmc_host *host)
|
||||
static int mmc_sdio_hw_reset(struct mmc_host *host)
|
||||
{
|
||||
mmc_power_cycle(host, host->card->ocr);
|
||||
return mmc_sdio_power_restore(host);
|
||||
}
|
||||
|
||||
static int mmc_sdio_sw_reset(struct mmc_host *host)
|
||||
{
|
||||
mmc_set_clock(host, host->f_init);
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
|
||||
mmc_set_initial_state(host);
|
||||
mmc_set_initial_signal_voltage(host);
|
||||
|
||||
return mmc_sdio_reinit_card(host, 0);
|
||||
}
|
||||
|
||||
static const struct mmc_bus_ops mmc_sdio_ops = {
|
||||
.remove = mmc_sdio_remove,
|
||||
.detect = mmc_sdio_detect,
|
||||
@@ -1055,7 +1078,8 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
|
||||
.runtime_resume = mmc_sdio_runtime_resume,
|
||||
.power_restore = mmc_sdio_power_restore,
|
||||
.alive = mmc_sdio_alive,
|
||||
.reset = mmc_sdio_reset,
|
||||
.hw_reset = mmc_sdio_hw_reset,
|
||||
.sw_reset = mmc_sdio_sw_reset,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -28,15 +28,17 @@ struct mmc_gpio {
|
||||
irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
|
||||
char *ro_label;
|
||||
char cd_label[0];
|
||||
u32 cd_debounce_delay_ms;
|
||||
};
|
||||
|
||||
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
|
||||
{
|
||||
/* Schedule a card detection after a debounce timeout */
|
||||
struct mmc_host *host = dev_id;
|
||||
struct mmc_gpio *ctx = host->slot.handler_priv;
|
||||
|
||||
host->trigger_card_event = true;
|
||||
mmc_detect_change(host, msecs_to_jiffies(200));
|
||||
mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -49,6 +51,7 @@ int mmc_gpio_alloc(struct mmc_host *host)
|
||||
|
||||
if (ctx) {
|
||||
ctx->ro_label = ctx->cd_label + len;
|
||||
ctx->cd_debounce_delay_ms = 200;
|
||||
snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
|
||||
snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
|
||||
host->slot.handler_priv = ctx;
|
||||
@@ -76,15 +79,22 @@ EXPORT_SYMBOL(mmc_gpio_get_ro);
|
||||
int mmc_gpio_get_cd(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_gpio *ctx = host->slot.handler_priv;
|
||||
int cansleep;
|
||||
|
||||
if (!ctx || !ctx->cd_gpio)
|
||||
return -ENOSYS;
|
||||
|
||||
if (ctx->override_cd_active_level)
|
||||
return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^
|
||||
!!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
|
||||
cansleep = gpiod_cansleep(ctx->cd_gpio);
|
||||
if (ctx->override_cd_active_level) {
|
||||
int value = cansleep ?
|
||||
gpiod_get_raw_value_cansleep(ctx->cd_gpio) :
|
||||
gpiod_get_raw_value(ctx->cd_gpio);
|
||||
return !value ^ !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
|
||||
}
|
||||
|
||||
return gpiod_get_value_cansleep(ctx->cd_gpio);
|
||||
return cansleep ?
|
||||
gpiod_get_value_cansleep(ctx->cd_gpio) :
|
||||
gpiod_get_value(ctx->cd_gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_get_cd);
|
||||
|
||||
@@ -261,7 +271,7 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
|
||||
if (debounce) {
|
||||
ret = gpiod_set_debounce(desc, debounce);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ctx->cd_debounce_delay_ms = debounce;
|
||||
}
|
||||
|
||||
if (gpio_invert)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user