Commit 1650ac53 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Introduce a host helper function to share re-tuning progress

  MMC host:
   - sdhci: Add support for v4 host mode
   - sdhci-of-arasan: Add Support for AM654 MMC and PHY
   - sdhci-sprd: Add support for Spreadtrum's host controller
   - sdhci-tegra: Add support for HS400 enhanced strobe
   - sdhci-tegra: Enable UHS/HS200 modes for Tegra186/210
   - sdhci-tegra: Add support for HS400 delay line calibration
   - sdhci-tegra: Add support for pad calibration
   - sdhci-of-dwcmshc: Address 128MB DMA boundary limitation
   - sdhci-of-esdhc: Add support for tuning erratum A008171
   - sdhci-iproc: Add ACPI support
   - mediatek: Add support for MT8183
   - mediatek: Improve the support for tuning
   - mediatek: Add bus clock control for MT2712
   - jz4740: Add support for the JZ4725B
   - mmci: Add support for the stm32 sdmmc variant
   - mmci: Add support for an optional reset control
   - mmci: Add some new variant specific properties/callbacks
   - mmci: Re-structure DMA code to prepare for new variants
   - renesas_sdhi: Add support for r8a77470, r8a7744 and r8a774a1
   - renesas_sdhi_internal_dmac: Whitelist r8a77970 and r8a774a1
   - tmio/uniphier-sd: Add new UniPhier SD/eMMC controller driver
   - tmio/renesas_sdhi: Deal properly with SCC detection during re-tune
   - tmio/renesas_sdhi: Refactor/consolidate clock management
   - omap_hsmmc: Drop cover detection and some unused platform data
   - dw_mmc-exynos: Enable tuning for more speed modes
   - sunxi: Clarify the new timing mode and enable it for the A64 controller
   - various: Convert to slot GPIO descriptors"

* tag 'mmc-v4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (129 commits)
  mmc: mediatek: drop too much code of tuning method
  mmc: mediatek: add MT8183 MMC driver support
  mmc: mediatek: tune CMD/DATA together
  mmc: mediatek: fix cannot receive new request when msdc_cmd_is_ready fail
  mmc: mediatek: fill the actual clock for mmc debugfs
  mmc: dt-bindings: add support for MT8183 SoC
  mmc: uniphier-sd: avoid using broken DMA RX channel
  mmc: uniphier-sd: fix DMA disabling
  mmc: tmio: simplify the DMA mode test
  mmc: tmio: remove TMIO_MMC_HAVE_HIGH_REG flag
  mmc: tmio: move MFD variant reset to a platform hook
  mmc: renesas_sdhi: Add r8a77470 SDHI1 support
  dt-bindings: mmc: renesas_sdhi: Add r8a77470 support
  mmc: mmci: add stm32 sdmmc variant
  dt-bindings: mmci: add stm32 sdmmc variant
  mmc: mmci: add stm32 sdmmc registers
  mmc: mmci: add clock divider for stm32 sdmmc
  mmc: mmci: add optional reset property
  dt-bindings: mmci: add optional reset property
  mmc: mmci: add variant property to not read datacnt
  ...
