1
0
Fork 0

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
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAlsWMJUXHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCkWhw/9GdsKWGAezGYcBC9fBKVbZgvl
 Mu7kTebyQy1N7kbIVD7sBz2ila1O2DhVI9SVS7lVhzFwrG4Hup0szb/mjEQgiOAi
 +S2EjKRD3+9sA612fi1uWY+2cXoQiwCHhFZsCS5deL4pYspebzuYRNO5vZD7QlN8
 vLHZ85yxBtMSiysDUTRm9MH2EXb9j6PfrHnVKj0ih112U/ip4PZVc7zHGBZq9zzy
 6WSUMYBe2d1jajJ6MS3gf5Vrp53mz2OLkxKRCtMgut7YOwLZ8biKVa3G69ruQTm8
 jqrMoNrZnhO3aT/1kassCE4ygoXewMZPhYq8k24PcaihR3o/tVI1dlb4Zz70cBb8
 AGAdmdzu1sDEzY6KkSVTZ5IaxQo9SNANste/O/LfsOxHWkWxBQ6H0EeqMdt+W7of
 A0zGKTQrcTFhxzA9OeX3aZwZhjcipQlf8TWnI5+ayPY/UKwMhvWNCTMQtTJAhqBh
 mS7Uk5qd7OSJZTzVYrfLZ2ZOQKhtMbD9lAza/9Ldy5j5QDscLmxmhLOP0yuKI2Zp
 92N3JPIGzfK4aKGCLKSA3KhYwuwaicwsXqfJV+cPz9fFtNs8WdHqyU+nslD0Oxm4
 v3QZKPJa3LWCezPvWGSSTGLEgOvJtLQtJBefX1Hm6sxLbY12aBgu/iNp5UckGlzW
 7zaWXtH8nzYlBKsXf/8=
 =MwCT
 -----END PGP SIGNATURE-----

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
  ...
hifive-unleashed-5.1
Linus Torvalds 2018-06-05 16:11:43 -07:00
commit f60342fac9
66 changed files with 1381 additions and 430 deletions

View File

@ -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>;
};

View 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;
};

View 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";
};

View File

@ -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"

View File

@ -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 {

View File

@ -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

View File

@ -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;
};
};

View File

@ -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>;

View File

@ -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

View File

@ -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);

View File

@ -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.
*/

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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,
};
/*

View File

@ -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);
}
}

View File

@ -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
};

View File

@ -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,
};
/*

View File

@ -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,
};

View File

@ -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)

View File

@ -345,11 +345,11 @@ config MMC_SDHCI_IPROC
If unsure, say N.
config MMC_MESON_GX
tristate "Amlogic S905/GX* SD/MMC Host Controller support"
tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support"
depends on ARCH_MESON && MMC
help
This selects support for the Amlogic SD/MMC Host Controller
found on the S905/GX* family of SoCs. This controller is
found on the S905/GX*/AXG family of SoCs. This controller is
MMC 5.1 compliant and supports SD, eMMC and SDIO interfaces.
If you have a controller with this interface, say Y here.
@ -358,7 +358,6 @@ config MMC_MESON_MX_SDIO
tristate "Amlogic Meson6/Meson8/Meson8b SD/MMC Host Controller support"
depends on ARCH_MESON || COMPILE_TEST
depends on COMMON_CLK
depends on HAS_DMA
depends on OF
help
This selects support for the SD/MMC Host Controller on
@ -401,7 +400,6 @@ config MMC_OMAP
config MMC_OMAP_HS
tristate "TI OMAP High Speed Multimedia Card Interface support"
depends on HAS_DMA
depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST
help
This selects the TI OMAP High Speed Multimedia card Interface.
@ -511,7 +509,6 @@ config MMC_DAVINCI
config MMC_GOLDFISH
tristate "goldfish qemu Multimedia Card Interface support"
depends on HAS_DMA
depends on GOLDFISH || COMPILE_TEST
help
This selects the Goldfish Multimedia card Interface emulation
@ -605,7 +602,7 @@ config MMC_SDHI
config MMC_SDHI_SYS_DMAC
tristate "DMA for SDHI SD/SDIO controllers using SYS-DMAC"
depends on MMC_SDHI && HAS_DMA
depends on MMC_SDHI
default MMC_SDHI if (SUPERH || ARM)
help
This provides DMA support for SDHI SD/SDIO controllers
@ -615,7 +612,7 @@ config MMC_SDHI_SYS_DMAC
config MMC_SDHI_INTERNAL_DMAC
tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
depends on ARM64 || COMPILE_TEST
depends on MMC_SDHI && HAS_DMA
depends on MMC_SDHI
default MMC_SDHI if ARM64
help
This provides DMA support for SDHI SD/SDIO controllers
@ -669,7 +666,6 @@ config MMC_CAVIUM_THUNDERX
config MMC_DW
tristate "Synopsys DesignWare Memory Card Interface"
depends on HAS_DMA
depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST
help
This selects support for the Synopsys DesignWare Mobile Storage IP
@ -690,6 +686,15 @@ config MMC_DW_PLTFM
If unsure, say Y.
config MMC_DW_BLUEFIELD
tristate "BlueField specific extensions for Synopsys DW Memory Card Interface"
depends on MMC_DW
select MMC_DW_PLTFM
help
This selects support for Mellanox BlueField SoC specific extensions to
the Synopsys DesignWare Memory Card Interface driver. Select this
option for platforms based on Mellanox BlueField SoC's.
config MMC_DW_EXYNOS
tristate "Exynos specific extensions for Synopsys DW Memory Card Interface"
depends on MMC_DW
@ -748,7 +753,6 @@ config MMC_DW_ZX
config MMC_SH_MMCIF
tristate "SuperH Internal MMCIF support"
depends on HAS_DMA
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
help
This selects the MMC Host Interface controller (MMCIF) found in various
@ -756,11 +760,12 @@ config MMC_SH_MMCIF
config MMC_JZ4740
tristate "JZ4740 SD/Multimedia Card Interface support"
depends on MACH_JZ4740
tristate "Ingenic JZ47xx SD/Multimedia Card Interface support"
depends on MACH_JZ4740 || MACH_JZ4780
help
This selects support for the SD/MMC controller on Ingenic JZ4740
SoCs.
This selects support for the SD/MMC controller on Ingenic
JZ4740, JZ4750, JZ4770 and JZ4780 SoCs.
If you have a board based on such a SoC and with a SD/MMC slot,
say Y or M here.
@ -868,7 +873,6 @@ config MMC_TOSHIBA_PCI
config MMC_BCM2835
tristate "Broadcom BCM2835 SDHOST MMC Controller support"
depends on ARCH_BCM2835 || COMPILE_TEST
depends on HAS_DMA
help
This selects the BCM2835 SDHOST MMC controller. If you have
a BCM2835 platform with SD or MMC devices, say Y or M here.

View File

@ -49,6 +49,7 @@ thunderx-mmc-objs := cavium.o cavium-thunderx.o
obj-$(CONFIG_MMC_CAVIUM_THUNDERX) += thunderx-mmc.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
obj-$(CONFIG_MMC_DW_BLUEFIELD) += dw_mmc-bluefield.o
obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o
obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o

View File

@ -217,8 +217,8 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
* We don't really have DMA, so we need
* to copy from our platform driver buffer
*/
uint8_t *dest = (uint8_t *)sg_virt(data->sg);
memcpy(dest, host->virt_base, data->sg->length);
sg_copy_to_buffer(data->sg, 1, host->virt_base,
data->sg->length);
}
host->data->bytes_xfered += data->sg->length;
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
@ -393,8 +393,8 @@ static void goldfish_mmc_prepare_data(struct goldfish_mmc_host *host,
* We don't really have DMA, so we need to copy to our
* platform driver buffer
*/
const uint8_t *src = (uint8_t *)sg_virt(data->sg);
memcpy(host->virt_base, src, data->sg->length);
sg_copy_from_buffer(data->sg, 1, host->virt_base,
data->sg->length);
}
}

View File

@ -1967,7 +1967,6 @@ static void atmci_tasklet_func(unsigned long priv)
static void atmci_read_data_pio(struct atmel_mci *host)
{
struct scatterlist *sg = host->sg;
void *buf = sg_virt(sg);
unsigned int offset = host->pio_offset;
struct mmc_data *data = host->data;
u32 value;
@ -1977,7 +1976,7 @@ static void atmci_read_data_pio(struct atmel_mci *host)
do {
value = atmci_readl(host, ATMCI_RDR);
if (likely(offset + 4 <= sg->length)) {
put_unaligned(value, (u32 *)(buf + offset));
sg_pcopy_to_buffer(sg, 1, &value, sizeof(u32), offset);
offset += 4;
nbytes += 4;
@ -1990,11 +1989,11 @@ static void atmci_read_data_pio(struct atmel_mci *host)
goto done;
offset = 0;
buf = sg_virt(sg);
}
} else {
unsigned int remaining = sg->length - offset;
memcpy(buf + offset, &value, remaining);
sg_pcopy_to_buffer(sg, 1, &value, remaining, offset);
nbytes += remaining;
flush_dcache_page(sg_page(sg));
@ -2004,8 +2003,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
goto done;
offset = 4 - remaining;
buf = sg_virt(sg);
memcpy(buf, (u8 *)&value + remaining, offset);
sg_pcopy_to_buffer(sg, 1, (u8 *)&value + remaining,
offset, 0);
nbytes += offset;
}
@ -2035,7 +2034,6 @@ done:
static void atmci_write_data_pio(struct atmel_mci *host)
{
struct scatterlist *sg = host->sg;
void *buf = sg_virt(sg);
unsigned int offset = host->pio_offset;
struct mmc_data *data = host->data;
u32 value;
@ -2044,7 +2042,7 @@ static void atmci_write_data_pio(struct atmel_mci *host)
do {
if (likely(offset + 4 <= sg->length)) {
value = get_unaligned((u32 *)(buf + offset));
sg_pcopy_from_buffer(sg, 1, &value, sizeof(u32), offset);
atmci_writel(host, ATMCI_TDR, value);
offset += 4;
@ -2056,13 +2054,12 @@ static void atmci_write_data_pio(struct atmel_mci *host)
goto done;
offset = 0;
buf = sg_virt(sg);
}
} else {
unsigned int remaining = sg->length - offset;
value = 0;
memcpy(&value, buf + offset, remaining);
sg_pcopy_from_buffer(sg, 1, &value, remaining, offset);
nbytes += remaining;
host->sg = sg = sg_next(sg);
@ -2073,8 +2070,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
}
offset = 4 - remaining;
buf = sg_virt(sg);
memcpy((u8 *)&value + remaining, buf, offset);
sg_pcopy_from_buffer(sg, 1, (u8 *)&value + remaining,
offset, 0);
atmci_writel(host, ATMCI_TDR, value);
nbytes += offset;
}

View File

@ -40,6 +40,7 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/highmem.h>
#include <linux/leds.h>
#include <linux/mmc/host.h>
#include <linux/slab.h>
@ -405,7 +406,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
/* This is the pointer to the data buffer */
sg = &data->sg[host->pio.index];
sg_ptr = sg_virt(sg) + host->pio.offset;
sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset;
/* This is the space left inside the buffer */
sg_len = data->sg[host->pio.index].length - host->pio.offset;
@ -421,11 +422,12 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
if (!(status & SD_STATUS_TH))
break;
val = *sg_ptr++;
val = sg_ptr[count];
__raw_writel((unsigned long)val, HOST_TXPORT(host));
wmb(); /* drain writebuffer */
}
kunmap_atomic(sg_ptr);
host->pio.len -= count;
host->pio.offset += count;
@ -462,7 +464,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
if (host->pio.index < host->dma.len) {
sg = &data->sg[host->pio.index];
sg_ptr = sg_virt(sg) + host->pio.offset;
sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset;
/* This is the space left inside the buffer */
sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
@ -501,8 +503,10 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
val = __raw_readl(HOST_RXPORT(host));
if (sg_ptr)
*sg_ptr++ = (unsigned char)(val & 0xFF);
sg_ptr[count] = (unsigned char)(val & 0xFF);
}
if (sg_ptr)
kunmap_atomic(sg_ptr);
host->pio.len -= count;
host->pio.offset += count;

View File

@ -1377,8 +1377,7 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int davinci_mmcsd_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mmc_davinci_host *host = platform_get_drvdata(pdev);
struct mmc_davinci_host *host = dev_get_drvdata(dev);
writel(0, host->base + DAVINCI_MMCIM);
mmc_davinci_reset_ctrl(host, 1);
@ -1389,8 +1388,7 @@ static int davinci_mmcsd_suspend(struct device *dev)
static int davinci_mmcsd_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mmc_davinci_host *host = platform_get_drvdata(pdev);
struct mmc_davinci_host *host = dev_get_drvdata(dev);
clk_enable(host->clk);
mmc_davinci_reset_ctrl(host, 0);

View File

@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 Mellanox Technologies.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include "dw_mmc.h"
#include "dw_mmc-pltfm.h"
#define UHS_REG_EXT_SAMPLE_MASK GENMASK(22, 16)
#define UHS_REG_EXT_DRIVE_MASK GENMASK(29, 23)
#define BLUEFIELD_UHS_REG_EXT_SAMPLE 2
#define BLUEFIELD_UHS_REG_EXT_DRIVE 4
static void dw_mci_bluefield_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
u32 reg;
/* Update the Drive and Sample fields in register UHS_REG_EXT. */
reg = mci_readl(host, UHS_REG_EXT);
reg &= ~UHS_REG_EXT_SAMPLE_MASK;
reg |= FIELD_PREP(UHS_REG_EXT_SAMPLE_MASK,
BLUEFIELD_UHS_REG_EXT_SAMPLE);
reg &= ~UHS_REG_EXT_DRIVE_MASK;
reg |= FIELD_PREP(UHS_REG_EXT_DRIVE_MASK, BLUEFIELD_UHS_REG_EXT_DRIVE);
mci_writel(host, UHS_REG_EXT, reg);
}
static const struct dw_mci_drv_data bluefield_drv_data = {
.set_ios = dw_mci_bluefield_set_ios
};
static const struct of_device_id dw_mci_bluefield_match[] = {
{ .compatible = "mellanox,bluefield-dw-mshc",
.data = &bluefield_drv_data },
{},
};
MODULE_DEVICE_TABLE(of, dw_mci_bluefield_match);
static int dw_mci_bluefield_probe(struct platform_device *pdev)
{
const struct dw_mci_drv_data *drv_data = NULL;
const struct of_device_id *match;
if (pdev->dev.of_node) {
match = of_match_node(dw_mci_bluefield_match,
pdev->dev.of_node);
drv_data = match->data;
}
return dw_mci_pltfm_register(pdev, drv_data);
}
static struct platform_driver dw_mci_bluefield_pltfm_driver = {
.probe = dw_mci_bluefield_probe,
.remove = dw_mci_pltfm_remove,
.driver = {
.name = "dwmmc_bluefield",
.of_match_table = dw_mci_bluefield_match,
.pm = &dw_mci_pltfm_pmops,
},
};
module_platform_driver(dw_mci_bluefield_pltfm_driver);
MODULE_DESCRIPTION("BlueField DW Multimedia Card driver");
MODULE_AUTHOR("Mellanox Technologies");
MODULE_LICENSE("GPL v2");

View File

@ -44,9 +44,8 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
* bus_hz = cclkin / RK3288_CLKGEN_DIV
* ios->clock = (div == 0) ? bus_hz : (bus_hz / (2 * div))
*
* Note: div can only be 0 or 1
* if DDR50 8bit mode(only emmc work in 8bit mode),
* div must be set 1
* Note: div can only be 0 or 1, but div must be set to 1 for eMMC
* DDR52 8-bit mode.
*/
if (ios->bus_width == MMC_BUS_WIDTH_8 &&
ios->timing == MMC_TIMING_MMC_DDR52)

View File

@ -1230,6 +1230,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
if (host->state == STATE_WAITING_CMD11_DONE)
sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
slot->mmc->actual_clock = 0;
if (!clock) {
mci_writel(host, CLKENA, 0);
mci_send_cmd(slot, sdmmc_cmd_bits, 0);
@ -1288,6 +1290,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
/* keep the last clock value that was requested from core */
slot->__clk_old = clock;
slot->mmc->actual_clock = div ? ((host->bus_hz / div) >> 1) :
host->bus_hz;
}
host->current_speed = clock;

View File

@ -1,5 +1,7 @@
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
* Copyright (C) 2013, Imagination Technologies
*
* JZ4740 SD/MMC controller driver
*
* This program is free software; you can redistribute it and/or modify it
@ -13,24 +15,25 @@
*
*/
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/scatterlist.h>
#include <linux/clk.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <asm/cacheflush.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <asm/mach-jz4740/dma.h>
#include <asm/mach-jz4740/jz4740_mmc.h>
@ -51,6 +54,7 @@
#define JZ_REG_MMC_RESP_FIFO 0x34
#define JZ_REG_MMC_RXFIFO 0x38
#define JZ_REG_MMC_TXFIFO 0x3C
#define JZ_REG_MMC_DMAC 0x44
#define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7)
#define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6)
@ -104,9 +108,17 @@
#define JZ_MMC_IRQ_PRG_DONE BIT(1)
#define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0)
#define JZ_MMC_DMAC_DMA_SEL BIT(1)
#define JZ_MMC_DMAC_DMA_EN BIT(0)
#define JZ_MMC_CLK_RATE 24000000
enum jz4740_mmc_version {
JZ_MMC_JZ4740,
JZ_MMC_JZ4750,
JZ_MMC_JZ4780,
};
enum jz4740_mmc_state {
JZ4740_MMC_STATE_READ_RESPONSE,
JZ4740_MMC_STATE_TRANSFER_DATA,
@ -125,6 +137,8 @@ struct jz4740_mmc_host {
struct jz4740_mmc_platform_data *pdata;
struct clk *clk;
enum jz4740_mmc_version version;
int irq;
int card_detect_irq;
@ -137,7 +151,7 @@ struct jz4740_mmc_host {
uint32_t cmdat;
uint16_t irq_mask;
uint32_t irq_mask;
spinlock_t lock;
@ -159,6 +173,32 @@ struct jz4740_mmc_host {
#define JZ4740_MMC_FIFO_HALF_SIZE 8
};
static void jz4740_mmc_write_irq_mask(struct jz4740_mmc_host *host,
uint32_t val)
{
if (host->version >= JZ_MMC_JZ4750)
return writel(val, host->base + JZ_REG_MMC_IMASK);
else
return writew(val, host->base + JZ_REG_MMC_IMASK);
}
static void jz4740_mmc_write_irq_reg(struct jz4740_mmc_host *host,
uint32_t val)
{
if (host->version >= JZ_MMC_JZ4780)
return writel(val, host->base + JZ_REG_MMC_IREG);
else
return writew(val, host->base + JZ_REG_MMC_IREG);
}
static uint32_t jz4740_mmc_read_irq_reg(struct jz4740_mmc_host *host)
{
if (host->version >= JZ_MMC_JZ4780)
return readl(host->base + JZ_REG_MMC_IREG);
else
return readw(host->base + JZ_REG_MMC_IREG);
}
/*----------------------------------------------------------------------------*/
/* DMA infrastructure */
@ -173,31 +213,23 @@ static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host)
static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
{
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
host->dma_tx = dma_request_channel(mask, NULL, host);
if (!host->dma_tx) {
host->dma_tx = dma_request_chan(mmc_dev(host->mmc), "tx");
if (IS_ERR(host->dma_tx)) {
dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n");
return -ENODEV;
return PTR_ERR(host->dma_tx);
}
host->dma_rx = dma_request_channel(mask, NULL, host);
if (!host->dma_rx) {
host->dma_rx = dma_request_chan(mmc_dev(host->mmc), "rx");
if (IS_ERR(host->dma_rx)) {
dev_err(mmc_dev(host->mmc), "Failed to get dma_rx channel\n");
goto free_master_write;
dma_release_channel(host->dma_tx);
return PTR_ERR(host->dma_rx);
}
/* Initialize DMA pre request cookie */
host->next_data.cookie = 1;
return 0;
free_master_write:
dma_release_channel(host->dma_tx);
return -ENODEV;
}
static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host,
@ -363,7 +395,7 @@ static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host,
else
host->irq_mask |= irq;
writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK);
jz4740_mmc_write_irq_mask(host, host->irq_mask);
spin_unlock_irqrestore(&host->lock, flags);
}
@ -415,10 +447,10 @@ static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host,
unsigned int irq)
{
unsigned int timeout = 0x800;
uint16_t status;
uint32_t status;
do {
status = readw(host->base + JZ_REG_MMC_IREG);
status = jz4740_mmc_read_irq_reg(host);
} while (!(status & irq) && --timeout);
if (timeout == 0) {
@ -518,7 +550,7 @@ static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host,
void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO;
uint32_t *buf;
uint32_t d;
uint16_t status;
uint32_t status;
size_t i, j;
unsigned int timeout;
@ -654,8 +686,25 @@ static void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
cmdat |= JZ_MMC_CMDAT_DATA_EN;
if (cmd->data->flags & MMC_DATA_WRITE)
cmdat |= JZ_MMC_CMDAT_WRITE;
if (host->use_dma)
cmdat |= JZ_MMC_CMDAT_DMA_EN;
if (host->use_dma) {
/*
* The 4780's MMC controller has integrated DMA ability
* in addition to being able to use the external DMA
* controller. It moves DMA control bits to a separate
* register. The DMA_SEL bit chooses the external
* controller over the integrated one. Earlier SoCs
* can only use the external controller, and have a
* single DMA enable bit in CMDAT.
*/
if (host->version >= JZ_MMC_JZ4780) {
writel(JZ_MMC_DMAC_DMA_EN | JZ_MMC_DMAC_DMA_SEL,
host->base + JZ_REG_MMC_DMAC);
} else {
cmdat |= JZ_MMC_CMDAT_DMA_EN;
}
} else if (host->version >= JZ_MMC_JZ4780) {
writel(0, host->base + JZ_REG_MMC_DMAC);
}
writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN);
writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB);
@ -736,7 +785,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
host->state = JZ4740_MMC_STATE_SEND_STOP;
break;
}
writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG);
jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_DATA_TRAN_DONE);
case JZ4740_MMC_STATE_SEND_STOP:
if (!req->stop)
@ -766,9 +815,10 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
{
struct jz4740_mmc_host *host = devid;
struct mmc_command *cmd = host->cmd;
uint16_t irq_reg, status, tmp;
uint32_t irq_reg, status, tmp;
irq_reg = readw(host->base + JZ_REG_MMC_IREG);
status = readl(host->base + JZ_REG_MMC_STATUS);
irq_reg = jz4740_mmc_read_irq_reg(host);
tmp = irq_reg;
irq_reg &= ~host->irq_mask;
@ -777,10 +827,10 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE);
if (tmp != irq_reg)
writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG);
jz4740_mmc_write_irq_reg(host, tmp & ~irq_reg);
if (irq_reg & JZ_MMC_IRQ_SDIO) {
writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG);
jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_SDIO);
mmc_signal_sdio_irq(host->mmc);
irq_reg &= ~JZ_MMC_IRQ_SDIO;
}
@ -789,8 +839,6 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
if (test_and_clear_bit(0, &host->waiting)) {
del_timer(&host->timeout_timer);
status = readl(host->base + JZ_REG_MMC_STATUS);
if (status & JZ_MMC_STATUS_TIMEOUT_RES) {
cmd->error = -ETIMEDOUT;
} else if (status & JZ_MMC_STATUS_CRC_RES_ERR) {
@ -803,7 +851,7 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
}
jz4740_mmc_set_irq_enabled(host, irq_reg, false);
writew(irq_reg, host->base + JZ_REG_MMC_IREG);
jz4740_mmc_write_irq_reg(host, irq_reg);
return IRQ_WAKE_THREAD;
}
@ -818,7 +866,7 @@ static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)
int real_rate;
jz4740_mmc_clock_disable(host);
clk_set_rate(host->clk, JZ_MMC_CLK_RATE);
clk_set_rate(host->clk, host->mmc->f_max);
real_rate = clk_get_rate(host->clk);
@ -837,9 +885,7 @@ static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
host->req = req;
writew(0xffff, host->base + JZ_REG_MMC_IREG);
writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
jz4740_mmc_write_irq_reg(host, ~0);
jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true);
host->state = JZ4740_MMC_STATE_READ_RESPONSE;
@ -857,7 +903,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_UP:
jz4740_mmc_reset(host);
if (gpio_is_valid(host->pdata->gpio_power))
if (host->pdata && gpio_is_valid(host->pdata->gpio_power))
gpio_set_value(host->pdata->gpio_power,
!host->pdata->power_active_low);
host->cmdat |= JZ_MMC_CMDAT_INIT;
@ -866,7 +912,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
case MMC_POWER_ON:
break;
default:
if (gpio_is_valid(host->pdata->gpio_power))
if (host->pdata && gpio_is_valid(host->pdata->gpio_power))
gpio_set_value(host->pdata->gpio_power,
host->pdata->power_active_low);
clk_disable_unprepare(host->clk);
@ -926,7 +972,7 @@ static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
struct platform_device *pdev)
{
struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev);
int ret = 0;
if (!pdata)
@ -955,7 +1001,7 @@ static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
static void jz4740_mmc_free_gpios(struct platform_device *pdev)
{
struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev);
if (!pdata)
return;
@ -964,14 +1010,22 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
gpio_free(pdata->gpio_power);
}
static const struct of_device_id jz4740_mmc_of_match[] = {
{ .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 },
{ .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 },
{},
};
MODULE_DEVICE_TABLE(of, jz4740_mmc_of_match);
static int jz4740_mmc_probe(struct platform_device* pdev)
{
int ret;
struct mmc_host *mmc;
struct jz4740_mmc_host *host;
const struct of_device_id *match;
struct jz4740_mmc_platform_data *pdata;
pdata = pdev->dev.platform_data;
pdata = dev_get_platdata(&pdev->dev);
mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev);
if (!mmc) {
@ -982,6 +1036,27 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
host = mmc_priv(mmc);
host->pdata = pdata;
match = of_match_device(jz4740_mmc_of_match, &pdev->dev);
if (match) {
host->version = (enum jz4740_mmc_version)match->data;
ret = mmc_of_parse(mmc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"could not parse of data: %d\n", ret);
goto err_free_host;
}
} else {
/* JZ4740 should be the only one using legacy probe */
host->version = JZ_MMC_JZ4740;
mmc->caps |= MMC_CAP_SDIO_IRQ;
if (!(pdata && pdata->data_1bit))
mmc->caps |= MMC_CAP_4_BIT_DATA;
ret = jz4740_mmc_request_gpios(mmc, pdev);
if (ret)
goto err_free_host;
}
host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0) {
ret = host->irq;
@ -1004,16 +1079,11 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
goto err_free_host;
}
ret = jz4740_mmc_request_gpios(mmc, pdev);
if (ret)
goto err_release_dma;
mmc->ops = &jz4740_mmc_ops;
mmc->f_min = JZ_MMC_CLK_RATE / 128;
mmc->f_max = JZ_MMC_CLK_RATE;
if (!mmc->f_max)
mmc->f_max = JZ_MMC_CLK_RATE;
mmc->f_min = mmc->f_max / 128;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA;
mmc->caps |= MMC_CAP_SDIO_IRQ;
mmc->max_blk_size = (1 << 10) - 1;
mmc->max_blk_count = (1 << 15) - 1;
@ -1025,7 +1095,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
host->mmc = mmc;
host->pdev = pdev;
spin_lock_init(&host->lock);
host->irq_mask = 0xffff;
host->irq_mask = ~0;
jz4740_mmc_reset(host);
ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0,
dev_name(&pdev->dev), host);
@ -1034,20 +1106,20 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
goto err_free_gpios;
}
jz4740_mmc_reset(host);
jz4740_mmc_clock_disable(host);
timer_setup(&host->timeout_timer, jz4740_mmc_timeout, 0);
host->use_dma = true;
if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0)
host->use_dma = false;
ret = jz4740_mmc_acquire_dma_channels(host);
if (ret == -EPROBE_DEFER)
goto err_free_irq;
host->use_dma = !ret;
platform_set_drvdata(pdev, host);
ret = mmc_add_host(mmc);
if (ret) {
dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret);
goto err_free_irq;
goto err_release_dma;
}
dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n");
@ -1057,13 +1129,13 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
return 0;
err_release_dma:
if (host->use_dma)
jz4740_mmc_release_dma_channels(host);
err_free_irq:
free_irq(host->irq, host);
err_free_gpios:
jz4740_mmc_free_gpios(pdev);
err_release_dma:
if (host->use_dma)
jz4740_mmc_release_dma_channels(host);
err_free_host:
mmc_free_host(mmc);
@ -1116,6 +1188,7 @@ static struct platform_driver jz4740_mmc_driver = {
.remove = jz4740_mmc_remove,
.driver = {
.name = "jz4740-mmc",
.of_match_table = of_match_ptr(jz4740_mmc_of_match),
.pm = JZ4740_MMC_PM_OPS,
},
};

View File

@ -35,6 +35,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/interrupt.h>
#include <linux/bitfield.h>
#include <linux/pinctrl/consumer.h>
@ -47,15 +48,29 @@
#define CLK_CORE_PHASE_MASK GENMASK(9, 8)
#define CLK_TX_PHASE_MASK GENMASK(11, 10)
#define CLK_RX_PHASE_MASK GENMASK(13, 12)
#define CLK_TX_DELAY_MASK GENMASK(19, 16)
#define CLK_RX_DELAY_MASK GENMASK(23, 20)
#define CLK_V2_TX_DELAY_MASK GENMASK(19, 16)
#define CLK_V2_RX_DELAY_MASK GENMASK(23, 20)
#define CLK_V2_ALWAYS_ON BIT(24)
#define CLK_V3_TX_DELAY_MASK GENMASK(21, 16)
#define CLK_V3_RX_DELAY_MASK GENMASK(27, 22)
#define CLK_V3_ALWAYS_ON BIT(28)
#define CLK_DELAY_STEP_PS 200
#define CLK_PHASE_STEP 30
#define CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP)
#define CLK_ALWAYS_ON BIT(24)
#define CLK_TX_DELAY_MASK(h) (h->data->tx_delay_mask)
#define CLK_RX_DELAY_MASK(h) (h->data->rx_delay_mask)
#define CLK_ALWAYS_ON(h) (h->data->always_on)
#define SD_EMMC_DELAY 0x4
#define SD_EMMC_ADJUST 0x8
#define SD_EMMC_DELAY1 0x4
#define SD_EMMC_DELAY2 0x8
#define SD_EMMC_V3_ADJUST 0xc
#define SD_EMMC_CALOUT 0x10
#define SD_EMMC_START 0x40
#define START_DESC_INIT BIT(0)
@ -122,6 +137,12 @@
#define MUX_CLK_NUM_PARENTS 2
struct meson_mmc_data {
unsigned int tx_delay_mask;
unsigned int rx_delay_mask;
unsigned int always_on;
};
struct sd_emmc_desc {
u32 cmd_cfg;
u32 cmd_arg;
@ -131,6 +152,7 @@ struct sd_emmc_desc {
struct meson_host {
struct device *dev;
struct meson_mmc_data *data;
struct mmc_host *mmc;
struct mmc_command *cmd;
@ -474,7 +496,7 @@ static int meson_mmc_clk_init(struct meson_host *host)
/* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
clk_reg = 0;
clk_reg |= CLK_ALWAYS_ON;
clk_reg |= CLK_ALWAYS_ON(host);
clk_reg |= CLK_DIV_MASK;
writel(clk_reg, host->regs + SD_EMMC_CLOCK);
@ -574,7 +596,7 @@ static int meson_mmc_clk_init(struct meson_host *host)
tx->reg = host->regs + SD_EMMC_CLOCK;
tx->phase_mask = CLK_TX_PHASE_MASK;
tx->delay_mask = CLK_TX_DELAY_MASK;
tx->delay_mask = CLK_TX_DELAY_MASK(host);
tx->delay_step_ps = CLK_DELAY_STEP_PS;
tx->hw.init = &init;
@ -597,7 +619,7 @@ static int meson_mmc_clk_init(struct meson_host *host)
rx->reg = host->regs + SD_EMMC_CLOCK;
rx->phase_mask = CLK_RX_PHASE_MASK;
rx->delay_mask = CLK_RX_DELAY_MASK;
rx->delay_mask = CLK_RX_DELAY_MASK(host);
rx->delay_step_ps = CLK_DELAY_STEP_PS;
rx->hw.init = &init;
@ -1184,6 +1206,21 @@ static int meson_mmc_probe(struct platform_device *pdev)
goto free_host;
}
host->data = (struct meson_mmc_data *)
of_device_get_match_data(&pdev->dev);
if (!host->data) {
ret = -EINVAL;
goto free_host;
}
ret = device_reset_optional(&pdev->dev);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "device reset failed: %d\n", ret);
return ret;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->regs)) {
@ -1315,11 +1352,24 @@ static int meson_mmc_remove(struct platform_device *pdev)
return 0;
}
static const struct meson_mmc_data meson_gx_data = {
.tx_delay_mask = CLK_V2_TX_DELAY_MASK,
.rx_delay_mask = CLK_V2_RX_DELAY_MASK,
.always_on = CLK_V2_ALWAYS_ON,
};
static const struct meson_mmc_data meson_axg_data = {
.tx_delay_mask = CLK_V3_TX_DELAY_MASK,
.rx_delay_mask = CLK_V3_RX_DELAY_MASK,
.always_on = CLK_V3_ALWAYS_ON,
};
static const struct of_device_id meson_mmc_of_match[] = {
{ .compatible = "amlogic,meson-gx-mmc", },
{ .compatible = "amlogic,meson-gxbb-mmc", },
{ .compatible = "amlogic,meson-gxl-mmc", },
{ .compatible = "amlogic,meson-gxm-mmc", },
{ .compatible = "amlogic,meson-gx-mmc", .data = &meson_gx_data },
{ .compatible = "amlogic,meson-gxbb-mmc", .data = &meson_gx_data },
{ .compatible = "amlogic,meson-gxl-mmc", .data = &meson_gx_data },
{ .compatible = "amlogic,meson-gxm-mmc", .data = &meson_gx_data },
{ .compatible = "amlogic,meson-axg-mmc", .data = &meson_axg_data },
{}
};
MODULE_DEVICE_TABLE(of, meson_mmc_of_match);
@ -1335,6 +1385,6 @@ static struct platform_driver meson_mmc_driver = {
module_platform_driver(meson_mmc_driver);
MODULE_DESCRIPTION("Amlogic S905*/GX* SD/eMMC driver");
MODULE_DESCRIPTION("Amlogic S905*/GX*/AXG SD/eMMC driver");
MODULE_AUTHOR("Kevin Hilman <khilman@baylibre.com>");
MODULE_LICENSE("GPL v2");

View File

@ -1253,15 +1253,12 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
struct sg_mapping_iter *sg_miter = &host->sg_miter;
struct variant_data *variant = host->variant;
void __iomem *base = host->base;
unsigned long flags;
u32 status;
status = readl(base + MMCISTATUS);
dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
local_irq_save(flags);
do {
unsigned int remain, len;
char *buffer;
@ -1301,8 +1298,6 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
sg_miter_stop(sg_miter);
local_irq_restore(flags);
/*
* If we have less than the fifo 'half-full' threshold to transfer,
* trigger a PIO interrupt as soon as any data is available.

View File

@ -19,6 +19,7 @@
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
@ -70,6 +71,7 @@
#define SDC_ADV_CFG0 0x64
#define EMMC_IOCON 0x7c
#define SDC_ACMD_RESP 0x80
#define DMA_SA_H4BIT 0x8c
#define MSDC_DMA_SA 0x90
#define MSDC_DMA_CTRL 0x98
#define MSDC_DMA_CFG 0x9c
@ -194,6 +196,9 @@
/* SDC_ADV_CFG0 mask */
#define SDC_RX_ENHANCE_EN (0x1 << 20) /* RW */
/* DMA_SA_H4BIT mask */
#define DMA_ADDR_HIGH_4BIT (0xf << 0) /* RW */
/* MSDC_DMA_CTRL mask */
#define MSDC_DMA_CTRL_START (0x1 << 0) /* W */
#define MSDC_DMA_CTRL_STOP (0x1 << 1) /* W */
@ -227,6 +232,7 @@
#define MSDC_PATCH_BIT2_CFGRESP (0x1 << 15) /* RW */
#define MSDC_PATCH_BIT2_CFGCRCSTS (0x1 << 28) /* RW */
#define MSDC_PB2_SUPPORT_64G (0x1 << 1) /* RW */
#define MSDC_PB2_RESPWAIT (0x3 << 2) /* RW */
#define MSDC_PB2_RESPSTSENSEL (0x7 << 16) /* RW */
#define MSDC_PB2_CRCSTSENSEL (0x7 << 29) /* RW */
@ -280,6 +286,8 @@ struct mt_gpdma_desc {
#define GPDMA_DESC_BDP (0x1 << 1)
#define GPDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */
#define GPDMA_DESC_INT (0x1 << 16)
#define GPDMA_DESC_NEXT_H4 (0xf << 24)
#define GPDMA_DESC_PTR_H4 (0xf << 28)
u32 next;
u32 ptr;
u32 gpd_data_len;
@ -296,6 +304,8 @@ struct mt_bdma_desc {
#define BDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */
#define BDMA_DESC_BLKPAD (0x1 << 17)
#define BDMA_DESC_DWPAD (0x1 << 18)
#define BDMA_DESC_NEXT_H4 (0xf << 24)
#define BDMA_DESC_PTR_H4 (0xf << 28)
u32 next;
u32 ptr;
u32 bd_data_len;
@ -334,6 +344,7 @@ struct mtk_mmc_compatible {
bool busy_check;
bool stop_clk_fix;
bool enhance_rx;
bool support_64g;
};
struct msdc_tune_para {
@ -403,6 +414,7 @@ static const struct mtk_mmc_compatible mt8135_compat = {
.busy_check = false,
.stop_clk_fix = false,
.enhance_rx = false,
.support_64g = false,
};
static const struct mtk_mmc_compatible mt8173_compat = {
@ -414,6 +426,7 @@ static const struct mtk_mmc_compatible mt8173_compat = {
.busy_check = false,
.stop_clk_fix = false,
.enhance_rx = false,
.support_64g = false,
};
static const struct mtk_mmc_compatible mt2701_compat = {
@ -425,6 +438,7 @@ static const struct mtk_mmc_compatible mt2701_compat = {
.busy_check = false,
.stop_clk_fix = false,
.enhance_rx = false,
.support_64g = false,
};
static const struct mtk_mmc_compatible mt2712_compat = {
@ -436,6 +450,7 @@ static const struct mtk_mmc_compatible mt2712_compat = {
.busy_check = true,
.stop_clk_fix = true,
.enhance_rx = true,
.support_64g = true,
};
static const struct mtk_mmc_compatible mt7622_compat = {
@ -447,6 +462,7 @@ static const struct mtk_mmc_compatible mt7622_compat = {
.busy_check = true,
.stop_clk_fix = true,
.enhance_rx = true,
.support_64g = false,
};
static const struct of_device_id msdc_of_ids[] = {
@ -556,7 +572,12 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
/* init bd */
bd[j].bd_info &= ~BDMA_DESC_BLKPAD;
bd[j].bd_info &= ~BDMA_DESC_DWPAD;
bd[j].ptr = (u32)dma_address;
bd[j].ptr = lower_32_bits(dma_address);
if (host->dev_comp->support_64g) {
bd[j].bd_info &= ~BDMA_DESC_PTR_H4;
bd[j].bd_info |= (upper_32_bits(dma_address) & 0xf)
<< 28;
}
bd[j].bd_data_len &= ~BDMA_DESC_BUFLEN;
bd[j].bd_data_len |= (dma_len & BDMA_DESC_BUFLEN);
@ -575,7 +596,10 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
dma_ctrl &= ~(MSDC_DMA_CTRL_BRUSTSZ | MSDC_DMA_CTRL_MODE);
dma_ctrl |= (MSDC_BURST_64B << 12 | 1 << 8);
writel_relaxed(dma_ctrl, host->base + MSDC_DMA_CTRL);
writel((u32)dma->gpd_addr, host->base + MSDC_DMA_SA);
if (host->dev_comp->support_64g)
sdr_set_field(host->base + DMA_SA_H4BIT, DMA_ADDR_HIGH_4BIT,
upper_32_bits(dma->gpd_addr) & 0xf);
writel(lower_32_bits(dma->gpd_addr), host->base + MSDC_DMA_SA);
}
static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq)
@ -1366,6 +1390,9 @@ static void msdc_init_hw(struct msdc_host *host)
MSDC_PATCH_BIT2_CFGCRCSTS);
}
if (host->dev_comp->support_64g)
sdr_set_bits(host->base + MSDC_PATCH_BIT2,
MSDC_PB2_SUPPORT_64G);
if (host->dev_comp->data_tune) {
sdr_set_bits(host->base + tune_reg,
MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL);
@ -1407,19 +1434,32 @@ static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma)
{
struct mt_gpdma_desc *gpd = dma->gpd;
struct mt_bdma_desc *bd = dma->bd;
dma_addr_t dma_addr;
int i;
memset(gpd, 0, sizeof(struct mt_gpdma_desc) * 2);
dma_addr = dma->gpd_addr + sizeof(struct mt_gpdma_desc);
gpd->gpd_info = GPDMA_DESC_BDP; /* hwo, cs, bd pointer */
gpd->ptr = (u32)dma->bd_addr; /* physical address */
/* gpd->next is must set for desc DMA
* That's why must alloc 2 gpd structure.
*/
gpd->next = (u32)dma->gpd_addr + sizeof(struct mt_gpdma_desc);
gpd->next = lower_32_bits(dma_addr);
if (host->dev_comp->support_64g)
gpd->gpd_info |= (upper_32_bits(dma_addr) & 0xf) << 24;
dma_addr = dma->bd_addr;
gpd->ptr = lower_32_bits(dma->bd_addr); /* physical address */
if (host->dev_comp->support_64g)
gpd->gpd_info |= (upper_32_bits(dma_addr) & 0xf) << 28;
memset(bd, 0, sizeof(struct mt_bdma_desc) * MAX_BD_NUM);
for (i = 0; i < (MAX_BD_NUM - 1); i++)
bd[i].next = (u32)dma->bd_addr + sizeof(*bd) * (i + 1);
for (i = 0; i < (MAX_BD_NUM - 1); i++) {
dma_addr = dma->bd_addr + sizeof(*bd) * (i + 1);
bd[i].next = lower_32_bits(dma_addr);
if (host->dev_comp->support_64g)
bd[i].bd_info |= (upper_32_bits(dma_addr) & 0xf) << 24;
}
}
static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@ -1820,7 +1860,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
struct mmc_host *mmc;
struct msdc_host *host;
struct resource *res;
const struct of_device_id *of_id;
int ret;
if (!pdev->dev.of_node) {
@ -1828,9 +1867,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
return -EINVAL;
}
of_id = of_match_node(msdc_of_ids, pdev->dev.of_node);
if (!of_id)
return -EINVAL;
/* Allocate MMC host for this device */
mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev);
if (!mmc)
@ -1899,7 +1935,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
msdc_of_property_parse(pdev, host);
host->dev = &pdev->dev;
host->dev_comp = of_id->data;
host->dev_comp = of_device_get_match_data(&pdev->dev);
host->mmc = mmc;
host->src_clk_freq = clk_get_rate(host->src_clk);
/* Set host parameters to mmc */
@ -1916,7 +1952,10 @@ static int msdc_drv_probe(struct platform_device *pdev)
mmc->max_blk_size = 2048;
mmc->max_req_size = 512 * 1024;
mmc->max_blk_count = mmc->max_req_size / 512;
host->dma_mask = DMA_BIT_MASK(32);
if (host->dev_comp->support_64g)
host->dma_mask = DMA_BIT_MASK(36);
else
host->dma_mask = DMA_BIT_MASK(32);
mmc_dev(mmc)->dma_mask = &host->dma_mask;
host->timeout_clks = 3 * 1048576;

View File

@ -143,6 +143,7 @@ static void mvsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
struct mmc_command *cmd = mrq->cmd;
u32 cmdreg = 0, xfer = 0, intr = 0;
unsigned long flags;
unsigned int timeout;
BUG_ON(host->mrq != NULL);
host->mrq = mrq;
@ -234,7 +235,8 @@ static void mvsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
mvsd_write(MVSD_ERR_INTR_EN, 0xffff);
mod_timer(&host->timer, jiffies + 5 * HZ);
timeout = cmd->busy_timeout ? cmd->busy_timeout : 5000;
mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout));
spin_unlock_irqrestore(&host->lock, flags);
}
@ -755,6 +757,8 @@ static int mvsd_probe(struct platform_device *pdev)
if (maxfreq)
mmc->f_max = maxfreq;
mmc->caps |= MMC_CAP_ERASE;
spin_lock_init(&host->lock);
host->base = devm_ioremap_resource(&pdev->dev, r);

View File

@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/highmem.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/blkdev.h>
@ -291,8 +292,10 @@ static void mxcmci_swap_buffers(struct mmc_data *data)
struct scatterlist *sg;
int i;
for_each_sg(data->sg, sg, data->sg_len, i)
buffer_swap32(sg_virt(sg), sg->length);
for_each_sg(data->sg, sg, data->sg_len, i) {
void *buf = kmap_atomic(sg_page(sg) + sg->offset;
buffer_swap32(buf, sg->length);
kunmap_atomic(buf);
}
#else
static inline void mxcmci_swap_buffers(struct mmc_data *data) {}
@ -609,6 +612,7 @@ static int mxcmci_transfer_data(struct mxcmci_host *host)
{
struct mmc_data *data = host->req->data;
struct scatterlist *sg;
void *buf;
int stat, i;
host->data = data;
@ -616,14 +620,18 @@ static int mxcmci_transfer_data(struct mxcmci_host *host)
if (data->flags & MMC_DATA_READ) {
for_each_sg(data->sg, sg, data->sg_len, i) {
stat = mxcmci_pull(host, sg_virt(sg), sg->length);
buf = kmap_atomic(sg_page(sg) + sg->offset);
stat = mxcmci_pull(host, buf, sg->length);
kunmap(buf);
if (stat)
return stat;
host->datasize += sg->length;
}
} else {
for_each_sg(data->sg, sg, data->sg_len, i) {
stat = mxcmci_push(host, sg_virt(sg), sg->length);
buf = kmap_atomic(sg_page(sg) + sg->offset);
stat = mxcmci_push(host, buf, sg->length);
kunmap(buf);
if (stat)
return stat;
host->datasize += sg->length;
@ -1206,7 +1214,8 @@ static int mxcmci_remove(struct platform_device *pdev)
return 0;
}
static int __maybe_unused mxcmci_suspend(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int mxcmci_suspend(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxcmci_host *host = mmc_priv(mmc);
@ -1216,7 +1225,7 @@ static int __maybe_unused mxcmci_suspend(struct device *dev)
return 0;
}
static int __maybe_unused mxcmci_resume(struct device *dev)
static int mxcmci_resume(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxcmci_host *host = mmc_priv(mmc);
@ -1232,6 +1241,7 @@ static int __maybe_unused mxcmci_resume(struct device *dev)
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);

View File

@ -28,6 +28,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/mfd/tmio.h>
#include <linux/sh_dma.h>
#include <linux/delay.h>
@ -534,6 +535,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
host->dma_ops = dma_ops;
/* For some SoC, we disable internal WP. GPIO may override this */
if (mmc_can_gpio_ro(host->mmc))
mmc_data->capabilities2 &= ~MMC_CAP2_NO_WRITE_PROTECT;
/* SDR speeds are only available on Gen2+ */
if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) {
/* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */

View File

@ -87,11 +87,12 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23,
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
.bus_shift = 2,
.scc_offset = 0x1000,
.taps = rcar_gen3_scc_taps,
.taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
/* Gen3 SDHI DMAC can handle 0xffffffff blk count, but seg = 1 */
/* DMAC can handle 0xffffffff blk count but only 1 segment */
.max_blk_count = 0xffffffff,
.max_segs = 1,
};
@ -157,38 +158,34 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
{
struct scatterlist *sg = host->sg_ptr;
u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
enum dma_data_direction dir;
int ret;
/* This DMAC cannot handle if sg_len is not 1 */
WARN_ON(host->sg_len > 1);
if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
mmc_get_dma_dir(data)))
goto force_pio;
/* This DMAC cannot handle if buffer is not 8-bytes alignment */
if (!IS_ALIGNED(sg->offset, 8))
if (!IS_ALIGNED(sg_dma_address(sg), 8)) {
dma_unmap_sg(&host->pdev->dev, sg, host->sg_len,
mmc_get_dma_dir(data));
goto force_pio;
}
if (data->flags & MMC_DATA_READ) {
dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
dir = DMA_FROM_DEVICE;
if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) &&
test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
goto force_pio;
} else {
dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
dir = DMA_TO_DEVICE;
}
ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir);
if (ret == 0)
goto force_pio;
renesas_sdhi_internal_dmac_enable_dma(host, true);
/* set dma parameters */
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
dtran_mode);
renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
sg->dma_address);
sg_dma_address(sg));
return;
@ -272,12 +269,17 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
* implementation as others may use a different implementation.
*/
static const struct soc_device_attribute gen3_soc_whitelist[] = {
/* specific ones */
{ .soc_id = "r8a7795", .revision = "ES1.*",
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
{ .soc_id = "r8a7795", .revision = "ES2.0" },
{ .soc_id = "r8a7796", .revision = "ES1.0",
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
{ .soc_id = "r8a77995", .revision = "ES1.0" },
/* generic ones */
{ .soc_id = "r8a7795" },
{ .soc_id = "r8a7796" },
{ .soc_id = "r8a77965" },
{ .soc_id = "r8a77980" },
{ .soc_id = "r8a77995" },
{ /* sentinel */ }
};

View File

@ -42,6 +42,7 @@ static const struct renesas_sdhi_of_data of_rz_compatible = {
static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
};
/* Definitions for sampling clocks */
@ -61,6 +62,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23,
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
.dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
.dma_rx_offset = 0x2000,
.scc_offset = 0x0300,
@ -81,6 +83,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23,
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
.bus_shift = 2,
.scc_offset = 0x1000,
.taps = rcar_gen3_scc_taps,

View File

@ -26,7 +26,6 @@
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/card.h>
#include <linux/scatterlist.h>
#include <linux/pm_runtime.h>
@ -343,7 +342,7 @@ static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host,
}
if (rsp_type == SD_RSP_TYPE_R1b)
timeout = 3000;
timeout = cmd->busy_timeout ? cmd->busy_timeout : 3000;
if (cmd->opcode == SD_SWITCH_VOLTAGE) {
err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
@ -839,17 +838,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
goto finish_detect_card;
}
/*
* Reject SDIO CMDs to speed up card identification
* since unsupported
*/
if (cmd->opcode == SD_IO_SEND_OP_COND ||
cmd->opcode == SD_IO_RW_DIRECT ||
cmd->opcode == SD_IO_RW_EXTENDED) {
cmd->error = -EINVAL;
goto finish;
}
mutex_lock(&ucr->dev_mutex);
mutex_lock(&host->host_mutex);
@ -1332,8 +1320,9 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
MMC_CAP_NEEDS_POLL;
mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE;
MMC_CAP_NEEDS_POLL | MMC_CAP_ERASE;
mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
MMC_CAP2_NO_SDIO;
mmc->max_current_330 = 400;
mmc->max_current_180 = 800;

View File

@ -284,10 +284,8 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
sdhci_bcm_kona_sd_init(host);
ret = sdhci_add_host(host);
if (ret) {
dev_err(dev, "Failed sdhci_add_host\n");
if (ret)
goto err_reset;
}
/* if device is eMMC, emulate card insert right here */
if (!mmc_card_is_removable(host->mmc)) {

View File

@ -253,6 +253,7 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
u32 tmp;
int i, ret;
if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
return -EINVAL;
@ -260,11 +261,24 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
tmp = readl(reg);
tmp &= ~SDHCI_CDNS_HRS06_TUNE;
tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
writel(tmp, reg);
return readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
0, 1);
/*
* Workaround for IP errata:
* The IP6116 SD/eMMC PHY design has a timing issue on receive data
* path. Send tune request twice.
*/
for (i = 0; i < 2; i++) {
tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
writel(tmp, reg);
ret = readl_poll_timeout(reg, tmp,
!(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
0, 1);
if (ret)
return ret;
}
return 0;
}
static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)

View File

@ -41,6 +41,12 @@
#define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8)
#define ESDHC_WTMK_LVL 0x44
#define ESDHC_WTMK_DEFAULT_VAL 0x10401040
#define ESDHC_WTMK_LVL_RD_WML_MASK 0x000000FF
#define ESDHC_WTMK_LVL_RD_WML_SHIFT 0
#define ESDHC_WTMK_LVL_WR_WML_MASK 0x00FF0000
#define ESDHC_WTMK_LVL_WR_WML_SHIFT 16
#define ESDHC_WTMK_LVL_WML_VAL_DEF 64
#define ESDHC_WTMK_LVL_WML_VAL_MAX 128
#define ESDHC_MIX_CTRL 0x48
#define ESDHC_MIX_CTRL_DDREN (1 << 3)
#define ESDHC_MIX_CTRL_AC23EN (1 << 7)
@ -516,6 +522,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
}
if (esdhc_is_usdhc(imx_data)) {
u32 wml;
u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
/* Swap AC23 bit */
if (val & SDHCI_TRNS_AUTO_CMD23) {
@ -524,6 +531,21 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
}
m = val | (m & ~ESDHC_MIX_CTRL_SDHCI_MASK);
writel(m, host->ioaddr + ESDHC_MIX_CTRL);
/* Set watermark levels for PIO access to maximum value
* (128 words) to accommodate full 512 bytes buffer.
* For DMA access restore the levels to default value.
*/
m = readl(host->ioaddr + ESDHC_WTMK_LVL);
if (val & SDHCI_TRNS_DMA)
wml = ESDHC_WTMK_LVL_WML_VAL_DEF;
else
wml = ESDHC_WTMK_LVL_WML_VAL_MAX;
m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK |
ESDHC_WTMK_LVL_WR_WML_MASK);
m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) |
(wml << ESDHC_WTMK_LVL_WR_WML_SHIFT);
writel(m, host->ioaddr + ESDHC_WTMK_LVL);
} else {
/*
* Postpone this write, we must do it together with a

View File

@ -21,6 +21,7 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/iopoll.h>
#include <linux/regulator/consumer.h>
#include "sdhci-pltfm.h"
@ -77,10 +78,16 @@
#define CORE_HC_MCLK_SEL_DFLT (2 << 8)
#define CORE_HC_MCLK_SEL_HS400 (3 << 8)
#define CORE_HC_MCLK_SEL_MASK (3 << 8)
#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15)
#define CORE_IO_PAD_PWR_SWITCH (1 << 16)
#define CORE_HC_SELECT_IN_EN BIT(18)
#define CORE_HC_SELECT_IN_HS400 (6 << 19)
#define CORE_HC_SELECT_IN_MASK (7 << 19)
#define CORE_3_0V_SUPPORT (1 << 25)
#define CORE_1_8V_SUPPORT (1 << 26)
#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT)
#define CORE_CSR_CDC_CTLR_CFG0 0x130
#define CORE_SW_TRIG_FULL_CALIB BIT(16)
#define CORE_HW_AUTOCAL_ENA BIT(17)
@ -148,6 +155,7 @@ struct sdhci_msm_host {
u32 curr_io_level;
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
u32 caps_0;
};
static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@ -1103,8 +1111,8 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0;
int retry = 10;
int pwr_state = 0, io_level = 0;
u32 pwr_state = 0, io_level = 0;
u32 config;
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
irq_status &= INT_MASK;
@ -1161,6 +1169,38 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
*/
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
/*
* If we don't have info regarding the voltage levels supported by
* regulators, don't change the IO PAD PWR SWITCH.
*/
if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
u32 new_config;
/*
* We should unset IO PAD PWR switch only if the register write
* can set IO lines high and the regulator also switches to 3 V.
* Else, we should keep the IO PAD PWR switch set.
* This is applicable to certain targets where eMMC vccq supply
* is only 1.8V. In such targets, even during REQ_IO_HIGH, the
* IO PAD PWR switch must be kept set to reflect actual
* regulator voltage. This way, during initialization of
* controllers with only 1.8V, we will set the IO PAD bit
* without waiting for a REQ_IO_LOW.
*/
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
new_config = config;
if ((io_level & REQ_IO_HIGH) &&
(msm_host->caps_0 & CORE_3_0V_SUPPORT))
new_config &= ~CORE_IO_PAD_PWR_SWITCH;
else if ((io_level & REQ_IO_LOW) ||
(msm_host->caps_0 & CORE_1_8V_SUPPORT))
new_config |= CORE_IO_PAD_PWR_SWITCH;
if (config ^ new_config)
writel_relaxed(new_config,
host->ioaddr + CORE_VENDOR_SPEC);
}
if (pwr_state)
msm_host->curr_pwr_state = pwr_state;
if (io_level)
@ -1313,6 +1353,45 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
sdhci_msm_check_power_status(host, req_type);
}
static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host)
{
struct mmc_host *mmc = msm_host->mmc;
struct regulator *supply = mmc->supply.vqmmc;
u32 caps = 0, config;
struct sdhci_host *host = mmc_priv(mmc);
if (!IS_ERR(mmc->supply.vqmmc)) {
if (regulator_is_supported_voltage(supply, 1700000, 1950000))
caps |= CORE_1_8V_SUPPORT;
if (regulator_is_supported_voltage(supply, 2700000, 3600000))
caps |= CORE_3_0V_SUPPORT;
if (!caps)
pr_warn("%s: 1.8/3V not supported for vqmmc\n",
mmc_hostname(mmc));
}
if (caps) {
/*
* Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH
* bit can be used as required later on.
*/
u32 io_level = msm_host->curr_io_level;
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
config |= CORE_IO_PAD_PWR_SWITCH_EN;
if ((io_level & REQ_IO_HIGH) && (caps & CORE_3_0V_SUPPORT))
config &= ~CORE_IO_PAD_PWR_SWITCH;
else if ((io_level & REQ_IO_LOW) || (caps & CORE_1_8V_SUPPORT))
config |= CORE_IO_PAD_PWR_SWITCH;
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
}
msm_host->caps_0 |= caps;
pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
}
static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@ -1333,7 +1412,6 @@ static const struct sdhci_ops sdhci_msm_ops = {
static const struct sdhci_pltfm_data sdhci_msm_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_NO_CARD_NO_RESET |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
@ -1530,6 +1608,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret)
goto pm_runtime_disable;
sdhci_msm_set_regulator_caps(msm_host);
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);

View File

@ -290,7 +290,8 @@ static const struct sdhci_pltfm_data sdhci_arasan_pdata = {
.ops = &sdhci_arasan_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC,
};
static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
@ -359,8 +360,7 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
*/
static int sdhci_arasan_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
int ret;
@ -403,8 +403,7 @@ static int sdhci_arasan_suspend(struct device *dev)
*/
static int sdhci_arasan_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
int ret;

View File

@ -26,6 +26,7 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/sys_soc.h>
#include "sdhci-pltfm.h"
@ -35,6 +36,7 @@
#define CON_DDR BIT(19)
#define CON_CLKEXTFREE BIT(16)
#define CON_PADEN BIT(15)
#define CON_CTPL BIT(11)
#define CON_INIT BIT(1)
#define CON_OD BIT(0)
@ -100,6 +102,7 @@ struct sdhci_omap_data {
};
struct sdhci_omap_host {
char *version;
void __iomem *base;
struct device *dev;
struct regulator *pbias;
@ -224,6 +227,23 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
}
}
static void sdhci_omap_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
u32 reg;
reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
if (enable)
reg |= (CON_CTPL | CON_CLKEXTFREE);
else
reg &= ~(CON_CTPL | CON_CLKEXTFREE);
sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
sdhci_enable_sdio_irq(mmc, enable);
}
static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host,
int count)
{
@ -713,10 +733,15 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = {
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN |
SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_RSP_136_HAS_CRC,
SDHCI_QUIRK2_RSP_136_HAS_CRC |
SDHCI_QUIRK2_DISABLE_HW_TIMEOUT,
.ops = &sdhci_omap_ops,
};
static const struct sdhci_omap_data k2g_data = {
.offset = 0x200,
};
static const struct sdhci_omap_data dra7_data = {
.offset = 0x200,
.flags = SDHCI_OMAP_REQUIRE_IODELAY,
@ -724,6 +749,7 @@ static const struct sdhci_omap_data dra7_data = {
static const struct of_device_id omap_sdhci_match[] = {
{ .compatible = "ti,dra7-sdhci", .data = &dra7_data },
{ .compatible = "ti,k2g-sdhci", .data = &k2g_data },
{},
};
MODULE_DEVICE_TABLE(of, omap_sdhci_match);
@ -733,12 +759,21 @@ static struct pinctrl_state
u32 *caps, u32 capmask)
{
struct device *dev = omap_host->dev;
char *version = omap_host->version;
struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV);
char str[20];
if (!(*caps & capmask))
goto ret;
pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode);
if (version) {
snprintf(str, 20, "%s-%s", mode, version);
pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, str);
}
if (IS_ERR(pinctrl_state))
pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode);
if (IS_ERR(pinctrl_state)) {
dev_err(dev, "no pinctrl state for %s mode", mode);
*caps &= ~capmask;
@ -807,8 +842,15 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host
state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_1_8v", caps,
MMC_CAP_1_8V_DDR);
if (!IS_ERR(state))
if (!IS_ERR(state)) {
pinctrl_state[MMC_TIMING_MMC_DDR52] = state;
} else {
state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_3_3v",
caps,
MMC_CAP_3_3V_DDR);
if (!IS_ERR(state))
pinctrl_state[MMC_TIMING_MMC_DDR52] = state;
}
state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps,
MMC_CAP_SD_HIGHSPEED);
@ -830,6 +872,16 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host
return 0;
}
static const struct soc_device_attribute sdhci_omap_soc_devices[] = {
{
.machine = "DRA7[45]*",
.revision = "ES1.[01]",
},
{
/* sentinel */
}
};
static int sdhci_omap_probe(struct platform_device *pdev)
{
int ret;
@ -841,6 +893,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
struct mmc_host *mmc;
const struct of_device_id *match;
struct sdhci_omap_data *data;
const struct soc_device_attribute *soc;
match = of_match_device(omap_sdhci_match, dev);
if (!match)
@ -871,10 +924,22 @@ static int sdhci_omap_probe(struct platform_device *pdev)
host->ioaddr += offset;
mmc = host->mmc;
sdhci_get_of_property(pdev);
ret = mmc_of_parse(mmc);
if (ret)
goto err_pltfm_free;
soc = soc_device_match(sdhci_omap_soc_devices);
if (soc) {
omap_host->version = "rev11";
if (!strcmp(dev_name(dev), "4809c000.mmc"))
mmc->f_max = 96000000;
if (!strcmp(dev_name(dev), "480b4000.mmc"))
mmc->f_max = 48000000;
if (!strcmp(dev_name(dev), "480ad000.mmc"))
mmc->f_max = 48000000;
}
pltfm_host->clk = devm_clk_get(dev, "fck");
if (IS_ERR(pltfm_host->clk)) {
ret = PTR_ERR(pltfm_host->clk);
@ -916,26 +981,31 @@ static int sdhci_omap_probe(struct platform_device *pdev)
goto err_put_sync;
}
ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host);
if (ret)
goto err_put_sync;
host->mmc_host_ops.get_ro = mmc_gpio_get_ro;
host->mmc_host_ops.start_signal_voltage_switch =
sdhci_omap_start_signal_voltage_switch;
host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq;
sdhci_read_caps(host);
host->caps |= SDHCI_CAN_DO_ADMA2;
ret = sdhci_add_host(host);
ret = sdhci_setup_host(host);
if (ret)
goto err_put_sync;
ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host);
if (ret)
goto err_cleanup_host;
ret = __sdhci_add_host(host);
if (ret)
goto err_cleanup_host;
return 0;
err_cleanup_host:
sdhci_cleanup_host(host);
err_put_sync:
pm_runtime_put_sync(dev);

View File

@ -453,6 +453,7 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
enum {
INTEL_DSM_FNS = 0,
INTEL_DSM_V18_SWITCH = 3,
INTEL_DSM_V33_SWITCH = 4,
INTEL_DSM_DRV_STRENGTH = 9,
INTEL_DSM_D3_RETUNE = 10,
};
@ -620,17 +621,37 @@ static void intel_hs400_enhanced_strobe(struct mmc_host *mmc,
sdhci_writel(host, val, INTEL_HS400_ES_REG);
}
static void sdhci_intel_voltage_switch(struct sdhci_host *host)
static int intel_start_signal_voltage_switch(struct mmc_host *mmc,
struct mmc_ios *ios)
{
struct device *dev = mmc_dev(mmc);
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pci_slot *slot = sdhci_priv(host);
struct intel_host *intel_host = sdhci_pci_priv(slot);
struct device *dev = &slot->chip->pdev->dev;
unsigned int fn;
u32 result = 0;
int err;
err = intel_dsm(intel_host, dev, INTEL_DSM_V18_SWITCH, &result);
pr_debug("%s: %s DSM error %d result %u\n",
mmc_hostname(host->mmc), __func__, err, result);
err = sdhci_start_signal_voltage_switch(mmc, ios);
if (err)
return err;
switch (ios->signal_voltage) {
case MMC_SIGNAL_VOLTAGE_330:
fn = INTEL_DSM_V33_SWITCH;
break;
case MMC_SIGNAL_VOLTAGE_180:
fn = INTEL_DSM_V18_SWITCH;
break;
default:
return 0;
}
err = intel_dsm(intel_host, dev, fn, &result);
pr_debug("%s: %s DSM fn %u error %d result %u\n",
mmc_hostname(mmc), __func__, fn, err, result);
return 0;
}
static const struct sdhci_ops sdhci_intel_byt_ops = {
@ -641,7 +662,6 @@ static const struct sdhci_ops sdhci_intel_byt_ops = {
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset,
.voltage_switch = sdhci_intel_voltage_switch,
};
static const struct sdhci_ops sdhci_intel_glk_ops = {
@ -652,7 +672,6 @@ static const struct sdhci_ops sdhci_intel_glk_ops = {
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset,
.voltage_switch = sdhci_intel_voltage_switch,
.irq = sdhci_cqhci_irq,
};
@ -691,6 +710,7 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot)
byt_read_dsm(slot);
ops->execute_tuning = intel_execute_tuning;
ops->start_signal_voltage_switch = intel_start_signal_voltage_switch;
}
static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
@ -832,6 +852,10 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_SD)
slot->host->mmc_host_ops.get_cd = bxt_get_cd;
if (slot->chip->pdev->subsystem_vendor == PCI_VENDOR_ID_NI &&
slot->chip->pdev->subsystem_device == PCI_SUBDEVICE_ID_NI_78E3)
slot->host->mmc->caps2 |= MMC_CAP2_AVOID_3_3V;
return 0;
}

View File

@ -54,6 +54,7 @@
#define PCI_DEVICE_ID_REALTEK_5250 0x5250
#define PCI_SUBDEVICE_ID_NI_7884 0x7884
#define PCI_SUBDEVICE_ID_NI_78E3 0x78e3
#define PCI_VENDOR_ID_ARASAN 0x16e6
#define PCI_DEVICE_ID_ARASAN_PHY_EMMC 0x0670

View File

@ -200,10 +200,8 @@ static int pic32_sdhci_probe(struct platform_device *pdev)
}
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "error adding host\n");
if (ret)
goto err_base_clk;
}
dev_info(&pdev->dev, "Successfully added sdhci host\n");
return 0;

View File

@ -221,10 +221,8 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
host->ops = &pxav2_sdhci_ops;
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "failed to add host\n");
if (ret)
goto disable_clk;
}
return 0;

View File

@ -472,10 +472,8 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
pm_suspend_ignore_children(&pdev->dev, 1);
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "failed to add host\n");
if (ret)
goto err_add_host;
}
if (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ)
device_init_wakeup(&pdev->dev, 1);

View File

@ -655,10 +655,8 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
goto err_req_regs;
ret = sdhci_add_host(host);
if (ret) {
dev_err(dev, "sdhci_add_host() failed\n");
if (ret)
goto err_req_regs;
}
#ifdef CONFIG_PM
if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)

View File

@ -126,10 +126,8 @@ static int sdhci_probe(struct platform_device *pdev)
}
ret = sdhci_add_host(host);
if (ret) {
dev_dbg(&pdev->dev, "error adding host\n");
if (ret)
goto disable_clk;
}
platform_set_drvdata(pdev, host);

View File

@ -422,10 +422,8 @@ static int sdhci_st_probe(struct platform_device *pdev)
st_mmcss_cconfig(np, host);
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "Failed sdhci_add_host\n");
if (ret)
goto err_out;
}
host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));

View File

@ -231,7 +231,7 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
if (timing == MMC_TIMING_UHS_DDR50)
tegra_host->ddr_signaling = true;
return sdhci_set_uhs_signaling(host, timing);
sdhci_set_uhs_signaling(host, timing);
}
static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)

View File

@ -814,15 +814,10 @@ static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
int i, ret;
int ret;
for (i = 0; i < NR_PHY_TYPES; i++) {
if (!strcmp(phy_name, phy_types[i])) {
priv->phy_type = i;
break;
}
}
if (i == NR_PHY_TYPES) {
priv->phy_type = match_string(phy_types, NR_PHY_TYPES, phy_name);
if (priv->phy_type < 0) {
dev_err(mmc_dev(host->mmc),
"Unable to determine PHY name %s. Use default eMMC 5.1 PHY\n",
phy_name);

View File

@ -709,29 +709,16 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
return sg_dma_address(host->data->sg);
}
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
static unsigned int sdhci_target_timeout(struct sdhci_host *host,
struct mmc_command *cmd,
struct mmc_data *data)
{
u8 count;
struct mmc_data *data = cmd->data;
unsigned target_timeout, current_timeout;
/*
* If the host controller provides us with an incorrect timeout
* value, just skip the check and use 0xE. The hardware may take
* longer to time out, but that's much better than having a too-short
* timeout value.
*/
if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
return 0xE;
/* Unspecified timeout, assume max */
if (!data && !cmd->busy_timeout)
return 0xE;
unsigned int target_timeout;
/* timeout in us */
if (!data)
if (!data) {
target_timeout = cmd->busy_timeout * 1000;
else {
} else {
target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
if (host->clock && data->timeout_clks) {
unsigned long long val;
@ -748,6 +735,67 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
}
}
return target_timeout;
}
static void sdhci_calc_sw_timeout(struct sdhci_host *host,
struct mmc_command *cmd)
{
struct mmc_data *data = cmd->data;
struct mmc_host *mmc = host->mmc;
struct mmc_ios *ios = &mmc->ios;
unsigned char bus_width = 1 << ios->bus_width;
unsigned int blksz;
unsigned int freq;
u64 target_timeout;
u64 transfer_time;
target_timeout = sdhci_target_timeout(host, cmd, data);
target_timeout *= NSEC_PER_USEC;
if (data) {
blksz = data->blksz;
freq = host->mmc->actual_clock ? : host->clock;
transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
do_div(transfer_time, freq);
/* multiply by '2' to account for any unknowns */
transfer_time = transfer_time * 2;
/* calculate timeout for the entire data */
host->data_timeout = data->blocks * target_timeout +
transfer_time;
} else {
host->data_timeout = target_timeout;
}
if (host->data_timeout)
host->data_timeout += MMC_CMD_TRANSFER_TIME;
}
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
bool *too_big)
{
u8 count;
struct mmc_data *data = cmd->data;
unsigned target_timeout, current_timeout;
*too_big = true;
/*
* If the host controller provides us with an incorrect timeout
* value, just skip the check and use 0xE. The hardware may take
* longer to time out, but that's much better than having a too-short
* timeout value.
*/
if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
return 0xE;
/* Unspecified timeout, assume max */
if (!data && !cmd->busy_timeout)
return 0xE;
/* timeout in us */
target_timeout = sdhci_target_timeout(host, cmd, data);
/*
* Figure out needed cycles.
* We do this in steps in order to fit inside a 32 bit int.
@ -768,9 +816,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
}
if (count >= 0xF) {
DBG("Too large timeout 0x%x requested for CMD%d!\n",
count, cmd->opcode);
if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT))
DBG("Too large timeout 0x%x requested for CMD%d!\n",
count, cmd->opcode);
count = 0xE;
} else {
*too_big = false;
}
return count;
@ -790,6 +841,16 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
{
if (enable)
host->ier |= SDHCI_INT_DATA_TIMEOUT;
else
host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
{
u8 count;
@ -797,7 +858,18 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
if (host->ops->set_timeout) {
host->ops->set_timeout(host, cmd);
} else {
count = sdhci_calc_timeout(host, cmd);
bool too_big = false;
count = sdhci_calc_timeout(host, cmd, &too_big);
if (too_big &&
host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
sdhci_calc_sw_timeout(host, cmd);
sdhci_set_data_timeout_irq(host, false);
} else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
sdhci_set_data_timeout_irq(host, true);
}
sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
}
}
@ -807,6 +879,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
u8 ctrl;
struct mmc_data *data = cmd->data;
host->data_timeout = 0;
if (sdhci_data_line_cmd(cmd))
sdhci_set_timeout(host, cmd);
@ -1160,13 +1234,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
mdelay(1);
}
timeout = jiffies;
if (!cmd->data && cmd->busy_timeout > 9000)
timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
else
timeout += 10 * HZ;
sdhci_mod_timer(host, cmd->mrq, timeout);
host->cmd = cmd;
if (sdhci_data_line_cmd(cmd)) {
WARN_ON(host->data_cmd);
@ -1206,6 +1273,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
flags |= SDHCI_CMD_DATA;
timeout = jiffies;
if (host->data_timeout)
timeout += nsecs_to_jiffies(host->data_timeout);
else if (!cmd->data && cmd->busy_timeout > 9000)
timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
else
timeout += 10 * HZ;
sdhci_mod_timer(host, cmd->mrq, timeout);
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
}
EXPORT_SYMBOL_GPL(sdhci_send_command);
@ -3616,6 +3692,10 @@ int sdhci_setup_host(struct sdhci_host *host)
mmc->max_busy_timeout /= host->timeout_clk;
}
if (host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT &&
!host->ops->get_max_timeout_count)
mmc->max_busy_timeout = 0;
mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
@ -3672,6 +3752,16 @@ int sdhci_setup_host(struct sdhci_host *host)
if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50);
/*
* The SDHCI controller in a SoC might support HS200/HS400
* (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property),
* but if the board is modeled such that the IO lines are not
* connected to 1.8v then HS200/HS400 cannot be supported.
* Disable HS200/HS400 if the board does not have 1.8v connected
* to the IO lines. (Applicable for other modes in 1.8v)
*/
mmc->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES);
mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS);
}
/* Any UHS-I mode in caps implies SDR12 and SDR25 support. */

View File

@ -332,6 +332,14 @@ struct sdhci_adma2_64_desc {
/* Allow for a a command request and a data request at the same time */
#define SDHCI_MAX_MRQS 2
/*
* 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms.
* However since the start time of the command, the time between
* command and response, and the time between response and start of data is
* not known, set the command transfer time to 10ms.
*/
#define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */
enum sdhci_cookie {
COOKIE_UNMAPPED,
COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */
@ -437,6 +445,11 @@ struct sdhci_host {
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15)
/* Controller has CRC in 136 bit Command Response */
#define SDHCI_QUIRK2_RSP_136_HAS_CRC (1<<16)
/*
* Disable HW timeout if the requested timeout is more than the maximum
* obtainable timeout.
*/
#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@ -550,6 +563,8 @@ struct sdhci_host {
/* Host SDMA buffer boundary. */
u32 sdma_boundary;
u64 data_timeout;
unsigned long private[0] ____cacheline_aligned;
};

View File

@ -13,36 +13,34 @@
* the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clk/sunxi-ng.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/reset.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sd.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
/* register offset definitions */
#define SDXC_REG_GCTRL (0x00) /* SMC Global Control Register */
@ -322,10 +320,9 @@ static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host)
return 0;
}
static int sunxi_mmc_init_host(struct mmc_host *mmc)
static int sunxi_mmc_init_host(struct sunxi_mmc_host *host)
{
u32 rval;
struct sunxi_mmc_host *host = mmc_priv(mmc);
if (sunxi_mmc_reset_host(host))
return -EIO;
@ -859,17 +856,48 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
return 0;
}
static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
static void sunxi_mmc_set_bus_width(struct sunxi_mmc_host *host,
unsigned char width)
{
switch (width) {
case MMC_BUS_WIDTH_1:
mmc_writel(host, REG_WIDTH, SDXC_WIDTH1);
break;
case MMC_BUS_WIDTH_4:
mmc_writel(host, REG_WIDTH, SDXC_WIDTH4);
break;
case MMC_BUS_WIDTH_8:
mmc_writel(host, REG_WIDTH, SDXC_WIDTH8);
break;
}
}
static void sunxi_mmc_set_clk(struct sunxi_mmc_host *host, struct mmc_ios *ios)
{
struct sunxi_mmc_host *host = mmc_priv(mmc);
u32 rval;
/* Set the power state */
switch (ios->power_mode) {
case MMC_POWER_ON:
break;
/* set ddr mode */
rval = mmc_readl(host, REG_GCTRL);
if (ios->timing == MMC_TIMING_UHS_DDR50 ||
ios->timing == MMC_TIMING_MMC_DDR52)
rval |= SDXC_DDR_MODE;
else
rval &= ~SDXC_DDR_MODE;
mmc_writel(host, REG_GCTRL, rval);
host->ferror = sunxi_mmc_clk_set_rate(host, ios);
/* Android code had a usleep_range(50000, 55000); here */
}
static void sunxi_mmc_card_power(struct sunxi_mmc_host *host,
struct mmc_ios *ios)
{
struct mmc_host *mmc = host->mmc;
switch (ios->power_mode) {
case MMC_POWER_UP:
dev_dbg(mmc_dev(mmc), "Powering card up\n");
if (!IS_ERR(mmc->supply.vmmc)) {
host->ferror = mmc_regulator_set_ocr(mmc,
mmc->supply.vmmc,
@ -887,53 +915,33 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
host->vqmmc_enabled = true;
}
host->ferror = sunxi_mmc_init_host(mmc);
if (host->ferror)
return;
dev_dbg(mmc_dev(mmc), "power on!\n");
break;
case MMC_POWER_OFF:
dev_dbg(mmc_dev(mmc), "power off!\n");
sunxi_mmc_reset_host(host);
dev_dbg(mmc_dev(mmc), "Powering card off\n");
if (!IS_ERR(mmc->supply.vmmc))
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled)
regulator_disable(mmc->supply.vqmmc);
host->vqmmc_enabled = false;
break;
}
/* set bus width */
switch (ios->bus_width) {
case MMC_BUS_WIDTH_1:
mmc_writel(host, REG_WIDTH, SDXC_WIDTH1);
break;
case MMC_BUS_WIDTH_4:
mmc_writel(host, REG_WIDTH, SDXC_WIDTH4);
break;
case MMC_BUS_WIDTH_8:
mmc_writel(host, REG_WIDTH, SDXC_WIDTH8);
default:
dev_dbg(mmc_dev(mmc), "Ignoring unknown card power state\n");
break;
}
}
/* set ddr mode */
rval = mmc_readl(host, REG_GCTRL);
if (ios->timing == MMC_TIMING_UHS_DDR50 ||
ios->timing == MMC_TIMING_MMC_DDR52)
rval |= SDXC_DDR_MODE;
else
rval &= ~SDXC_DDR_MODE;
mmc_writel(host, REG_GCTRL, rval);
static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct sunxi_mmc_host *host = mmc_priv(mmc);
/* set up clock */
if (ios->power_mode) {
host->ferror = sunxi_mmc_clk_set_rate(host, ios);
/* Android code had a usleep_range(50000, 55000); here */
}
sunxi_mmc_card_power(host, ios);
sunxi_mmc_set_bus_width(host, ios->bus_width);
sunxi_mmc_set_clk(host, ios);
}
static int sunxi_mmc_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
@ -955,6 +963,9 @@ static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
unsigned long flags;
u32 imask;
if (enable)
pm_runtime_get_noresume(host->dev);
spin_lock_irqsave(&host->lock, flags);
imask = mmc_readl(host, REG_IMASK);
@ -967,6 +978,9 @@ static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
}
mmc_writel(host, REG_IMASK, imask);
spin_unlock_irqrestore(&host->lock, flags);
if (!enable)
pm_runtime_put_noidle(host->mmc->parent);
}
static void sunxi_mmc_hw_reset(struct mmc_host *mmc)
@ -1380,6 +1394,15 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
if (ret)
goto error_free_dma;
ret = sunxi_mmc_init_host(host);
if (ret)
goto error_free_dma;
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = mmc_add_host(mmc);
if (ret)
goto error_free_dma;
@ -1400,6 +1423,7 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
struct sunxi_mmc_host *host = mmc_priv(mmc);
mmc_remove_host(mmc);
pm_runtime_force_suspend(&pdev->dev);
disable_irq(host->irq);
sunxi_mmc_disable(host);
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
@ -1408,10 +1432,47 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int sunxi_mmc_runtime_resume(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct sunxi_mmc_host *host = mmc_priv(mmc);
int ret;
ret = sunxi_mmc_enable(host);
if (ret)
return ret;
sunxi_mmc_init_host(host);
sunxi_mmc_set_bus_width(host, mmc->ios.bus_width);
sunxi_mmc_set_clk(host, &mmc->ios);
return 0;
}
static int sunxi_mmc_runtime_suspend(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct sunxi_mmc_host *host = mmc_priv(mmc);
sunxi_mmc_reset_host(host);
sunxi_mmc_disable(host);
return 0;
}
#endif
static const struct dev_pm_ops sunxi_mmc_pm_ops = {
SET_RUNTIME_PM_OPS(sunxi_mmc_runtime_suspend,
sunxi_mmc_runtime_resume,
NULL)
};
static struct platform_driver sunxi_mmc_driver = {
.driver = {
.name = "sunxi-mmc",
.of_match_table = of_match_ptr(sunxi_mmc_of_match),
.pm = &sunxi_mmc_pm_ops,
},
.probe = sunxi_mmc_probe,
.remove = sunxi_mmc_remove,

View File

@ -300,8 +300,10 @@ static void ushc_request(struct mmc_host *mmc, struct mmc_request *req)
pipe = usb_sndbulkpipe(ushc->usb_dev, 2);
usb_fill_bulk_urb(ushc->data_urb, ushc->usb_dev, pipe,
sg_virt(data->sg), data->sg->length,
NULL, data->sg->length,
data_callback, ushc);
ushc->data_urb->num_sgs = 1;
ushc->data_urb->sg = data->sg;
ret = usb_submit_urb(ushc->data_urb, GFP_ATOMIC);
if (ret < 0)
goto out;

View File

@ -268,43 +268,29 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
return host->num_sg;
}
static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
static inline char *wbsd_map_sg(struct wbsd_host *host)
{
return sg_virt(host->cur_sg);
return kmap_atomic(sg_page(host->cur_sg)) + host->cur_sg->offset;
}
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
{
unsigned int len, i;
struct scatterlist *sg;
char *dmabuf = host->dma_buffer;
char *sgbuf;
size_t len = 0;
int i;
sg = data->sg;
len = data->sg_len;
for (i = 0; i < len; i++) {
sgbuf = sg_virt(&sg[i]);
memcpy(dmabuf, sgbuf, sg[i].length);
dmabuf += sg[i].length;
}
for (i = 0; i < data->sg_len; i++)
len += data->sg[i].length;
sg_copy_to_buffer(data->sg, data->sg_len, host->dma_buffer, len);
}
static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
{
unsigned int len, i;
struct scatterlist *sg;
char *dmabuf = host->dma_buffer;
char *sgbuf;
size_t len = 0;
int i;
sg = data->sg;
len = data->sg_len;
for (i = 0; i < len; i++) {
sgbuf = sg_virt(&sg[i]);
memcpy(sgbuf, dmabuf, sg[i].length);
dmabuf += sg[i].length;
}
for (i = 0; i < data->sg_len; i++)
len += data->sg[i].length;
sg_copy_from_buffer(data->sg, data->sg_len, host->dma_buffer, len);
}
/*
@ -418,7 +404,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
{
struct mmc_data *data = host->mrq->cmd->data;
char *buffer;
int i, fsr, fifo;
int i, idx, fsr, fifo;
/*
* Handle excessive data.
@ -426,7 +412,8 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
if (host->num_sg == 0)
return;
buffer = wbsd_sg_to_buffer(host) + host->offset;
buffer = wbsd_map_sg(host) + host->offset;
idx = 0;
/*
* Drain the fifo. This has a tendency to loop longer
@ -445,8 +432,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
fifo = 1;
for (i = 0; i < fifo; i++) {
*buffer = inb(host->base + WBSD_DFR);
buffer++;
buffer[idx++] = inb(host->base + WBSD_DFR);
host->offset++;
host->remain--;
@ -456,16 +442,19 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
* End of scatter list entry?
*/
if (host->remain == 0) {
kunmap_atomic(buffer);
/*
* Get next entry. Check if last.
*/
if (!wbsd_next_sg(host))
return;
buffer = wbsd_sg_to_buffer(host);
buffer = wbsd_map_sg(host);
idx = 0;
}
}
}
kunmap_atomic(buffer);
/*
* This is a very dirty hack to solve a
@ -480,7 +469,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
{
struct mmc_data *data = host->mrq->cmd->data;
char *buffer;
int i, fsr, fifo;
int i, idx, fsr, fifo;
/*
* Check that we aren't being called after the
@ -489,7 +478,8 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
if (host->num_sg == 0)
return;
buffer = wbsd_sg_to_buffer(host) + host->offset;
buffer = wbsd_map_sg(host) + host->offset;
idx = 0;
/*
* Fill the fifo. This has a tendency to loop longer
@ -508,8 +498,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
fifo = 15;
for (i = 16; i > fifo; i--) {
outb(*buffer, host->base + WBSD_DFR);
buffer++;
outb(buffer[idx], host->base + WBSD_DFR);
host->offset++;
host->remain--;
@ -519,16 +508,19 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
* End of scatter list entry?
*/
if (host->remain == 0) {
kunmap_atomic(buffer);
/*
* Get next entry. Check if last.
*/
if (!wbsd_next_sg(host))
return;
buffer = wbsd_sg_to_buffer(host);
buffer = wbsd_map_sg(host);
idx = 0;
}
}
}
kunmap_atomic(buffer);
/*
* The controller stops sending interrupts for

View File

@ -928,8 +928,7 @@ static int wmt_mci_remove(struct platform_device *pdev)
static int wmt_mci_suspend(struct device *dev)
{
u32 reg_tmp;
struct platform_device *pdev = to_platform_device(dev);
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct mmc_host *mmc = dev_get_drvdata(dev);
struct wmt_mci_priv *priv;
if (!mmc)
@ -953,8 +952,7 @@ static int wmt_mci_suspend(struct device *dev)
static int wmt_mci_resume(struct device *dev)
{
u32 reg_tmp;
struct platform_device *pdev = to_platform_device(dev);
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct mmc_host *mmc = dev_get_drvdata(dev);
struct wmt_mci_priv *priv;
if (mmc) {

View File

@ -0,0 +1,49 @@
#ifndef __DT_BINDINGS_DMA_JZ4780_DMA_H__
#define __DT_BINDINGS_DMA_JZ4780_DMA_H__
/*
* Request type numbers for the JZ4780 DMA controller (written to the DRTn
* register for the channel).
*/
#define JZ4780_DMA_I2S1_TX 0x4
#define JZ4780_DMA_I2S1_RX 0x5
#define JZ4780_DMA_I2S0_TX 0x6
#define JZ4780_DMA_I2S0_RX 0x7
#define JZ4780_DMA_AUTO 0x8
#define JZ4780_DMA_SADC_RX 0x9
#define JZ4780_DMA_UART4_TX 0xc
#define JZ4780_DMA_UART4_RX 0xd
#define JZ4780_DMA_UART3_TX 0xe
#define JZ4780_DMA_UART3_RX 0xf
#define JZ4780_DMA_UART2_TX 0x10
#define JZ4780_DMA_UART2_RX 0x11
#define JZ4780_DMA_UART1_TX 0x12
#define JZ4780_DMA_UART1_RX 0x13
#define JZ4780_DMA_UART0_TX 0x14
#define JZ4780_DMA_UART0_RX 0x15
#define JZ4780_DMA_SSI0_TX 0x16
#define JZ4780_DMA_SSI0_RX 0x17
#define JZ4780_DMA_SSI1_TX 0x18
#define JZ4780_DMA_SSI1_RX 0x19
#define JZ4780_DMA_MSC0_TX 0x1a
#define JZ4780_DMA_MSC0_RX 0x1b
#define JZ4780_DMA_MSC1_TX 0x1c
#define JZ4780_DMA_MSC1_RX 0x1d
#define JZ4780_DMA_MSC2_TX 0x1e
#define JZ4780_DMA_MSC2_RX 0x1f
#define JZ4780_DMA_PCM0_TX 0x20
#define JZ4780_DMA_PCM0_RX 0x21
#define JZ4780_DMA_SMB0_TX 0x24
#define JZ4780_DMA_SMB0_RX 0x25
#define JZ4780_DMA_SMB1_TX 0x26
#define JZ4780_DMA_SMB1_RX 0x27
#define JZ4780_DMA_SMB2_TX 0x28
#define JZ4780_DMA_SMB2_RX 0x29
#define JZ4780_DMA_SMB3_TX 0x2a
#define JZ4780_DMA_SMB3_RX 0x2b
#define JZ4780_DMA_SMB4_TX 0x2c
#define JZ4780_DMA_SMB4_RX 0x2d
#define JZ4780_DMA_DES_TX 0x2e
#define JZ4780_DMA_DES_RX 0x2f
#endif /* __DT_BINDINGS_DMA_JZ4780_DMA_H__ */

View File

@ -156,6 +156,7 @@ struct sd_switch_caps {
#define UHS_DDR50_MAX_DTR 50000000
#define UHS_SDR25_MAX_DTR UHS_DDR50_MAX_DTR
#define UHS_SDR12_MAX_DTR 25000000
#define DEFAULT_SPEED_MAX_DTR UHS_SDR12_MAX_DTR
unsigned int sd3_bus_mode;
#define UHS_SDR12_BUS_SPEED 0
#define HIGH_SPEED_BUS_SPEED 1
@ -252,6 +253,7 @@ struct mmc_card {
#define MMC_TYPE_SD_COMBO 3 /* SD combo (IO+mem) card */
unsigned int state; /* (our) card state */
unsigned int quirks; /* card quirks */
unsigned int quirk_max_rate; /* max rate set by quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
/* for byte mode */

View File

@ -177,6 +177,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd,
int retries);
int mmc_hw_reset(struct mmc_host *host);
int mmc_sw_reset(struct mmc_host *host);
void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card);
#endif /* LINUX_MMC_CORE_H */

View File

@ -22,6 +22,7 @@
struct mmc_ios {
unsigned int clock; /* clock rate */
unsigned short vdd;
unsigned int power_delay_ms; /* waiting for stable power */
/* vdd stores the bit number of the selected voltage range from below. */
@ -320,6 +321,9 @@ struct mmc_host {
#define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */
#define MMC_CAP_UHS_SDR104 (1 << 19) /* Host supports UHS SDR104 mode */
#define MMC_CAP_UHS_DDR50 (1 << 20) /* Host supports UHS DDR50 mode */
#define MMC_CAP_UHS (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | \
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | \
MMC_CAP_UHS_DDR50)
/* (1 << 21) is free for reuse */
#define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
#define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
@ -345,6 +349,7 @@ struct mmc_host {
#define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */
#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \
MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_HSX00_1_8V (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)
#define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
#define MMC_CAP2_NO_WRITE_PROTECT (1 << 18) /* No physical write protect pin, assume that card is always read-write */
@ -354,6 +359,7 @@ struct mmc_host {
#define MMC_CAP2_NO_MMC (1 << 22) /* Do not send (e)MMC commands during initialization */
#define MMC_CAP2_CQE (1 << 23) /* Has eMMC command queue engine */
#define MMC_CAP2_CQE_DCMD (1 << 24) /* CQE can issue a direct command */
#define MMC_CAP2_AVOID_3_3V (1 << 25) /* Host must negotiate down from 3.3V */
int fixed_drv_type; /* fixed driver type for non-removable media */

View File

@ -55,6 +55,7 @@
#define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104
#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105
#define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128
#define SDIO_DEVICE_ID_MARVELL_8887WLAN 0x9134
#define SDIO_VENDOR_ID_SIANO 0x039a
#define SDIO_DEVICE_ID_SIANO_NOVA_B0 0x0201