parents ca9eb48f fd82cc30
......@@ -15,6 +15,7 @@ Required Properties:
- "arasan,sdhci-5.1": generic Arasan SDHCI 5.1 PHY
- "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
- "ti,am654-sdhci-5.1", "arasan,sdhci-5.1": TI AM654 MMC PHY
- reg: From mmc bindings: Register location and length.
- clocks: From clock bindings: Handles to clock inputs.
- clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"
......
......@@ -7,6 +7,7 @@ described in mmc.txt.
Required properties:
- compatible: Should be one of the following:
- "ingenic,jz4740-mmc" for the JZ4740
- "ingenic,jz4725b-mmc" for the JZ4725B
- "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.
......
......@@ -15,8 +15,11 @@ Required properties:
Optional properties:
- arm,primecell-periphid : contains the PrimeCell Peripheral ID, it overrides
the ID provided by the HW
- resets : phandle to internal reset line.
Should be defined for sdmmc variant.
- vqmmc-supply : phandle to the regulator device tree node, mentioned
as the VCCQ/VDD_IO supply in the eMMC/SD specs.
specific for ux500 variant:
- st,sig-dir-dat0 : bus signal direction pin used for DAT[0].
- st,sig-dir-dat2 : bus signal direction pin used for DAT[2].
- st,sig-dir-dat31 : bus signal direction pin used for DAT[3] and DAT[1].
......@@ -24,6 +27,14 @@ Optional properties:
- st,sig-dir-cmd : cmd signal direction pin used for CMD.
- st,sig-pin-fbclk : feedback clock signal pin used.
specific for sdmmc variant:
- st,sig-dir : signal direction polarity used for cmd, dat0 dat123.
- st,neg-edge : data & command phase relation, generated on
sd clock falling edge.
- st,use-ckin : use ckin pin from an external driver to sample
the receive data (example: with voltage
switch transceiver).
Deprecated properties:
- mmc-cap-mmc-highspeed : indicates whether MMC is high speed capable.
- mmc-cap-sd-highspeed : indicates whether SD is high speed capable.
......
......@@ -10,6 +10,7 @@ Required properties:
- compatible: value should be either of the following.
"mediatek,mt8135-mmc": for mmc host ip compatible with mt8135
"mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
"mediatek,mt8183-mmc": for mmc host ip compatible with mt8183
"mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
"mediatek,mt7622-mmc": for MT7622 SoC
......@@ -22,6 +23,7 @@ Required properties:
"source" - source clock (required)
"hclk" - HCLK which used for host (required)
"source_cg" - independent source clock gate (required for MT2712)
"bus_clk" - bus clock used for internal register access (required for MT2712 MSDC0/3)
- pinctrl-names: should be "default", "state_uhs"
- pinctrl-0: should contain default/high speed pin ctrl
- pinctrl-1: should contain uhs mode pin ctrl
......
......@@ -38,3 +38,75 @@ sdhci@c8000200 {
power-gpios = <&gpio 155 0>; /* gpio PT3 */
bus-width = <8>;
};
Optional properties for Tegra210 and Tegra186:
- pinctrl-names, pinctrl-0, pinctrl-1 : Specify pad voltage
configurations. Valid pinctrl-names are "sdmmc-3v3" and "sdmmc-1v8"
for controllers supporting multiple voltage levels. The order of names
should correspond to the pin configuration states in pinctrl-0 and
pinctrl-1.
- nvidia,only-1-8-v : The presence of this property indicates that the
controller operates at a 1.8 V fixed I/O voltage.
- nvidia,pad-autocal-pull-up-offset-3v3,
nvidia,pad-autocal-pull-down-offset-3v3 : Specify drive strength
calibration offsets for 3.3 V signaling modes.
- nvidia,pad-autocal-pull-up-offset-1v8,
nvidia,pad-autocal-pull-down-offset-1v8 : Specify drive strength
calibration offsets for 1.8 V signaling modes.
- nvidia,pad-autocal-pull-up-offset-3v3-timeout,
nvidia,pad-autocal-pull-down-offset-3v3-timeout : Specify drive
strength used as a fallback in case the automatic calibration times
out on a 3.3 V signaling mode.
- nvidia,pad-autocal-pull-up-offset-1v8-timeout,
nvidia,pad-autocal-pull-down-offset-1v8-timeout : Specify drive
strength used as a fallback in case the automatic calibration times
out on a 1.8 V signaling mode.
- nvidia,pad-autocal-pull-up-offset-sdr104,
nvidia,pad-autocal-pull-down-offset-sdr104 : Specify drive strength
calibration offsets for SDR104 mode.
- nvidia,pad-autocal-pull-up-offset-hs400,
nvidia,pad-autocal-pull-down-offset-hs400 : Specify drive strength
calibration offsets for HS400 mode.
- nvidia,default-tap : Specify the default inbound sampling clock
trimmer value for non-tunable modes.
- nvidia,default-trim : Specify the default outbound clock trimmer
value.
- nvidia,dqs-trim : Specify DQS trim value for HS400 timing
Notes on the pad calibration pull up and pulldown offset values:
- The property values are drive codes which are programmed into the
PD_OFFSET and PU_OFFSET sections of the
SDHCI_TEGRA_AUTO_CAL_CONFIG register.
- A higher value corresponds to higher drive strength. Please refer
to the reference manual of the SoC for correct values.
- The SDR104 and HS400 timing specific values are used in
corresponding modes if specified.
Notes on tap and trim values:
- The values are used for compensating trace length differences
by adjusting the sampling point.
- The values are programmed to the Vendor Clock Control Register.
Please refer to the reference manual of the SoC for correct
values.
- The DQS trim values are only used on controllers which support
HS400 timing. Only SDMMC4 on Tegra210 and Tegra 186 supports
HS400.
Example:
sdhci@700b0000 {
compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
reg = <0x0 0x700b0000 0x0 0x200>;
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
clock-names = "sdhci";
resets = <&tegra_car 14>;
reset-names = "sdhci";
pinctrl-names = "sdmmc-3v3", "sdmmc-1v8";
pinctrl-0 = <&sdmmc1_3v3>;
pinctrl-1 = <&sdmmc1_1v8>;
nvidia,pad-autocal-pull-up-offset-3v3 = <0x00>;
nvidia,pad-autocal-pull-down-offset-3v3 = <0x7d>;
nvidia,pad-autocal-pull-up-offset-1v8 = <0x7b>;
nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>;
status = "disabled";
};
......@@ -12,6 +12,7 @@ Required properties:
- "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs
- "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
- "renesas,mmcif-r8a7743" for the MMCIF found in r8a7743 SoCs
- "renesas,mmcif-r8a7744" for the MMCIF found in r8a7744 SoCs
- "renesas,mmcif-r8a7745" for the MMCIF found in r8a7745 SoCs
- "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs
- "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
......@@ -23,7 +24,8 @@ Required properties:
- interrupts: Some SoCs have only 1 shared interrupt, while others have either
2 or 3 individual interrupts (error, int, card detect). Below is the number
of interrupts for each SoC:
1: r8a73a4, r8a7743, r8a7745, r8a7778, r8a7790, r8a7791, r8a7793, r8a7794
1: r8a73a4, r8a7743, r8a7744, r8a7745, r8a7778, r8a7790, r8a7791, r8a7793,
r8a7794
2: r8a7740, sh73a0
3: r7s72100
......
* Spreadtrum SDHCI controller (sdhci-sprd)
The Secure Digital (SD) Host controller on Spreadtrum SoCs provides an interface
for MMC, SD and SDIO types of cards.
This file documents differences between the core properties in mmc.txt
and the properties used by the sdhci-sprd driver.
Required properties:
- compatible: Should contain "sprd,sdhci-r11".
- reg: physical base address of the controller and length.
- interrupts: Interrupts used by the SDHCI controller.
- clocks: Should contain phandle for the clock feeding the SDHCI controller
- clock-names: Should contain the following:
"sdio" - SDIO source clock (required)
"enable" - gate clock which used for enabling/disabling the device (required)
Optional properties:
- assigned-clocks: the same with "sdio" clock
- assigned-clock-parents: the default parent of "sdio" clock
Examples:
sdio0: sdio@20600000 {
compatible = "sprd,sdhci-r11";
reg = <0 0x20600000 0 0x1000>;
interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "sdio", "enable";
clocks = <&ap_clk CLK_EMMC_2X>,
<&apahb_gate CLK_EMMC_EB>;
assigned-clocks = <&ap_clk CLK_EMMC_2X>;
assigned-clock-parents = <&rpll CLK_RPLL_390M>;
bus-width = <8>;
non-removable;
no-sdio;
no-sd;
cap-mmc-hw-reset;
status = "okay";
};
......@@ -16,7 +16,11 @@ Required properties:
"renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
"renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
"renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC
"renesas,sdhi-r8a7744" - SDHI IP on R8A7744 SoC
"renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC
"renesas,sdhi-r8a774a1" - SDHI IP on R8A774A1 SoC
"renesas,sdhi-r8a77470" - SDHI IP on R8A77470 SoC
"renesas,sdhi-mmc-r8a77470" - SDHI/MMC IP on R8A77470 SoC
"renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
"renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC
"renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC
......@@ -27,14 +31,16 @@ Required properties:
"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-r8a77970" - SDHI IP on R8A77970 SoC
"renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC
"renesas,sdhi-r8a77990" - SDHI IP on R8A77990 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
"renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 or RZ/G1
"renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 and RZ/G1 SDHI
(not SDHI/MMC) controller
"renesas,rcar-gen3-sdhi" - a generic R-Car Gen3 or RZ/G2
SDHI controller
"renesas,rcar-gen3-sdhi" - a generic R-Car Gen3 SDHI controller
When compatible with the generic version, nodes must list
......
UniPhier SD/eMMC controller
Required properties:
- compatible: should be one of the following:
"socionext,uniphier-sd-v2.91" - IP version 2.91
"socionext,uniphier-sd-v3.1" - IP version 3.1
"socionext,uniphier-sd-v3.1.1" - IP version 3.1.1
- reg: offset and length of the register set for the device.
- interrupts: a single interrupt specifier.
- clocks: a single clock specifier of the controller clock.
- reset-names: should contain the following:
"host" - mandatory for all versions
"bridge" - should exist only for "socionext,uniphier-sd-v2.91"
"hw" - should exist if eMMC hw reset line is available
- resets: a list of reset specifiers, corresponding to the reset-names
Optional properties:
- pinctrl-names: if present, should contain the following:
"default" - should exist for all instances
"uhs" - should exist for SD instance with UHS support
- pinctrl-0: pin control state for the default mode
- pinctrl-1: pin control state for the UHS mode
- dma-names: should be "rx-tx" if present.
This property can exist only for "socionext,uniphier-sd-v2.91".
- dmas: a single DMA channel specifier
This property can exist only for "socionext,uniphier-sd-v2.91".
- bus-width: see mmc.txt
- cap-sd-highspeed: see mmc.txt
- cap-mmc-highspeed: see mmc.txt
- sd-uhs-sdr12: see mmc.txt
- sd-uhs-sdr25: see mmc.txt
- sd-uhs-sdr50: see mmc.txt
- cap-mmc-hw-reset: should exist if reset-names contains "hw". see mmc.txt
- non-removable: see mmc.txt
Example:
sd: sdhc@5a400000 {
compatible = "socionext,uniphier-sd-v2.91";
reg = <0x5a400000 0x200>;
interrupts = <0 76 4>;
pinctrl-names = "default", "uhs";
pinctrl-0 = <&pinctrl_sd>;
pinctrl-1 = <&pinctrl_sd_uhs>;
clocks = <&mio_clk 0>;
reset-names = "host", "bridge";
resets = <&mio_rst 0>, <&mio_rst 3>;
dma-names = "rx-tx";
dmas = <&dmac 4>;
bus-width = <4>;
cap-sd-highspeed;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
};
......@@ -2195,6 +2195,7 @@ F: drivers/clk/uniphier/
F: drivers/gpio/gpio-uniphier.c
F: drivers/i2c/busses/i2c-uniphier*
F: drivers/irqchip/irq-uniphier-aidet.c
F: drivers/mmc/host/uniphier-sd.c
F: drivers/pinctrl/uniphier/
F: drivers/reset/reset-uniphier.c
F: drivers/tty/serial/8250/8250_uniphier.c
......
......@@ -80,8 +80,6 @@ static unsigned int mmc_status(struct device *dev)
static struct mmci_platform_data mmc_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = mmc_status,
.gpio_wp = -1,
.gpio_cd = -1,
};
static u64 notrace intcp_read_sched_clock(void)
......
......@@ -12,8 +12,6 @@ struct omap2_hsmmc_info {
u8 mmc; /* controller 1/2/3 */
u32 caps; /* 4/8 wires and any additional host
* capabilities OR'd (ref. linux/mmc/host.h) */
int gpio_cd; /* or -EINVAL */
int gpio_wp; /* or -EINVAL */
struct platform_device *pdev; /* mmc controller instance */
/* init some special card */
void (*init_card)(struct mmc_card *card);
......
......@@ -376,8 +376,6 @@ static struct omap2_hsmmc_info pandora_mmc3[] = {
{
.mmc = 3,
.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.init_card = pandora_wl1251_init_card,
},
{} /* Terminator */
......
......@@ -89,15 +89,11 @@ unsigned int mmc_status(struct device *dev)
static struct mmci_platform_data mmc0_plat_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = mmc_status,
.gpio_wp = -1,
.gpio_cd = -1,
};
static struct mmci_platform_data mmc1_plat_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = mmc_status,
.gpio_wp = -1,
.gpio_cd = -1,
};
/*
......
......@@ -14,7 +14,7 @@ config PWRSEQ_EMMC
config PWRSEQ_SD8787
tristate "HW reset support for SD8787 BT + Wifi module"
depends on OF && (MWIFIEX || BT_MRVL_SDIO)
depends on OF && (MWIFIEX || BT_MRVL_SDIO || LIBERTAS_SDIO)
help
This selects hardware reset support for the SD8787 BT + Wifi
module. By default this option is set to n.
......
......@@ -34,6 +34,16 @@ config MMC_QCOM_DML
if unsure, say N.
config MMC_STM32_SDMMC
bool "STMicroelectronics STM32 SDMMC Controller"
depends on MMC_ARMMMCI
default y
help
This selects the STMicroelectronics STM32 SDMMC host controller.
If you have a STM32 sdmmc host with internal DMA say Y here.
If unsure, say N.
config MMC_PXA
tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
depends on ARCH_PXA
......@@ -345,6 +355,7 @@ config MMC_SDHCI_IPROC
tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller"
depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
depends on OF || ACPI
default ARCH_BCM_IPROC
select MMC_SDHCI_IO_ACCESSORS
help
......@@ -592,6 +603,19 @@ config MMC_SDRICOH_CS
To compile this driver as a module, choose M here: the
module will be called sdricoh_cs.
config MMC_SDHCI_SPRD
tristate "Spreadtrum SDIO host Controller"
depends on ARCH_SPRD
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help
This selects the SDIO Host Controller in Spreadtrum
SoCs, this driver supports R11(IP version: R11P0).
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_TMIO_CORE
tristate
......@@ -622,14 +646,24 @@ 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 ARM64 || ARCH_R8A77470 || COMPILE_TEST
depends on MMC_SDHI
default MMC_SDHI if ARM64
default MMC_SDHI if (ARM64 || ARCH_R8A77470)
help
This provides DMA support for SDHI SD/SDIO controllers
using on-chip bus mastering. This supports the controllers
found in arm64 based SoCs.
config MMC_UNIPHIER
tristate "UniPhier SD/eMMC Host Controller support"
depends on ARCH_UNIPHIER || COMPILE_TEST
depends on OF
select MMC_TMIO_CORE
help
This provides support for the SD/eMMC controller found in
UniPhier SoCs. The eMMC variant of this controller is used
only for 32-bit SoCs.
config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
depends on PCI
......@@ -772,7 +806,7 @@ config MMC_SH_MMCIF
config MMC_JZ4740
tristate "Ingenic JZ47xx SD/Multimedia Card Interface support"
depends on MACH_JZ4740 || MACH_JZ4780
depends on MIPS
help
This selects support for the SD/MMC controller on Ingenic
JZ4740, JZ4750, JZ4770 and JZ4780 SoCs.
......
......@@ -6,6 +6,7 @@
obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
armmmci-y := mmci.o
armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
armmmci-$(CONFIG_MMC_STM32_SDMMC) += mmci_stm32_sdmmc.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
......@@ -42,6 +43,7 @@ obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o
obj-$(CONFIG_MMC_SDHI_SYS_DMAC) += renesas_sdhi_sys_dmac.o
obj-$(CONFIG_MMC_SDHI_INTERNAL_DMAC) += renesas_sdhi_internal_dmac.o
obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
octeon-mmc-objs := cavium.o cavium-octeon.o
......@@ -91,6 +93,7 @@ obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o
obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o
obj-$(CONFIG_MMC_CQHCI) += cqhci.o
ifeq ($(CONFIG_CB710_DEBUG),y)
......
......@@ -253,6 +253,8 @@ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
if (timing == MMC_TIMING_MMC_HS400) {
dqs |= DATA_STROBE_EN;
strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
} else if (timing == MMC_TIMING_UHS_SDR104) {
dqs &= 0xffffff00;
} else {
dqs &= ~DATA_STROBE_EN;
}
......@@ -312,6 +314,15 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
if (ios->bus_width == MMC_BUS_WIDTH_8)
wanted <<= 1;
break;
case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_UHS_SDR50:
clksel = (priv->sdr_timing & 0xfff8ffff) |
(priv->ciu_div << 16);
break;
case MMC_TIMING_UHS_DDR50:
clksel = (priv->ddr_timing & 0xfff8ffff) |
(priv->ciu_div << 16);
break;
default:
clksel = priv->sdr_timing;
}
......
......@@ -23,6 +23,12 @@ struct hi3798cv200_priv {
struct clk *drive_clk;
};
static unsigned long dw_mci_hi3798cv200_caps[] = {
MMC_CAP_CMD23,
MMC_CAP_CMD23,
MMC_CAP_CMD23
};
static void dw_mci_hi3798cv200_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
struct hi3798cv200_priv *priv = host->priv;
......@@ -160,6 +166,8 @@ static int dw_mci_hi3798cv200_init(struct dw_mci *host)
}
static const struct dw_mci_drv_data hi3798cv200_data = {
.caps = dw_mci_hi3798cv200_caps,
.num_caps = ARRAY_SIZE(dw_mci_hi3798cv200_caps),
.init = dw_mci_hi3798cv200_init,
.set_ios = dw_mci_hi3798cv200_set_ios,
.execute_tuning = dw_mci_hi3798cv200_execute_tuning,
......
......@@ -115,7 +115,7 @@
enum jz4740_mmc_version {
JZ_MMC_JZ4740,
JZ_MMC_JZ4750,
JZ_MMC_JZ4725B,
JZ_MMC_JZ4780,
};
......@@ -176,7 +176,7 @@ struct jz4740_mmc_host {
static void jz4740_mmc_write_irq_mask(struct jz4740_mmc_host *host,
uint32_t val)
{
if (host->version >= JZ_MMC_JZ4750)
if (host->version >= JZ_MMC_JZ4725B)
return writel(val, host->base + JZ_REG_MMC_IMASK);
else
return writew(val, host->base + JZ_REG_MMC_IMASK);
......@@ -1012,6 +1012,7 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
static const struct of_device_id jz4740_mmc_of_match[] = {
{ .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 },
{ .compatible = "ingenic,jz4725b-mmc", .data = (void *)JZ_MMC_JZ4725B },
{ .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 },
{},
};
......
......@@ -294,7 +294,7 @@ static void meson_mx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_OFF:
vdd = 0;
/* fall-through: */
/* fall through */
case MMC_POWER_UP:
if (!IS_ERR(mmc->supply.vmmc)) {
host->error = mmc_regulator_set_ocr(mmc,
......
This diff is collapsed.
This diff is collapsed.
......@@ -119,19 +119,23 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name)
}
/* Initialize the dml hardware connected to SD Card controller */
static void qcom_dma_setup(struct mmci_host *host)
static int qcom_dma_setup(struct mmci_host *host)
{
u32 config;
void __iomem *base;
int consumer_id, producer_id;
struct device_node *np = host->mmc->parent->of_node;
if (mmci_dmae_setup(host))
return -EINVAL;
consumer_id = of_get_dml_pipe_index(np, "tx");
producer_id = of_get_dml_pipe_index(np, "rx");
if (producer_id < 0 || consumer_id < 0) {
host->variant->qcom_dml = false;
return;
mmci_dmae_release(host);
return -EINVAL;
}
base = host->base + DML_OFFSET;
......@@ -175,10 +179,19 @@ static void qcom_dma_setup(struct mmci_host *host)
/* Make sure dml initialization is finished */
mb();
return 0;
}
static struct mmci_host_ops qcom_variant_ops = {
.prep_data = mmci_dmae_prep_data,
.unprep_data = mmci_dmae_unprep_data,
.get_next_data = mmci_dmae_get_next_data,
.dma_setup = qcom_dma_setup,
.dma_release = mmci_dmae_release,
.dma_start = mmci_dmae_start,
.dma_finalize = mmci_dmae_finalize,
.dma_error = mmci_dmae_error,
};
void qcom_variant_init(struct mmci_host *host)
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics 2018 - All Rights Reserved
* Author: Ludovic.barre@st.com for STMicroelectronics.
*/
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/reset.h>
#include <linux/scatterlist.h>
#include "mmci.h"
#define SDMMC_LLI_BUF_LEN PAGE_SIZE
#define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT)
struct sdmmc_lli_desc {
u32 idmalar;
u32 idmabase;
u32 idmasize;
};
struct sdmmc_priv {
dma_addr_t sg_dma;
void *sg_cpu;
};
int sdmmc_idma_validate_data(struct mmci_host *host,
struct mmc_data *data)
{
struct scatterlist *sg;
int i;
/*
* idma has constraints on idmabase & idmasize for each element
* excepted the last element which has no constraint on idmasize
*/
for_each_sg(data->sg, sg, data->sg_len - 1, i) {
if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32)) ||
!IS_ALIGNED(sg_dma_len(data->sg), SDMMC_IDMA_BURST)) {
dev_err(mmc_dev(host->mmc),
"unaligned scatterlist: ofst:%x length:%d\n",
data->sg->offset, data->sg->length);
return -EINVAL;
}
}
if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32))) {
dev_err(mmc_dev(host->mmc),
"unaligned last scatterlist: ofst:%x length:%d\n",
data->sg->offset, data->sg->length);
return -EINVAL;
}
return 0;
}
static int _sdmmc_idma_prep_data(struct mmci_host *host,
struct mmc_data *data)
{
int n_elem;
n_elem = dma_map_sg(mmc_dev(host->mmc),
data->sg,
data->sg_len,
mmc_get_dma_dir(data));
if (!n_elem) {
dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n");
return -EINVAL;
}
return 0;
}
static int sdmmc_idma_prep_data(struct mmci_host *host,
struct mmc_data *data, bool next)
{
/* Check if job is already prepared. */
if (!next && data->host_cookie == host->next_cookie)
return 0;
return _sdmmc_idma_prep_data(host, data);
}
static void sdmmc_idma_unprep_data(struct mmci_host *host,
struct mmc_data *data, int err)
{
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
mmc_get_dma_dir(data));
}
static int sdmmc_idma_setup(struct mmci_host *host)
{
struct sdmmc_priv *idma;
idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL);
if (!idma)
return -ENOMEM;
host->dma_priv = idma;
if (host->variant->dma_lli) {
idma->sg_cpu = dmam_alloc_coherent(mmc_dev(host->mmc),
SDMMC_LLI_BUF_LEN,
&idma->sg_dma, GFP_KERNEL);
if (!idma->sg_cpu) {
dev_err(mmc_dev(host->mmc),
"Failed to alloc IDMA descriptor\n");
return -ENOMEM;
}
host->mmc->max_segs = SDMMC_LLI_BUF_LEN /
sizeof(struct sdmmc_lli_desc);
host->mmc->max_seg_size = host->variant->stm32_idmabsize_mask;
} else {
host->mmc->max_segs = 1;
host->mmc->max_seg_size = host->mmc->max_req_size;
}
return 0;
}
static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl)
{
struct sdmmc_priv *idma = host->dma_priv;
struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu;
struct mmc_data *data = host->data;
struct scatterlist *sg;
int i;
if (!host->variant->dma_lli || data->sg_len == 1) {
writel_relaxed(sg_dma_address(data->sg),
host->base + MMCI_STM32_IDMABASE0R);
writel_relaxed(MMCI_STM32_IDMAEN,
host->base + MMCI_STM32_IDMACTRLR);
return 0;
}
for_each_sg(data->sg, sg, data->sg_len, i) {
desc[i].idmalar = (i + 1) * sizeof(struct sdmmc_lli_desc);
desc[i].idmalar |= MMCI_STM32_ULA | MMCI_STM32_ULS
| MMCI_STM32_ABR;
desc[i].idmabase = sg_dma_address(sg);
desc[i].idmasize = sg_dma_len(sg);
}
/* notice the end of link list */
desc[data->sg_len - 1].idmalar &= ~MMCI_STM32_ULA;
dma_wmb();
writel_relaxed(idma->sg_dma, host->base + MMCI_STM32_IDMABAR);
writel_relaxed(desc[0].idmalar, host->base + MMCI_STM32_IDMALAR);
writel_relaxed(desc[0].idmabase, host->base + MMCI_STM32_IDMABASE0R);
writel_relaxed(desc[0].idmasize, host->base + MMCI_STM32_IDMABSIZER);
writel_relaxed(MMCI_STM32_IDMAEN | MMCI_STM32_IDMALLIEN,
host->base + MMCI_STM32_IDMACTRLR);
return 0;
}
static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data)
{
writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR);
}
static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired)
{
unsigned int clk = 0, ddr = 0;
if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52 ||
host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
ddr = MCI_STM32_CLK_DDR;
/*
* cclk = mclk / (2 * clkdiv)
* clkdiv 0 => bypass
* in ddr mode bypass is not possible
*/
if (desired) {
if (desired >= host->mclk && !ddr) {
host->cclk = host->mclk;
} else {
clk = DIV_ROUND_UP(host->mclk, 2 * desired);
if (clk > MCI_STM32_CLK_CLKDIV_MSK)
clk = MCI_STM32_CLK_CLKDIV_MSK;
host->cclk = host->mclk / (2 * clk);
}
} else {
/*
* while power-on phase the clock can't be define to 0,
* Only power-off and power-cyc deactivate the clock.
* if desired clock is 0, set max divider
*/
clk = MCI_STM32_CLK_CLKDIV_MSK;
host->cclk = host->mclk / (2 * clk);
}
/* Set actual clock for debug */
if (host->mmc->ios.power_mode == MMC_POWER_ON)
host->mmc->actual_clock = host->cclk;
else
host->mmc->actual_clock = 0;
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
clk |= MCI_STM32_CLK_WIDEBUS_4;
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
clk |= MCI_STM32_CLK_WIDEBUS_8;
clk |= MCI_STM32_CLK_HWFCEN;
clk |= host->clk_reg_add;
clk |= ddr;
/*
* SDMMC_FBCK is selected when an external Delay Block is needed
* with SDR104.
*/
if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) {
clk |= MCI_STM32_CLK_BUSSPEED;
if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) {
clk &= ~MCI_STM32_CLK_SEL_MSK;
clk |= MCI_STM32_CLK_SELFBCK;
}
}
mmci_write_clkreg(host, clk);
}
static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr)
{
struct mmc_ios ios = host->mmc->ios;
pwr = host->pwr_reg_add;
if (ios.power_mode == MMC_POWER_OFF) {
/* Only a reset could power-off sdmmc */
reset_control_assert(host->rst);
udelay(2);
reset_control_deassert(host->rst);
/*
* Set the SDMMC in Power-cycle state.
* This will make that the SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK
* are driven low, to prevent the Card from being supplied
* through the signal lines.
*/
mmci_write_pwrreg(host, MCI_STM32_PWR_CYC | pwr);
} else if (ios.power_mode == MMC_POWER_ON) {
/*
* After power-off (reset): the irq mask defined in probe
* functionis lost
* ault irq mask (probe) must be activated
*/
writel(MCI_IRQENABLE | host->variant->start_err,
host->base + MMCIMASK0);
/*
* After a power-cycle state, we must set the SDMMC in
* Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are
* driven high. Then we can set the SDMMC to Power-on state
*/
mmci_write_pwrreg(host, MCI_PWR_OFF | pwr);
mdelay(1);
mmci_write_pwrreg(host, MCI_PWR_ON | pwr);
}
}
static struct mmci_host_ops sdmmc_variant_ops = {
.validate_data = sdmmc_idma_validate_data,
.prep_data = sdmmc_idma_prep_data,
.unprep_data = sdmmc_idma_unprep_data,
.dma_setup = sdmmc_idma_setup,
.dma_start = sdmmc_idma_start,
.dma_finalize = sdmmc_idma_finalize,
.set_clkreg = mmci_sdmmc_set_clkreg,
.set_pwrreg = mmci_sdmmc_set_pwrreg,
};
void sdmmc_variant_init(struct mmci_host *host)
{
host->ops = &sdmmc_variant_ops;
}
This diff is collapsed.
......@@ -728,7 +728,6 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
static irqreturn_t mxcmci_irq(int irq, void *devid)
{
struct mxcmci_host *host = devid;
unsigned long flags;
bool sdio_irq;
u32 stat;
......@@ -740,9 +739,9 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
spin_lock_irqsave(&host->lock, flags);
spin_lock(&host->lock);
sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
spin_unlock_irqrestore(&host->lock, flags);
spin_unlock(&host->lock);
if (mxcmci_use_dma(host) && (stat & (STATUS_WRITE_OP_DONE)))
mxcmci_writel(host, STATUS_WRITE_OP_DONE, MMC_REG_STATUS);
......
......@@ -30,7 +30,6 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/mmc/host.h>
#include <linux/mmc/core.h>
......@@ -38,7 +37,6 @@
#include <linux/mmc/slot-gpio.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
......@@ -198,7 +196,6 @@ struct omap_hsmmc_host {
struct dma_chan *rx_chan;
int response_busy;
int context_loss;
int protect_card;
int reqs_blocked;
int req_in_progress;
unsigned long clk_rate;
......@@ -207,16 +204,6 @@ struct omap_hsmmc_host {
#define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */
struct omap_hsmmc_next next_data;
struct omap_hsmmc_platform_data *pdata;
/* return MMC cover switch state, can be NULL if not supported.
*
* possible return values:
* 0 - closed
* 1 - open
*/
int (*get_cover_state)(struct device *dev);
int (*card_detect)(struct device *dev);
};
struct omap_mmc_of_data {
......@@ -226,20 +213,6 @@ struct omap_mmc_of_data {
static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host);
static int omap_hsmmc_card_detect(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
return mmc_gpio_get_cd(host->mmc);
}
static int omap_hsmmc_get_cover_state(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
return mmc_gpio_get_cd(host->mmc);
}
static int omap_hsmmc_enable_supply(struct mmc_host *mmc)
{
int ret;
......@@ -484,38 +457,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
return 0;
}
static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id);
static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
struct omap_hsmmc_host *host,
struct omap_hsmmc_platform_data *pdata)
{
int ret;
if (gpio_is_valid(pdata->gpio_cod)) {
ret = mmc_gpio_request_cd(mmc, pdata->gpio_cod, 0);
if (ret)
return ret;
host->get_cover_state = omap_hsmmc_get_cover_state;
mmc_gpio_set_cd_isr(mmc, omap_hsmmc_cover_irq);
} else if (gpio_is_valid(pdata->gpio_cd)) {
ret = mmc_gpio_request_cd(mmc, pdata->gpio_cd, 0);
if (ret)
return ret;
host->card_detect = omap_hsmmc_card_detect;
}
if (gpio_is_valid(pdata->gpio_wp)) {
ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp);
if (ret)
return ret;
}
return 0;
}
/*
* Start clock to the card
*/
......@@ -781,9 +722,6 @@ static void send_init_stream(struct omap_hsmmc_host *host)
int reg = 0;
unsigned long timeout;
if (host->protect_card)
return;
disable_irq(host->irq);
OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
......@@ -804,29 +742,6 @@ static void send_init_stream(struct omap_hsmmc_host *host)
enable_irq(host->irq);
}
static inline
int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
{
int r = 1;
if (host->get_cover_state)
r = host->get_cover_state(host->dev);
return r;
}
static ssize_t
omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
struct omap_hsmmc_host *host = mmc_priv(mmc);
return sprintf(buf, "%s\n",
omap_hsmmc_cover_is_closed(host) ? "closed" : "open");
}
static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL);
static ssize_t
omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
char *buf)
......@@ -1247,44 +1162,6 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
return ret;
}
/* Protect the card while the cover is open */
static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
{
if (!host->get_cover_state)
return;
host->reqs_blocked = 0;
if (host->get_cover_state(host->dev)) {
if (host->protect_card) {
dev_info(host->dev, "%s: cover is closed, "
"card is now accessible\n",
mmc_hostname(host->mmc));
host->protect_card = 0;
}
} else {
if (!host->protect_card) {
dev_info(host->dev, "%s: cover is open, "
"card is now inaccessible\n",
mmc_hostname(host->mmc));
host->protect_card = 1;
}
}
}
/*
* irq handler when (cell-phone) cover is mounted/removed
*/
static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id)
{
struct omap_hsmmc_host *host = dev_id;
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
omap_hsmmc_protect_card(host);
mmc_detect_change(host->mmc, (HZ * 200) / 1000);
return IRQ_HANDLED;
}
static void omap_hsmmc_dma_callback(void *param)
{
struct omap_hsmmc_host *host = param;
......@@ -1555,24 +1432,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
BUG_ON(host->req_in_progress);
BUG_ON(host->dma_ch != -1);
if (host->protect_card) {
if (host->reqs_blocked < 3) {
/*
* Ensure the controller is left in a consistent
* state by resetting the command and data state
* machines.
*/
omap_hsmmc_reset_controller_fsm(host, SRD);
omap_hsmmc_reset_controller_fsm(host, SRC);
host->reqs_blocked += 1;
}
req->cmd->error = -EBADF;
if (req->data)
req->data->error = -EBADF;
req->cmd->retries = 0;
mmc_request_done(mmc, req);
return;
} else if (host->reqs_blocked)
if (host->reqs_blocked)
host->reqs_blocked = 0;
WARN_ON(host->mrq != NULL);
host->mrq = req;
......@@ -1646,15 +1506,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
omap_hsmmc_set_bus_mode(host);
}
static int omap_hsmmc_get_cd(struct mmc_host *mmc)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
if (!host->card_detect)
return -ENOSYS;
return host->card_detect(host->dev);
}
static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
......@@ -1793,7 +1644,7 @@ static struct mmc_host_ops omap_hsmmc_ops = {
.pre_req = omap_hsmmc_pre_req,
.request = omap_hsmmc_request,
.set_ios = omap_hsmmc_set_ios,
.get_cd = omap_hsmmc_get_cd,
.get_cd = mmc_gpio_get_cd,
.get_ro = mmc_gpio_get_ro,
.init_card = omap_hsmmc_init_card,
.enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
......@@ -1920,10 +1771,6 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
if (of_find_property(np, "ti,dual-volt", NULL))
pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
pdata->gpio_cd = -EINVAL;
pdata->gpio_cod = -EINVAL;
pdata->gpio_wp = -EINVAL;
if (of_find_property(np, "ti,non-removable", NULL)) {
pdata->nonremovable = true;
pdata->no_regulator_off_init = true;
......@@ -2008,10 +1855,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->pbias_enabled = 0;
host->vqmmc_enabled = 0;
ret = omap_hsmmc_gpio_init(mmc, host, pdata);
if (ret)
goto err_gpio;
platform_set_drvdata(pdev, host);
if (pdev->dev.of_node)
......@@ -2125,8 +1968,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (!ret)
mmc->caps |= MMC_CAP_SDIO_IRQ;
omap_hsmmc_protect_card(host);
mmc_add_host(mmc);
if (mmc_pdata(host)->name != NULL) {
......@@ -2134,12 +1975,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (ret < 0)
goto err_slot_name;
}
if (host->get_cover_state) {
ret = device_create_file(&mmc->class_dev,
&dev_attr_cover_switch);
if (ret < 0)
goto err_slot_name;
}
omap_hsmmc_debugfs(mmc);
pm_runtime_mark_last_busy(host->dev);
......@@ -2161,7 +1996,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
err1:
err_gpio:
mmc_free_host(mmc);
err:
return ret;
......@@ -2231,7 +2065,6 @@ static int omap_hsmmc_resume(struct device *dev)
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
omap_hsmmc_conf_bus_power(host);
omap_hsmmc_protect_card(host);
pm_runtime_mark_last_busy(host->dev);
pm_runtime_put_autosuspend(host->dev);
return 0;
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Renesas Mobile SDHI
*
* Copyright (C) 2017 Horms Solutions Ltd., Simon Horman
* Copyright (C) 2017 Renesas Electronics Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef RENESAS_SDHI_H
......
// SPDX-License-Identifier: GPL-2.0
/*
* Renesas SDHI
*
......@@ -6,10 +7,6 @@
* Copyright (C) 2016-17 Horms Solutions, Simon Horman
* Copyright (C) 2009 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Based on "Compaq ASIC3 support":
*
* Copyright 2001 Compaq Computer Corporation.
......@@ -155,6 +152,52 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
return ret == 0 ? best_freq : clk_get_rate(priv->clk);
}
static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
unsigned int new_clock)
{
u32 clk = 0, clock;
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
if (new_clock == 0)
goto out;
/*
* Both HS400 and HS200/SD104 set 200MHz, but some devices need to
* set 400MHz to distinguish the CPG settings in HS400.
*/
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400 &&
new_clock == 200000000)
new_clock = 400000000;
clock = renesas_sdhi_clk_update(host, new_clock) / 512;
for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1)
clock <<= 1;
/* 1/1 clock is option */
if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1)) {
if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400))
clk |= 0xff;
else
clk &= ~0xff;
}
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
usleep_range(10000, 11000);
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
out:
/* HW engineers overrode docs: no sleep needed on R-Car2+ */
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
usleep_range(10000, 11000);
}
static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
......@@ -443,6 +486,19 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
bool use_4tap = host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400;
/*
* Skip checking SCC errors when running on 4 taps in HS400 mode as
* any retuning would still result in the same 4 taps being used.
*/
if (!(host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) &&
!(host->mmc->ios.timing == MMC_TIMING_MMC_HS200) &&
!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap))
return false;
if (mmc_doing_retune(host->mmc))
return false;
/* Check SCC error */
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
......@@ -620,8 +676,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->write16_hook = renesas_sdhi_write16_hook;
host->clk_enable = renesas_sdhi_clk_enable;
host->clk_update = renesas_sdhi_clk_update;
host->clk_disable = renesas_sdhi_clk_disable;
host->set_clock = renesas_sdhi_set_clock;
host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
host->dma_ops = dma_ops;
......
// SPDX-License-Identifier: GPL-2.0
/*
* DMA support for Internal DMAC with SDHI SD/SDIO controller
*
* Copyright (C) 2016-17 Renesas Electronics Corporation
* Copyright (C) 2016-17 Horms Solutions, Simon Horman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/bitops.h>
......@@ -35,8 +32,8 @@
/* DM_CM_DTRAN_MODE */
#define DTRAN_MODE_CH_NUM_CH0 0 /* "downstream" = for write commands */
#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "uptream" = for read commands */
#define DTRAN_MODE_BUS_WID_TH (BIT(5) | BIT(4))
#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "upstream" = for read commands */
#define DTRAN_MODE_BUS_WIDTH (BIT(5) | BIT(4))
#define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address */
/* DM_CM_DTRAN_CTRL */
......@@ -116,6 +113,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
};
static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_r8a7795_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_r8a7795_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
......@@ -174,7 +172,7 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
struct mmc_data *data)
{
struct scatterlist *sg = host->sg_ptr;
u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
u32 dtran_mode = DTRAN_MODE_BUS_WIDTH | DTRAN_MODE_ADDR_MODE;
if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
mmc_get_dma_dir(data)))
......@@ -201,13 +199,14 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
sg_dma_address(sg));
host->dma_on = true;
return;
force_pio_with_unmap:
dma_unmap_sg(&host->pdev->dev, sg, host->sg_len, mmc_get_dma_dir(data));
force_pio:
host->force_pio = true;
renesas_sdhi_internal_dmac_enable_dma(host, false);
}
......@@ -291,16 +290,19 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
* Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC
* implementation as others may use a different implementation.
*/
static const struct soc_device_attribute gen3_soc_whitelist[] = {
static const struct soc_device_attribute soc_whitelist[] = {
/* specific ones */
{ .soc_id = "r8a7795", .revision = "ES1.*",
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
{ .soc_id = "r8a7796", .revision = "ES1.0",
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
/* generic ones */
{ .soc_id = "r8a774a1" },
{ .soc_id = "r8a77470" },
{ .soc_id = "r8a7795" },
{ .soc_id = "r8a7796" },
{ .soc_id = "r8a77965" },
{ .soc_id = "r8a77970" },
{ .soc_id = "r8a77980" },
{ .soc_id = "r8a77995" },
{ /* sentinel */ }
......@@ -308,13 +310,21 @@ static const struct soc_device_attribute gen3_soc_whitelist[] = {
static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
{
const struct soc_device_attribute *soc = soc_device_match(gen3_soc_whitelist);
const struct soc_device_attribute *soc = soc_device_match(soc_whitelist);
struct device *dev = &pdev->dev;
if (!soc)
return -ENODEV;
global_flags |= (unsigned long)soc->data;
dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
if (!dev->dma_parms)
return -ENOMEM;
/* value is max of SD_SECCNT. Confirmed by HW engineers */
dma_set_max_seg_size(dev, 0xffffffff);
return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* DMA support use of SYS DMAC with SDHI SD/SDIO controller
*
......@@ -5,10 +6,6 @@
* Copyright (C) 2016-17 Sang Engineering, Wolfram Sang
* Copyright (C) 2017 Horms Solutions, Simon Horman
* Copyright (C) 2010-2011 Guennadi Liakhovetski
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/device.h>
......@@ -213,10 +210,8 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)
goto pio;
}
if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
host->force_pio = true;
if (sg->length < TMIO_MMC_MIN_DMA_LEN)
return;
}
/* The only sg element can be unaligned, use our bounce buffer then */
if (!aligned) {
......@@ -240,6 +235,7 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)
desc = NULL;
ret = cookie;
}
host->dma_on = true;
}
pio:
if (!desc) {
......@@ -286,10 +282,8 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
goto pio;
}
if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
host->force_pio = true;
if (sg->length < TMIO_MMC_MIN_DMA_LEN)
return;
}
/* The only sg element can be unaligned, use our bounce buffer then */
if (!aligned) {
......@@ -318,6 +312,7 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
desc = NULL;
ret = cookie;
}
host->dma_on = true;
}
pio:
if (!desc) {
......
......@@ -76,6 +76,7 @@ struct sdhci_acpi_slot {
size_t priv_size;
int (*probe_slot)(struct platform_device *, const char *, const char *);
int (*remove_slot)(struct platform_device *);
int (*free_slot)(struct platform_device *pdev);
int (*setup_host)(struct platform_device *pdev);
};
......@@ -470,10 +471,70 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
.priv_size = sizeof(struct intel_host),
};
#define VENDOR_SPECIFIC_PWRCTL_CLEAR_REG 0x1a8
#define VENDOR_SPECIFIC_PWRCTL_CTL_REG 0x1ac
static irqreturn_t sdhci_acpi_qcom_handler(int irq, void *ptr)
{
struct sdhci_host *host = ptr;
sdhci_writel(host, 0x3, VENDOR_SPECIFIC_PWRCTL_CLEAR_REG);
sdhci_writel(host, 0x1, VENDOR_SPECIFIC_PWRCTL_CTL_REG);
return IRQ_HANDLED;
}
static int qcom_probe_slot(struct platform_device *pdev, const char *hid,
const char *uid)
{
struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
struct sdhci_host *host = c->host;
int *irq = sdhci_acpi_priv(c);
*irq = -EINVAL;
if (strcmp(hid, "QCOM8051"))
return 0;
*irq = platform_get_irq(pdev, 1);
if (*irq < 0)
return 0;
return request_threaded_irq(*irq, NULL, sdhci_acpi_qcom_handler,
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
"sdhci_qcom", host);
}
static int qcom_free_slot(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
struct sdhci_host *host = c->host;
struct acpi_device *adev;
int *irq = sdhci_acpi_priv(c);
const char *hid;
adev = ACPI_COMPANION(dev);
if (!adev)
return -ENODEV;
hid = acpi_device_hid(adev);
if (strcmp(hid, "QCOM8051"))
return 0;
if (*irq < 0)
return 0;
free_irq(*irq, host);
return 0;
}
static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
.quirks2 = SDHCI_QUIRK2_NO_1_8_V,
.caps = MMC_CAP_NONREMOVABLE,
.priv_size = sizeof(int),
.probe_slot = qcom_probe_slot,
.free_slot = qcom_free_slot,
};
static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
......@@ -756,6 +817,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
err_cleanup:
sdhci_cleanup_host(c->host);
err_free:
if (c->slot && c->slot->free_slot)
c->slot->free_slot(pdev);
sdhci_free_host(c->host);
return err;
}
......@@ -777,6 +841,10 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0);
sdhci_remove_host(c->host, dead);
if (c->slot && c->slot->free_slot)
c->slot->free_slot(pdev);
sdhci_free_host(c->host);
return 0;
......
......@@ -60,6 +60,7 @@
/* Tuning Block Control Register */
#define ESDHC_TBCTL 0x120
#define ESDHC_TB_EN 0x00000004
#define ESDHC_TBPTR 0x128
/* Control Register for DMA transfer */
#define ESDHC_DMA_SYSCTL 0x40c
......
......@@ -15,6 +15,7 @@
* iProc SDHCI platform driver
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mmc/host.h>
......@@ -162,9 +163,19 @@ static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg)
sdhci_iproc_writel(host, newval, reg & ~3);
}
static unsigned int sdhci_iproc_get_max_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
if (pltfm_host->clk)
return sdhci_pltfm_clk_get_max_clock(host);
else
return pltfm_host->clock;
}
static const struct sdhci_ops sdhci_iproc_ops = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_max_clock = sdhci_iproc_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
......@@ -178,7 +189,7 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = {
.write_w = sdhci_iproc_writew,
.write_b = sdhci_iproc_writeb,
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_max_clock = sdhci_iproc_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
......@@ -256,19 +267,25 @@ static const struct of_device_id sdhci_iproc_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match);
static const struct acpi_device_id sdhci_iproc_acpi_ids[] = {
{ .id = "BRCM5871", .driver_data = (kernel_ulong_t)&iproc_cygnus_data },
{ .id = "BRCM5872", .driver_data = (kernel_ulong_t)&iproc_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(acpi, sdhci_iproc_acpi_ids);
static int sdhci_iproc_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct sdhci_iproc_data *iproc_data;
struct device *dev = &pdev->dev;
const struct sdhci_iproc_data *iproc_data = NULL;
struct sdhci_host *host;
struct sdhci_iproc_host *iproc_host;
struct sdhci_pltfm_host *pltfm_host;
int ret;
match = of_match_device(sdhci_iproc_of_match, &pdev->dev);
if (!match)
return -EINVAL;
iproc_data = match->data;
iproc_data = device_get_match_data(dev);
if (!iproc_data)
return -ENODEV;
host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host));
if (IS_ERR(host))
......@@ -280,20 +297,22 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
iproc_host->data = iproc_data;
mmc_of_parse(host->mmc);
sdhci_get_of_property(pdev);
sdhci_get_property(pdev);
host->mmc->caps |= iproc_host->data->mmc_caps;
pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
if (dev->of_node) {
pltfm_host->clk = devm_clk_get(dev, NULL);
if (IS_ERR(pltfm_host->clk)) {
ret = PTR_ERR(pltfm_host->clk);
goto err;
}
ret = clk_prepare_enable(pltfm_host->clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable host clk\n");
dev_err(dev, "failed to enable host clk\n");
goto err;
}
}
if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) {
host->caps = iproc_host->data->caps;
......@@ -307,6 +326,7 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
return 0;
err_clk:
if (dev->of_node)
clk_disable_unprepare(pltfm_host->clk);
err:
sdhci_pltfm_free(pdev);
......@@ -317,6 +337,7 @@ static struct platform_driver sdhci_iproc_driver = {
.driver = {
.name = "sdhci-iproc",
.of_match_table = sdhci_iproc_of_match,
.acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids),
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_iproc_probe,
......
......@@ -107,6 +107,11 @@ struct sdhci_arasan_data {
#define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1)
};
struct sdhci_arasan_of_data {
const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
const struct sdhci_pltfm_data *pdata;
};
static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
.baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 },
.clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0},
......@@ -226,6 +231,25 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
}
}
static void sdhci_arasan_am654_set_clock(struct sdhci_host *host,
unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
if (sdhci_arasan->is_phy_on) {
phy_power_off(sdhci_arasan->phy);
sdhci_arasan->is_phy_on = false;
}
sdhci_set_clock(host, clock);
if (clock > PHY_CLK_TOO_SLOW_HZ) {
phy_power_on(sdhci_arasan->phy);
sdhci_arasan->is_phy_on = true;
}
}
static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios)
{
......@@ -307,6 +331,33 @@ static const struct sdhci_pltfm_data sdhci_arasan_pdata = {
SDHCI_QUIRK2_STOP_WITH_TC,
};
static struct sdhci_arasan_of_data sdhci_arasan_data = {
.pdata = &sdhci_arasan_pdata,
};
static const struct sdhci_ops sdhci_arasan_am654_ops = {
.set_clock = sdhci_arasan_am654_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_arasan_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static const struct sdhci_pltfm_data sdhci_arasan_am654_pdata = {
.ops = &sdhci_arasan_am654_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
};
static const struct sdhci_arasan_of_data sdhci_arasan_am654_data = {
.pdata = &sdhci_arasan_am654_pdata,
};
static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
{
int cmd_error = 0;
......@@ -363,6 +414,11 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
};
static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = {
.soc_ctl_map = &rk3399_soc_ctl_map,
.pdata = &sdhci_arasan_cqe_pdata,
};
#ifdef CONFIG_PM_SLEEP
/**
* sdhci_arasan_suspend - Suspend method for the driver
......@@ -462,14 +518,25 @@ static const struct of_device_id sdhci_arasan_of_match[] = {
/* SoC-specific compatible strings w/ soc_ctl_map */
{
.compatible = "rockchip,rk3399-sdhci-5.1",
.data = &rk3399_soc_ctl_map,
.data = &sdhci_arasan_rk3399_data,
},
{
.compatible = "ti,am654-sdhci-5.1",
.data = &sdhci_arasan_am654_data,
},
/* Generic compatible below here */
{ .compatible = "arasan,sdhci-8.9a" },
{ .compatible = "arasan,sdhci-5.1" },
{ .compatible = "arasan,sdhci-4.9a" },
{
.compatible = "arasan,sdhci-8.9a",
.data = &sdhci_arasan_data,
},
{
.compatible = "arasan,sdhci-5.1",
.data = &sdhci_arasan_data,
},
{
.compatible = "arasan,sdhci-4.9a",
.data = &sdhci_arasan_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
......@@ -707,14 +774,11 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_arasan_data *sdhci_arasan;
struct device_node *np = pdev->dev.of_node;
const struct sdhci_pltfm_data *pdata;
if (of_device_is_compatible(pdev->dev.of_node, "arasan,sdhci-5.1"))
pdata = &sdhci_arasan_cqe_pdata;
else
pdata = &sdhci_arasan_pdata;
const struct sdhci_arasan_of_data *data;
host = sdhci_pltfm_init(pdev, pdata, sizeof(*sdhci_arasan));
match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node);
data = match->data;
host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan));
if (IS_ERR(host))
return PTR_ERR(host);
......@@ -723,8 +787,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
sdhci_arasan->host = host;
match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node);
sdhci_arasan->soc_ctl_map = match->data;
sdhci_arasan->soc_ctl_map = data->soc_ctl_map;
node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0);
if (node) {
......@@ -788,6 +851,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
ret = mmc_of_parse(host->mmc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret);
goto unreg_clk;
}
......
......@@ -8,21 +8,51 @@
*/
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/sizes.h>
#include "sdhci-pltfm.h"
#define BOUNDARY_OK(addr, len) \
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
struct dwcmshc_priv {
struct clk *bus_clk;
};
/*
* If DMA addr spans 128MB boundary, we split the DMA transfer into two
* so that each DMA transfer doesn't exceed the boundary.
*/
static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
dma_addr_t addr, int len, unsigned int cmd)
{
int tmplen, offset;
if (likely(!len || BOUNDARY_OK(addr, len))) {
sdhci_adma_write_desc(host, desc, addr, len, cmd);
return;
}
offset = addr & (SZ_128M - 1);
tmplen = SZ_128M - offset;
sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
addr += tmplen;
len -= tmplen;
sdhci_adma_write_desc(host, desc, addr, len, cmd);
}
static const struct sdhci_ops sdhci_dwcmshc_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.reset = sdhci_reset,
.adma_write_desc = dwcmshc_adma_write_desc,
};
static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
......@@ -36,12 +66,21 @@ static int dwcmshc_probe(struct platform_device *pdev)
struct sdhci_host *host;
struct dwcmshc_priv *priv;
int err;
u32 extra;
host = sdhci_pltfm_init(pdev, &sdhci_dwcmshc_pdata,
sizeof(struct dwcmshc_priv));
if (IS_ERR(host))
return PTR_ERR(host);
/*
* extra adma table cnt for cross 128M boundary handling.
*/
extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M);
if (extra > SDHCI_MAX_SEGS)
extra = SDHCI_MAX_SEGS;
host->adma_table_cnt += extra;
pltfm_host = sdhci_priv(host);
priv = sdhci_pltfm_priv(pltfm_host);
......
......@@ -78,8 +78,10 @@ struct sdhci_esdhc {
u8 vendor_ver;
u8 spec_ver;
bool quirk_incorrect_hostver;
bool quirk_fixup_tuning;
unsigned int peripheral_clock;
const struct esdhc_clk_fixup *clk_fixup;
u32 div_ratio;
};
/**
......@@ -580,6 +582,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
clock, host->max_clk / pre_div / div);
host->mmc->actual_clock = host->max_clk / pre_div / div;
esdhc->div_ratio = pre_div * div;
pre_div >>= 1;
div--;
......@@ -712,9 +715,24 @@ static int esdhc_signal_voltage_switch(struct mmc_host *mmc,
}
}
static struct soc_device_attribute soc_fixup_tuning[] = {
{ .family = "QorIQ T1040", .revision = "1.0", },
{ .family = "QorIQ T2080", .revision = "1.0", },
{ .family = "QorIQ T1023", .revision = "1.0", },
{ .family = "QorIQ LS1021A", .revision = "1.0", },
{ .family = "QorIQ LS1080A", .revision = "1.0", },
{ .family = "QorIQ LS2080A", .revision = "1.0", },
{ .family = "QorIQ LS1012A", .revision = "1.0", },
{ .family = "QorIQ LS1043A", .revision = "1.*", },
{ .family = "QorIQ LS1046A", .revision = "1.0", },
{ },
};
static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
u32 val;
/* Use tuning block for tuning procedure */
......@@ -728,7 +746,26 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_writel(host, val, ESDHC_TBCTL);
esdhc_clock_enable(host, true);
return sdhci_execute_tuning(mmc, opcode);
sdhci_execute_tuning(mmc, opcode);
if (host->tuning_err == -EAGAIN && esdhc->quirk_fixup_tuning) {
/* program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and
* program TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO
*/
val = sdhci_readl(host, ESDHC_TBPTR);
val = (val & ~((0x7f << 8) | 0x7f)) |
(3 * esdhc->div_ratio) | ((5 * esdhc->div_ratio) << 8);
sdhci_writel(host, val, ESDHC_TBPTR);
/* program the software tuning mode by setting
* TBCTL[TB_MODE]=2'h3
*/
val = sdhci_readl(host, ESDHC_TBCTL);
val |= 0x3;
sdhci_writel(host, val, ESDHC_TBCTL);
sdhci_execute_tuning(mmc, opcode);
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
......@@ -903,6 +940,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
esdhc = sdhci_pltfm_priv(pltfm_host);
if (soc_device_match(soc_fixup_tuning))
esdhc->quirk_fixup_tuning = true;
else
esdhc->quirk_fixup_tuning = false;
if (esdhc->vendor_ver == VENDOR_V_22)
host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
......
......@@ -490,6 +490,9 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
break;
case PCI_DEVICE_ID_O2_SEABIRD0:
if (chip->pdev->revision == 0x01)
chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER;
/* fall through */
case PCI_DEVICE_ID_O2_SEABIRD1:
/* UnLock WP */
ret = pci_read_config_byte(chip->pdev,
......
......@@ -30,6 +30,7 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/of.h>
#ifdef CONFIG_PPC
#include <asm/machdep.h>
......@@ -51,11 +52,10 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
#ifdef CONFIG_OF
static bool sdhci_of_wp_inverted(struct device_node *np)
static bool sdhci_wp_inverted(struct device *dev)
{
if (of_get_property(np, "sdhci,wp-inverted", NULL) ||
of_get_property(np, "wp-inverted", NULL))
if (device_property_present(dev, "sdhci,wp-inverted") ||
device_property_present(dev, "wp-inverted"))
return true;
/* Old device trees don't have the wp-inverted property. */
......@@ -66,52 +66,64 @@ static bool sdhci_of_wp_inverted(struct device_node *np)
#endif /* CONFIG_PPC */
}
void sdhci_get_of_property(struct platform_device *pdev)
#ifdef CONFIG_OF
static void sdhci_get_compatibility(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node;
if (!np)
return;
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
of_device_is_compatible(np, "fsl,p1010-esdhc") ||
of_device_is_compatible(np, "fsl,t4240-esdhc") ||
of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
}
#else
void sdhci_get_compatibility(struct platform_device *pdev) {}
#endif /* CONFIG_OF */
void sdhci_get_property(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
u32 bus_width;
if (of_get_property(np, "sdhci,auto-cmd12", NULL))
if (device_property_present(dev, "sdhci,auto-cmd12"))
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
(of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
if (device_property_present(dev, "sdhci,1-bit-only") ||
(device_property_read_u32(dev, "bus-width", &bus_width) == 0 &&
bus_width == 1))
host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
if (sdhci_of_wp_inverted(np))
if (sdhci_wp_inverted(dev))
host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
if (of_get_property(np, "broken-cd", NULL))
if (device_property_present(dev, "broken-cd"))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
if (of_get_property(np, "no-1-8-v", NULL))
if (device_property_present(dev, "no-1-8-v"))
host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
of_device_is_compatible(np, "fsl,p1010-esdhc") ||
of_device_is_compatible(np, "fsl,t4240-esdhc") ||
of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
sdhci_get_compatibility(pdev);
of_property_read_u32(np, "clock-frequency", &pltfm_host->clock);
device_property_read_u32(dev, "clock-frequency", &pltfm_host->clock);
if (of_find_property(np, "keep-power-in-suspend", NULL))
if (device_property_present(dev, "keep-power-in-suspend"))
host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
if (of_property_read_bool(np, "wakeup-source") ||
of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */
if (device_property_read_bool(dev, "wakeup-source") ||
device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
}
#else
void sdhci_get_of_property(struct platform_device *pdev) {}
#endif /* CONFIG_OF */
EXPORT_SYMBOL_GPL(sdhci_get_of_property);
EXPORT_SYMBOL_GPL(sdhci_get_property);
struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
const struct sdhci_pltfm_data *pdata,
......@@ -184,7 +196,7 @@ int sdhci_pltfm_register(struct platform_device *pdev,
if (IS_ERR(host))
return PTR_ERR(host);
sdhci_get_of_property(pdev);
sdhci_get_property(pdev);
ret = sdhci_add_host(host);
if (ret)
......
......@@ -90,7 +90,12 @@ static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
}
#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
extern void sdhci_get_of_property(struct platform_device *pdev);
void sdhci_get_property(struct platform_device *pdev);
static inline void sdhci_get_of_property(struct platform_device *pdev)
{
return sdhci_get_property(pdev);
}
extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
const struct sdhci_pltfm_data *pdata,
......
......@@ -21,17 +21,14 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/platform_data/pxa_sdhci.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/mbus.h>
......@@ -452,16 +449,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
host->mmc->caps2 |= pdata->host_caps2;
if (pdata->pm_caps)
host->mmc->pm_caps |= pdata->pm_caps;
if (gpio_is_valid(pdata->ext_cd_gpio)) {
ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio,
0);
if (ret) {
dev_err(mmc_dev(host->mmc),
"failed to allocate card detect gpio\n");
goto err_cd_req;
}
}
}
pm_runtime_get_noresume(&pdev->dev);
......@@ -486,7 +473,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
err_of_parse:
err_cd_req:
err_mbus_win:
clk_disable_unprepare(pxa->clk_io);
clk_disable_unprepare(pxa->clk_core);
......
......@@ -11,7 +11,6 @@
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h>
#include "sdhci-pltfm.h"
......@@ -19,10 +18,6 @@
#define SDHCI_SIRF_8BITBUS BIT(3)
#define SIRF_TUNING_COUNT 16384
struct sdhci_sirf_priv {
int gpio_cd;
};
static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
{
u8 ctrl;
......@@ -170,9 +165,7 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_sirf_priv *priv;
struct clk *clk;
int gpio_cd;
int ret;
clk = devm_clk_get(&pdev->dev, NULL);
......@@ -181,19 +174,12 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
return PTR_ERR(clk);
}
if (pdev->dev.of_node)
gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0);
else
gpio_cd = -EINVAL;
host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv));
host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, 0);
if (IS_ERR(host))
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
pltfm_host->clk = clk;
priv = sdhci_pltfm_priv(pltfm_host);
priv->gpio_cd = gpio_cd;
sdhci_get_of_property(pdev);
......@@ -209,15 +195,11 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
* We must request the IRQ after sdhci_add_host(), as the tasklet only
* gets setup in sdhci_add_host() and we oops.
*/
if (gpio_is_valid(priv->gpio_cd)) {
ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0);
if (ret) {
dev_err(&pdev->dev, "card detect irq request failed: %d\n",
ret);
ret = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0, NULL);
if (ret == -EPROBE_DEFER)
goto err_request_cd;
}
if (!ret)
mmc_gpiod_request_cd_irq(host->mmc);
}
return 0;
......
......@@ -15,13 +15,11 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
......@@ -32,7 +30,6 @@
struct spear_sdhci {
struct clk *clk;
int card_int_gpio;
};
/* sdhci ops */
......@@ -43,18 +40,6 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static void sdhci_probe_config_dt(struct device_node *np,
struct spear_sdhci *host)
{
int cd_gpio;
cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
if (!gpio_is_valid(cd_gpio))
cd_gpio = -1;
host->card_int_gpio = cd_gpio;
}
static int sdhci_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
......@@ -109,21 +94,13 @@ static int sdhci_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",
clk_get_rate(sdhci->clk));
sdhci_probe_config_dt(pdev->dev.of_node, sdhci);
/*
* It is optional to use GPIOs for sdhci card detection. If
* sdhci->card_int_gpio < 0, then use original sdhci lines otherwise
* GPIO lines. We use the built-in GPIO support for this.
* It is optional to use GPIOs for sdhci card detection. If we
* find a descriptor using slot GPIO, we use it.
*/
if (sdhci->card_int_gpio >= 0) {
ret = mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0);
if (ret < 0) {
dev_dbg(&pdev->dev,
"failed to request card-detect gpio%d\n",
sdhci->card_int_gpio);
ret = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0, NULL);
if (ret == -EPROBE_DEFER)
goto disable_clk;
}
}
ret = sdhci_add_host(host);
if (ret)
......
This diff is collapsed.
This diff is collapsed.
......@@ -660,8 +660,8 @@ static int get_dt_pad_ctrl_data(struct sdhci_host *host,
return 0;
if (of_address_to_resource(np, 1, &iomem)) {
dev_err(mmc_dev(host->mmc), "Unable to find SoC PAD ctrl register address for %s\n",
np->name);
dev_err(mmc_dev(host->mmc), "Unable to find SoC PAD ctrl register address for %pOFn\n",
np);
return -EINVAL;
}
......
This diff is collapsed.
......@@ -28,6 +28,7 @@
#define SDHCI_DMA_ADDRESS 0x00
#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS
#define SDHCI_32BIT_BLK_CNT SDHCI_DMA_ADDRESS
#define SDHCI_BLOCK_SIZE 0x04
#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
......@@ -41,6 +42,7 @@
#define SDHCI_TRNS_BLK_CNT_EN 0x02
#define SDHCI_TRNS_AUTO_CMD12 0x04
#define SDHCI_TRNS_AUTO_CMD23 0x08
#define SDHCI_TRNS_AUTO_SEL 0x0C
#define SDHCI_TRNS_READ 0x10
#define SDHCI_TRNS_MULTI 0x20
......@@ -184,6 +186,9 @@
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
#define SDHCI_CTRL_EXEC_TUNING 0x0040
#define SDHCI_CTRL_TUNED_CLK 0x0080
#define SDHCI_CMD23_ENABLE 0x0800
#define SDHCI_CTRL_V4_MODE 0x1000
#define SDHCI_CTRL_64BIT_ADDR 0x2000
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
#define SDHCI_CAPABILITIES 0x40
......@@ -204,6 +209,7 @@
#define SDHCI_CAN_VDD_330 0x01000000
#define SDHCI_CAN_VDD_300 0x02000000
#define SDHCI_CAN_VDD_180 0x04000000
#define SDHCI_CAN_64BIT_V4 0x08000000
#define SDHCI_CAN_64BIT 0x10000000
#define SDHCI_SUPPORT_SDR50 0x00000001
......@@ -270,6 +276,9 @@
#define SDHCI_SPEC_100 0
#define SDHCI_SPEC_200 1
#define SDHCI_SPEC_300 2
#define SDHCI_SPEC_400 3
#define SDHCI_SPEC_410 4
#define SDHCI_SPEC_420 5
/*
* End of controller registers.
......@@ -305,8 +314,14 @@ struct sdhci_adma2_32_desc {
*/
#define SDHCI_ADMA2_DESC_ALIGN 8
/* ADMA2 64-bit DMA descriptor size */
#define SDHCI_ADMA2_64_DESC_SZ 12
/*
* ADMA2 64-bit DMA descriptor size
* According to SD Host Controller spec v4.10, there are two kinds of
* descriptors for 64-bit addressing mode: 96-bit Descriptor and 128-bit
* Descriptor, if Host Version 4 Enable is set in the Host Control 2
* register, 128-bit Descriptor will be selected.
*/
#define SDHCI_ADMA2_64_DESC_SZ(host) ((host)->v4_mode ? 16 : 12)
/*
* ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
......@@ -450,6 +465,13 @@ struct sdhci_host {
* obtainable timeout.
*/
#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17)
/*
* 32-bit block count may not support eMMC where upper bits of CMD23 are used
* for other purposes. Consequently we support 16-bit block count by default.
* Otherwise, SDHCI_QUIRK2_USE_32BIT_BLK_CNT can be selected to use 32-bit
* block count.
*/
#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
......@@ -501,6 +523,7 @@ struct sdhci_host {
bool preset_enabled; /* Preset is enabled */
bool pending_reset; /* Cmd/data reset is pending */
bool irq_wake_enabled; /* IRQ wakeup is enabled */
bool v4_mode; /* Host Version 4 Enable */
struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */
struct mmc_command *cmd; /* Current command */
......@@ -554,6 +577,7 @@ struct sdhci_host {
unsigned int tuning_count; /* Timer count for re-tuning */
unsigned int tuning_mode; /* Re-tuning mode supported by host */
unsigned int tuning_err; /* Error code for re-tuning */
#define SDHCI_TUNING_MODE_1 0
#define SDHCI_TUNING_MODE_2 1
#define SDHCI_TUNING_MODE_3 2
......@@ -563,6 +587,9 @@ struct sdhci_host {
/* Host SDMA buffer boundary. */
u32 sdma_boundary;
/* Host ADMA table count */
u32 adma_table_cnt;
u64 data_timeout;
unsigned long private[0] ____cacheline_aligned;
......@@ -603,6 +630,8 @@ struct sdhci_ops {
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*card_event)(struct sdhci_host *host);
void (*voltage_switch)(struct sdhci_host *host);
void (*adma_write_desc)(struct sdhci_host *host, void **desc,
dma_addr_t addr, int len, unsigned int cmd);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
......@@ -725,6 +754,7 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
unsigned short vdd);
void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
unsigned short vdd);
void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq);
void sdhci_set_bus_width(struct sdhci_host *host, int width);
void sdhci_reset(struct sdhci_host *host, u8 mask);
void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
......@@ -733,6 +763,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
struct mmc_ios *ios);
void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
dma_addr_t addr, int len, unsigned int cmd);
#ifdef CONFIG_PM
int sdhci_suspend_host(struct sdhci_host *host);
......@@ -747,6 +779,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
int *data_error);
void sdhci_dumpregs(struct sdhci_host *host);
void sdhci_enable_v4_mode(struct sdhci_host *host);
void sdhci_start_tuning(struct sdhci_host *host);
void sdhci_end_tuning(struct sdhci_host *host);
......
// SPDX-License-Identifier: GPL-2.0
/*
* MMCIF eMMC driver.
*
* Copyright (C) 2010 Renesas Solutions Corp.
* Yusuke Goda <yusuke.goda.sx@renesas.com>
*
* 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.
*/
/*
......@@ -1573,6 +1570,6 @@ static struct platform_driver sh_mmcif_driver = {
module_platform_driver(sh_mmcif_driver);
MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");
......@@ -258,11 +258,16 @@ struct sunxi_mmc_cfg {
/* Does DATA0 needs to be masked while the clock is updated */
bool mask_data0;
/* hardware only supports new timing mode */
/*
* hardware only supports new timing mode, either due to lack of
* a mode switch in the clock controller, or the mmc controller
* is permanently configured in the new timing mode, without the
* NTSR mode switch.
*/
bool needs_new_timings;
/* hardware can switch between old and new timing modes */
bool has_timings_switch;
/* clock hardware can switch between old and new timing modes */
bool ccu_has_timings_switch;
};
struct sunxi_mmc_host {
......@@ -787,7 +792,7 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
clock <<= 1;
}
if (host->use_new_timings && host->cfg->has_timings_switch) {
if (host->use_new_timings && host->cfg->ccu_has_timings_switch) {
ret = sunxi_ccu_set_mmc_timing_mode(host->clk_mmc, true);
if (ret) {
dev_err(mmc_dev(mmc),
......@@ -822,6 +827,12 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
/* update card clock rate to account for internal divider */
rate /= div;
/*
* Configure the controller to use the new timing mode if needed.
* On controllers that only support the new timing mode, such as
* the eMMC controller on the A64, this register does not exist,
* and any writes to it are ignored.
*/
if (host->use_new_timings) {
/* Don't touch the delay bits */
rval = mmc_readl(host, REG_SD_NTSR);
......@@ -1145,7 +1156,7 @@ static const struct sunxi_mmc_cfg sun8i_a83t_emmc_cfg = {
.idma_des_size_bits = 16,
.clk_delays = sunxi_mmc_clk_delays,
.can_calibrate = false,
.has_timings_switch = true,
.ccu_has_timings_switch = true,
};
static const struct sunxi_mmc_cfg sun9i_a80_cfg = {
......@@ -1166,6 +1177,7 @@ static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = {
.idma_des_size_bits = 13,
.clk_delays = NULL,
.can_calibrate = true,
.needs_new_timings = true,
};
static const struct of_device_id sunxi_mmc_of_match[] = {
......@@ -1351,7 +1363,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
goto error_free_host;
}
if (host->cfg->has_timings_switch) {
if (host->cfg->ccu_has_timings_switch) {
/*
* Supports both old and new timing modes.
* Try setting the clk to new timing mode.
......
......@@ -336,7 +336,8 @@ static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
rc |= TIFM_MMCSD_RSP_R0;
break;
case MMC_RSP_R1B:
rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
rc |= TIFM_MMCSD_RSP_BUSY;
/* fall-through */
case MMC_RSP_R1:
rc |= TIFM_MMCSD_RSP_R1;
break;
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for the MMC / SD / SDIO cell found in:
*
......@@ -8,11 +9,6 @@
* Copyright (C) 2016-17 Horms Solutions, Simon Horman
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef TMIO_MMC_H
......@@ -47,9 +43,6 @@
#define CTL_RESET_SD 0xe0
#define CTL_VERSION 0xe2
#define CTL_SDIF_MODE 0xe6
#define CTL_SDIO_REGS 0x100
#define CTL_CLK_AND_WAIT_CTL 0x138
#define CTL_RESET_SDIO 0x1e0
/* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
#define TMIO_STOP_STP BIT(0)
......@@ -133,7 +126,6 @@ struct tmio_mmc_host {
/* Callbacks for clock / power control */
void (*set_pwr)(struct platform_device *host, int state);
void (*set_clk_div)(struct platform_device *host, int state);
/* pio related stuff */
struct scatterlist *sg_ptr;
......@@ -146,7 +138,7 @@ struct tmio_mmc_host {
struct tmio_mmc_data *pdata;
/* DMA support */
bool force_pio;
bool dma_on;
struct dma_chan *chan_rx;
struct dma_chan *chan_tx;
struct tasklet_struct dma_issue;
......@@ -170,14 +162,14 @@ struct tmio_mmc_host {
/* Mandatory callback */
int (*clk_enable)(struct tmio_mmc_host *host);
void (*set_clock)(struct tmio_mmc_host *host, unsigned int clock);
/* Optional callbacks */
unsigned int (*clk_update)(struct tmio_mmc_host *host,
unsigned int new_clock);
void (*clk_disable)(struct tmio_mmc_host *host);
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
void (*reset)(struct tmio_mmc_host *host);
void (*hw_reset)(struct tmio_mmc_host *host);
void (*prepare_tuning)(struct tmio_mmc_host *host, unsigned long tap);
bool (*check_scc_error)(struct tmio_mmc_host *host);
......
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2013-2014 Renesas Electronics Europe Ltd.
* Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
......
......@@ -18,20 +18,13 @@
* mask into a value to be binary (or set some other custom bits
* in MMCIPWR) or:ed and written into the MMCIPWR register of the
* block. May also control external power based on the power_mode.
* @status: if no GPIO read function was given to the block in
* gpio_wp (below) this function will be called to determine
* whether a card is present in the MMC slot or not
* @gpio_wp: read this GPIO pin to see if the card is write protected
* @gpio_cd: read this GPIO pin to detect card insertion
* @cd_invert: true if the gpio_cd pin value is active low
* @status: if no GPIO line was given to the block in this function will
* be called to determine whether a card is present in the MMC slot or not
*/
struct mmci_platform_data {
unsigned int ocr_mask;
int (*ios_handler)(struct device *, struct mmc_ios *);
unsigned int (*status)(struct device *);
int gpio_wp;
int gpio_cd;
bool cd_invert;
};
#endif
This diff is collapsed.
......@@ -569,6 +569,11 @@ static inline bool mmc_can_retune(struct mmc_host *host)
return host->can_retune == 1;
}
static inline bool mmc_doing_retune(struct mmc_host *host)
{
return host->doing_retune == 1;
}
static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data)
{
return data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment