Commit be580e75 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Continue to re-factor code to prepare for eMMC CMDQ and blkmq support
   - Introduce queue semantics to prepare for eMMC CMDQ and blkmq support
   - Add helper functions to manage temporary enable/disable of eMMC CMDQ
   - Improve wait-busy detection for SDIO

  MMC host:
   - cavium: Add driver to support Cavium controllers
   - cavium: Extend Cavium driver to support Octeon and ThunderX SOCs
   - bcm2835: Add new driver for Broadcom BCM2835 controller
   - sdhci-xenon: Add driver to support Marvell Xenon SDHCI controller
   - sdhci-tegra: Add support for the Tegra186 variant
   - sdhci-of-esdhc: Support for UHS-I SD cards
   - sdhci-of-esdhc: Support for eMMC HS200 cards
   - sdhci-cadence: Add eMMC HS400 enhanced strobe support
   - sdhci-esdhc-imx: Reset tuning circuit when needed
   - sdhci-pci: Modernize and clean-up some PM related code
   - sdhci-pci: Avoid re-tuning at runtime PM for some Intel devices
   - sdhci-pci|acpi: Use aggressive PM for some Intel BYT controllers
   - sdhci: Re-factoring and modernizations
   - sdhci: Optimize delay loops
   - sdhci: Improve register dump print format
   - sdhci: Add support for the Command Queue Engine
   - meson-gx: Various improvements and clean-ups
   - meson-gx: Add support for CMD23
   - meson-gx: Basic tuning support to avoid CRC errors
   - s3cmci: Enable probing via DT
   - mediatek: Improve tuning support for eMMC HS200 and HS400 mode
   - tmio: Improve DMA support
   - tmio: Use correct response for CMD12
   - dw_mmc: Minor improvements and clean-ups"

* tag 'mmc-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (148 commits)
  mmc: sdhci-of-esdhc: limit SD clock for ls1012a/ls1046a
  mmc: sdhci-of-esdhc: poll ESDHC_CLOCK_STABLE bit with udelay
  mmc: sdhci-xenon: Fix default value of LOGIC_TIMING_ADJUST for eMMC5.0 PHY
  mmc: sdhci-xenon: Fix the work flow in xenon_remove().
  MIPS: Octeon: cavium_octeon_defconfig: Enable Octeon MMC
  mmc: sdhci-xenon: Remove redundant dev_err call in get_dt_pad_ctrl_data()
  mmc: cavium: Use module_pci_driver to simplify the code
  mmc: cavium: Add MMC support for Octeon SOCs.
  mmc: cavium: Fix detection of block or byte addressing.
  mmc: core: Export API to allow hosts to get the card address
  mmc: sdio: Fix sdio wait busy implement limitation
  mmc: sdhci-esdhc-imx: reset tuning circuit when power on mmc card
  clk: apn806: fix spelling mistake: "mising" -> "missing"
  mmc: sdhci-of-esdhc: add delay between tuning cycles
  mmc: sdhci: Control the delay between tuning commands
  mmc: sdhci-of-esdhc: add tuning support
  mmc: sdhci-of-esdhc: add support for signal voltage switch
  mmc: sdhci-of-esdhc: add peripheral clock support
  mmc: sdhci-pci: Allow for 3 bytes from Intel DSM
  mmc: cavium: Fix a shift wrapping bug
  ...
parents 8d65b08d a627f025
Broadcom BCM2835 SDHOST controller
This file documents differences between the core properties described
by mmc.txt and the properties that represent the BCM2835 controller.
Required properties:
- compatible: Should be "brcm,bcm2835-sdhost".
- clocks: The clock feeding the SDHOST controller.
Optional properties:
- dmas: DMA channel for read and write.
See Documentation/devicetree/bindings/dma/dma.txt for details
Example:
sdhost: mmc@7e202000 {
compatible = "brcm,bcm2835-sdhost";
reg = <0x7e202000 0x100>;
interrupts = <2 24>;
clocks = <&clocks BCM2835_CLOCK_VPU>;
dmas = <&dma 13>;
dma-names = "rx-tx";
};
* Cavium Octeon & ThunderX MMC controller
The highspeed MMC host controller on Caviums SoCs provides an interface
for MMC and SD types of memory cards.
Supported maximum speeds are the ones of the eMMC standard 4.41 as well
as the speed of SD standard 4.0. Only 3.3 Volt is supported.
Required properties:
- compatible : should be one of:
cavium,octeon-6130-mmc
cavium,octeon-7890-mmc
cavium,thunder-8190-mmc
cavium,thunder-8390-mmc
mmc-slot
- reg : mmc controller base registers
- clocks : phandle
Optional properties:
- for cd, bus-width and additional generic mmc parameters
please refer to mmc.txt within this directory
- cavium,cmd-clk-skew : number of coprocessor clocks before sampling command
- cavium,dat-clk-skew : number of coprocessor clocks before sampling data
Deprecated properties:
- spi-max-frequency : use max-frequency instead
- cavium,bus-max-width : use bus-width instead
- power-gpios : use vmmc-supply instead
- cavium,octeon-6130-mmc-slot : use mmc-slot instead
Examples:
mmc_1_4: mmc@1,4 {
compatible = "cavium,thunder-8390-mmc";
reg = <0x0c00 0 0 0 0>; /* DEVFN = 0x0c (1:4) */
#address-cells = <1>;
#size-cells = <0>;
clocks = <&sclk>;
mmc-slot@0 {
compatible = "mmc-slot";
reg = <0>;
vmmc-supply = <&mmc_supply_3v3>;
max-frequency = <42000000>;
bus-width = <4>;
cap-sd-highspeed;
};
mmc-slot@1 {
compatible = "mmc-slot";
reg = <1>;
vmmc-supply = <&mmc_supply_3v3>;
max-frequency = <42000000>;
bus-width = <8>;
cap-mmc-highspeed;
non-removable;
};
};
Marvell Xenon SDHCI Controller device tree bindings
This file documents differences between the core mmc properties
described by mmc.txt and the properties used by the Xenon implementation.
Multiple SDHCs might be put into a single Xenon IP, to save size and cost.
Each SDHC is independent and owns independent resources, such as register sets,
clock and PHY.
Each SDHC should have an independent device tree node.
Required Properties:
- compatible: should be one of the following
- "marvell,armada-3700-sdhci": For controllers on Armada-3700 SoC.
Must provide a second register area and marvell,pad-type.
- "marvell,armada-ap806-sdhci": For controllers on Armada AP806.
- "marvell,armada-cp110-sdhci": For controllers on Armada CP110.
- clocks:
Array of clocks required for SDHC.
Require at least input clock for Xenon IP core.
- clock-names:
Array of names corresponding to clocks property.
The input clock for Xenon IP core should be named as "core".
- reg:
* For "marvell,armada-3700-sdhci", two register areas.
The first one for Xenon IP register. The second one for the Armada 3700 SoC
PHY PAD Voltage Control register.
Please follow the examples with compatible "marvell,armada-3700-sdhci"
in below.
Please also check property marvell,pad-type in below.
* For other compatible strings, one register area for Xenon IP.
Optional Properties:
- marvell,xenon-sdhc-id:
Indicate the corresponding bit index of current SDHC in
SDHC System Operation Control Register Bit[7:0].
Set/clear the corresponding bit to enable/disable current SDHC.
If Xenon IP contains only one SDHC, this property is optional.
- marvell,xenon-phy-type:
Xenon support multiple types of PHYs.
To select eMMC 5.1 PHY, set:
marvell,xenon-phy-type = "emmc 5.1 phy"
eMMC 5.1 PHY is the default choice if this property is not provided.
To select eMMC 5.0 PHY, set:
marvell,xenon-phy-type = "emmc 5.0 phy"
All those types of PHYs can support eMMC, SD and SDIO.
Please note that this property only presents the type of PHY.
It doesn't stand for the entire SDHC type or property.
For example, "emmc 5.1 phy" doesn't mean that this Xenon SDHC only
supports eMMC 5.1.
- marvell,xenon-phy-znr:
Set PHY ZNR value.
Only available for eMMC PHY.
Valid range = [0:0x1F].
ZNR is set as 0xF by default if this property is not provided.
- marvell,xenon-phy-zpr:
Set PHY ZPR value.
Only available for eMMC PHY.
Valid range = [0:0x1F].
ZPR is set as 0xF by default if this property is not provided.
- marvell,xenon-phy-nr-success-tun:
Set the number of required consecutive successful sampling points
used to identify a valid sampling window, in tuning process.
Valid range = [1:7].
Set as 0x4 by default if this property is not provided.
- marvell,xenon-phy-tun-step-divider:
Set the divider for calculating TUN_STEP.
Set as 64 by default if this property is not provided.
- marvell,xenon-phy-slow-mode:
If this property is selected, transfers will bypass PHY.
Only available when bus frequency lower than 55MHz in SDR mode.
Disabled by default. Please only try this property if timing issues
always occur with PHY enabled in eMMC HS SDR, SD SDR12, SD SDR25,
SD Default Speed and HS mode and eMMC legacy speed mode.
- marvell,xenon-tun-count:
Xenon SDHC SoC usually doesn't provide re-tuning counter in
Capabilities Register 3 Bit[11:8].
This property provides the re-tuning counter.
If this property is not set, default re-tuning counter will
be set as 0x9 in driver.
- marvell,pad-type:
Type of Armada 3700 SoC PHY PAD Voltage Controller register.
Only valid when "marvell,armada-3700-sdhci" is selected.
Two types: "sd" and "fixed-1-8v".
If "sd" is selected, SoC PHY PAD is set as 3.3V at the beginning and is
switched to 1.8V when later in higher speed mode.
If "fixed-1-8v" is selected, SoC PHY PAD is fixed 1.8V, such as for eMMC.
Please follow the examples with compatible "marvell,armada-3700-sdhci"
in below.
Example:
- For eMMC:
sdhci@aa0000 {
compatible = "marvell,armada-ap806-sdhci";
reg = <0xaa0000 0x1000>;
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>
clocks = <&emmc_clk>;
clock-names = "core";
bus-width = <4>;
marvell,xenon-phy-slow-mode;
marvell,xenon-tun-count = <11>;
non-removable;
no-sd;
no-sdio;
/* Vmmc and Vqmmc are both fixed */
};
- For SD/SDIO:
sdhci@ab0000 {
compatible = "marvell,armada-cp110-sdhci";
reg = <0xab0000 0x1000>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>
vqmmc-supply = <&sd_vqmmc_regulator>;
vmmc-supply = <&sd_vmmc_regulator>;
clocks = <&sdclk>;
clock-names = "core";
bus-width = <4>;
marvell,xenon-tun-count = <9>;
};
- For eMMC with compatible "marvell,armada-3700-sdhci":
sdhci@aa0000 {
compatible = "marvell,armada-3700-sdhci";
reg = <0xaa0000 0x1000>,
<phy_addr 0x4>;
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>
clocks = <&emmcclk>;
clock-names = "core";
bus-width = <8>;
mmc-ddr-1_8v;
mmc-hs400-1_8v;
non-removable;
no-sd;
no-sdio;
/* Vmmc and Vqmmc are both fixed */
marvell,pad-type = "fixed-1-8v";
};
- For SD/SDIO with compatible "marvell,armada-3700-sdhci":
sdhci@ab0000 {
compatible = "marvell,armada-3700-sdhci";
reg = <0xab0000 0x1000>,
<phy_addr 0x4>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>
vqmmc-supply = <&sd_regulator>;
/* Vmmc is fixed */
clocks = <&sdclk>;
clock-names = "core";
bus-width = <4>;
marvell,pad-type = "sd";
};
......@@ -21,6 +21,15 @@ Optional properties:
- assigned-clocks: PLL of the source clock
- assigned-clock-parents: parent of source clock, used for HS400 mode to get 400Mhz source clock
- hs400-ds-delay: HS400 DS delay setting
- mediatek,hs200-cmd-int-delay: HS200 command internal delay setting.
This field has total 32 stages.
The value is an integer from 0 to 31.
- mediatek,hs400-cmd-int-delay: HS400 command internal delay setting
This field has total 32 stages.
The value is an integer from 0 to 31.
- mediatek,hs400-cmd-resp-sel-rising: HS400 command response sample selection
If present,HS400 command responses are sampled on rising edges.
If not present,HS400 command responses are sampled on falling edges.
Examples:
mmc0: mmc@11230000 {
......@@ -38,4 +47,7 @@ mmc0: mmc@11230000 {
assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
hs400-ds-delay = <0x14015>;
mediatek,hs200-cmd-int-delay = <26>;
mediatek,hs400-cmd-int-delay = <14>;
mediatek,hs400-cmd-resp-sel-rising;
};
......@@ -7,11 +7,13 @@ This file documents differences between the core properties described
by mmc.txt and the properties used by the sdhci-tegra driver.
Required properties:
- compatible : For Tegra20, must contain "nvidia,tegra20-sdhci".
For Tegra30, must contain "nvidia,tegra30-sdhci". For Tegra114,
must contain "nvidia,tegra114-sdhci". For Tegra124, must contain
"nvidia,tegra124-sdhci". Otherwise, must contain "nvidia,<chip>-sdhci",
plus one of the above, where <chip> is tegra132 or tegra210.
- compatible : should be one of:
- "nvidia,tegra20-sdhci": for Tegra20
- "nvidia,tegra30-sdhci": for Tegra30
- "nvidia,tegra114-sdhci": for Tegra114
- "nvidia,tegra124-sdhci": for Tegra124 and Tegra132
- "nvidia,tegra210-sdhci": for Tegra210
- "nvidia,tegra186-sdhci": for Tegra186
- clocks : Must contain one entry, for the module clock.
See ../clocks/clock-bindings.txt for details.
- resets : Must contain an entry for each entry in reset-names.
......
......@@ -8,6 +8,7 @@ Required properties:
- compatible: should be "renesas,mmcif-<soctype>", "renesas,sh-mmcif" as a
fallback. Examples with <soctype> are:
- "renesas,mmcif-r7s72100" for the MMCIF found in r7s72100 SoCs
- "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs
- "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
- "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs
......@@ -17,6 +18,13 @@ Required properties:
- "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs
- "renesas,mmcif-sh73a0" for the MMCIF found in sh73a0 SoCs
- 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, r8a7778, r8a7790, r8a7791, r8a7793, r8a7794
2: r8a7740, sh73a0
3: r7s72100
- clocks: reference to the functional clock
- dmas: reference to the DMA channels, one per channel name listed in the
......
* Samsung's S3C24XX MMC/SD/SDIO controller device tree bindings
Samsung's S3C24XX MMC/SD/SDIO controller is used as a connectivity interface
with external MMC, SD and SDIO storage mediums.
This file documents differences between the core mmc properties described by
mmc.txt and the properties used by the Samsung S3C24XX MMC/SD/SDIO controller
implementation.
Required SoC Specific Properties:
- compatible: should be one of the following
- "samsung,s3c2410-sdi": for controllers compatible with s3c2410
- "samsung,s3c2412-sdi": for controllers compatible with s3c2412
- "samsung,s3c2440-sdi": for controllers compatible with s3c2440
- reg: register location and length
- interrupts: mmc controller interrupt
- clocks: Should reference the controller clock
- clock-names: Should contain "sdi"
Required Board Specific Properties:
- pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default".
Optional Properties:
- bus-width: number of data lines (see mmc.txt)
- cd-gpios: gpio for card detection (see mmc.txt)
- wp-gpios: gpio for write protection (see mmc.txt)
Example:
mmc0: mmc@5a000000 {
compatible = "samsung,s3c2440-sdi";
pinctrl-names = "default";
pinctrl-0 = <&sdi_pins>;
reg = <0x5a000000 0x100000>;
interrupts = <0 0 21 3>;
clocks = <&clocks PCLK_SDI>;
clock-names = "sdi";
bus-width = <4>;
cd-gpios = <&gpg 8 GPIO_ACTIVE_LOW>;
wp-gpios = <&gph 8 GPIO_ACTIVE_LOW>;
};
......@@ -19,6 +19,53 @@ if supported. See mmc.txt for details.
- mmc-hs400-1_8v
- mmc-hs400-1_2v
Some PHY delays can be configured by following properties.
PHY DLL input delays:
They are used to delay the data valid window, and align the window
to sampling clock. The delay starts from 5ns (for delay parameter equal to 0)
and it is increased by 2.5ns in each step.
- cdns,phy-input-delay-sd-highspeed:
Value of the delay in the input path for SD high-speed timing
Valid range = [0:0x1F].
- cdns,phy-input-delay-legacy:
Value of the delay in the input path for legacy timing
Valid range = [0:0x1F].
- cdns,phy-input-delay-sd-uhs-sdr12:
Value of the delay in the input path for SD UHS SDR12 timing
Valid range = [0:0x1F].
- cdns,phy-input-delay-sd-uhs-sdr25:
Value of the delay in the input path for SD UHS SDR25 timing
Valid range = [0:0x1F].
- cdns,phy-input-delay-sd-uhs-sdr50:
Value of the delay in the input path for SD UHS SDR50 timing
Valid range = [0:0x1F].
- cdns,phy-input-delay-sd-uhs-ddr50:
Value of the delay in the input path for SD UHS DDR50 timing
Valid range = [0:0x1F].
- cdns,phy-input-delay-mmc-highspeed:
Value of the delay in the input path for MMC high-speed timing
Valid range = [0:0x1F].
- cdns,phy-input-delay-mmc-ddr:
Value of the delay in the input path for eMMC high-speed DDR timing
Valid range = [0:0x1F].
PHY DLL clock delays:
Each delay property represents the fraction of the clock period.
The approximate delay value will be
(<delay property value>/128)*sdmclk_clock_period.
- cdns,phy-dll-delay-sdclk:
Value of the delay introduced on the sdclk output
for all modes except HS200, HS400 and HS400_ES.
Valid range = [0:0x7F].
- cdns,phy-dll-delay-sdclk-hsmmc:
Value of the delay introduced on the sdclk output
for HS200, HS400 and HS400_ES speed modes.
Valid range = [0:0x7F].
- cdns,phy-dll-delay-strobe:
Value of the delay introduced on the dat_strobe input
used in HS400 / HS400_ES speed modes.
Valid range = [0:0x7F].
Example:
emmc: sdhci@5a000000 {
compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc";
......@@ -29,4 +76,5 @@ Example:
mmc-ddr-1_8v;
mmc-hs200-1_8v;
mmc-hs400-1_8v;
cdns,phy-dll-delay-sdclk = <0>;
};
......@@ -30,6 +30,7 @@ All attributes are read-only.
rel_sectors Reliable write sector count
ocr Operation Conditions Register
dsr Driver Stage Register
cmdq_en Command Queue enabled: 1 => enabled, 0 => not enabled
Note on Erase Size and Preferred Erase Size:
......
......@@ -3064,6 +3064,14 @@ S: Supported
F: drivers/i2c/busses/i2c-octeon*
F: drivers/i2c/busses/i2c-thunderx*
CAVIUM MMC DRIVER
M: Jan Glauber <jglauber@cavium.com>
M: David Daney <david.daney@cavium.com>
M: Steven J. Hill <Steven.Hill@cavium.com>
W: http://www.cavium.com
S: Supported
F: drivers/mmc/host/cavium*
CAVIUM LIQUIDIO NETWORK DRIVER
M: Derek Chickles <derek.chickles@caviumnetworks.com>
M: Satanand Burla <satananda.burla@caviumnetworks.com>
......@@ -7919,6 +7927,13 @@ M: Nicolas Pitre <nico@fluxnic.net>
S: Odd Fixes
F: drivers/mmc/host/mvsdio.*
MARVELL XENON MMC/SD/SDIO HOST CONTROLLER DRIVER
M: Hu Ziji <huziji@marvell.com>
L: linux-mmc@vger.kernel.org
S: Supported
F: drivers/mmc/host/sdhci-xenon*
F: Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
MATROX FRAMEBUFFER DRIVER
L: linux-fbdev@vger.kernel.org
S: Orphan
......
......@@ -235,7 +235,8 @@ ap_syscon: system-controller@6f4000 {
#clock-cells = <1>;
clock-output-names = "ap-cpu-cluster-0",
"ap-cpu-cluster-1",
"ap-fixed", "ap-mss";
"ap-fixed", "ap-mss",
"ap-emmc";
reg = <0x6f4000 0x1000>;
};
};
......
......@@ -127,6 +127,11 @@ CONFIG_USB_EHCI_HCD=m
CONFIG_USB_EHCI_HCD_PLATFORM=m
CONFIG_USB_OHCI_HCD=m
CONFIG_USB_OHCI_HCD_PLATFORM=m
CONFIG_MMC=y
# CONFIG_PWRSEQ_EMMC is not set
# CONFIG_PWRSEQ_SIMPLE is not set
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_CAVIUM_OCTEON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_DS1307=y
CONFIG_STAGING=y
......
......@@ -23,7 +23,7 @@
#define AP806_SAR_REG 0x400
#define AP806_SAR_CLKFREQ_MODE_MASK 0x1f
#define AP806_CLK_NUM 4
#define AP806_CLK_NUM 5
static struct clk *ap806_clks[AP806_CLK_NUM];
......@@ -135,6 +135,23 @@ static int ap806_syscon_clk_probe(struct platform_device *pdev)
goto fail3;
}
/* eMMC Clock is fixed clock divided by 3 */
if (of_property_read_string_index(np, "clock-output-names",
4, &name)) {
ap806_clk_data.clk_num--;
dev_warn(&pdev->dev,
"eMMC clock missing: update the device tree!\n");
} else {
ap806_clks[4] = clk_register_fixed_factor(NULL, name,
fixedclk_name,
0, 1, 3);
if (IS_ERR(ap806_clks[4])) {
ret = PTR_ERR(ap806_clks[4]);
goto fail4;
}
}
of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
if (ret)
goto fail_clk_add;
......@@ -142,6 +159,8 @@ static int ap806_syscon_clk_probe(struct platform_device *pdev)
return 0;
fail_clk_add:
clk_unregister_fixed_factor(ap806_clks[4]);
fail4:
clk_unregister_fixed_factor(ap806_clks[3]);
fail3:
clk_unregister_fixed_rate(ap806_clks[2]);
......
This diff is collapsed.
......@@ -172,14 +172,16 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
trace_mmc_request_done(host, mrq);
if (err && cmd->retries && !mmc_card_removed(host->card)) {
/*
* Request starter must handle retries - see
* mmc_wait_for_req_done().
* We list various conditions for the command to be considered
* properly done:
*
* - There was no error, OK fine then
* - We are not doing some kind of retry
* - The card was removed (...so just complete everything no matter
* if there are errors or retries)
*/
if (mrq->done)
mrq->done(mrq);
} else {
if (!err || !cmd->retries || mmc_card_removed(host->card)) {
mmc_should_fail_request(host, mrq);
if (!host->ongoing_mrq)
......@@ -211,10 +213,13 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->resp[0], mrq->stop->resp[1],
mrq->stop->resp[2], mrq->stop->resp[3]);
}
}
/*
* Request starter must handle retries - see
* mmc_wait_for_req_done().
*/
if (mrq->done)
mrq->done(mrq);
}
}
EXPORT_SYMBOL(mmc_request_done);
......@@ -234,8 +239,10 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
/*
* For sdio rw commands we must wait for card busy otherwise some
* sdio devices won't work properly.
* And bypass I/O abort, reset and bus suspend operations.
*/
if (mmc_is_io_op(mrq->cmd->opcode) && host->ops->card_busy) {
if (sdio_is_io_busy(mrq->cmd->opcode, mrq->cmd->arg) &&
host->ops->card_busy) {
int tries = 500; /* Wait aprox 500ms at maximum */
while (host->ops->card_busy(host) && --tries)
......@@ -262,26 +269,19 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
host->ops->request(host, mrq);
}
static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
{
#ifdef CONFIG_MMC_DEBUG
unsigned int i, sz;
struct scatterlist *sg;
#endif
mmc_retune_hold(host);
if (mmc_card_removed(host->card))
return -ENOMEDIUM;
if (mrq->sbc) {
pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
mmc_hostname(host), mrq->sbc->opcode,
mrq->sbc->arg, mrq->sbc->flags);
}
if (mrq->cmd) {
pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags);
mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg,
mrq->cmd->flags);
}
if (mrq->data) {
pr_debug("%s: blksz %d blocks %d flags %08x "
......@@ -297,11 +297,20 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->stop->opcode,
mrq->stop->arg, mrq->stop->flags);
}
}
WARN_ON(!host->claimed);
static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
{
#ifdef CONFIG_MMC_DEBUG
unsigned int i, sz;
struct scatterlist *sg;
#endif
if (mrq->cmd) {
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
mrq->cmd->data = mrq->data;
}
if (mrq->sbc) {
mrq->sbc->error = 0;
mrq->sbc->mrq = mrq;
......@@ -318,8 +327,6 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
if (sz != mrq->data->blocks * mrq->data->blksz)
return -EINVAL;
#endif
mrq->cmd->data = mrq->data;
mrq->data->error = 0;
mrq->data->mrq = mrq;
if (mrq->stop) {
......@@ -328,6 +335,27 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->mrq = mrq;
}
}
return 0;
}
static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
int err;
mmc_retune_hold(host);
if (mmc_card_removed(host->card))
return -ENOMEDIUM;
mmc_mrq_pr_debug(host, mrq);
WARN_ON(!host->claimed);
err = mmc_mrq_prep(host, mrq);
if (err)
return err;
led_trigger_event(host->led, LED_FULL);
__mmc_start_request(host, mrq);
......@@ -485,56 +513,6 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
return err;
}
/*
* mmc_wait_for_data_req_done() - wait for request completed
* @host: MMC host to prepare the command.
* @mrq: MMC request to wait for
*
* Blocks MMC context till host controller will ack end of data request
* execution or new request notification arrives from the block layer.
* Handles command retries.
*
* Returns enum mmc_blk_status after checking errors.
*/
static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
struct mmc_request *mrq)
{
struct mmc_command *cmd;
struct mmc_context_info *context_info = &host->context_info;
enum mmc_blk_status status;
while (1) {
wait_event_interruptible(context_info->wait,
(context_info->is_done_rcv ||
context_info->is_new_req));
if (context_info->is_done_rcv) {
context_info->is_done_rcv = false;
cmd = mrq->cmd;
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card)) {
status = host->areq->err_check(host->card,
host->areq);
break; /* return status */
} else {
mmc_retune_recheck(host);
pr_info("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host),
cmd->opcode, cmd->error);
cmd->retries--;
cmd->error = 0;
__mmc_start_request(host, mrq);
continue; /* wait for done/new event again */
}
}
return MMC_BLK_NEW_REQUEST;
}
mmc_retune_release(host);
return status;
}
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
{
struct mmc_command *cmd;
......@@ -639,14 +617,44 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
*/
static enum mmc_blk_status mmc_finalize_areq(struct mmc_host *host)
{
struct mmc_context_info *context_info = &host->context_info;
enum mmc_blk_status status;
if (!host->areq)
return MMC_BLK_SUCCESS;
status = mmc_wait_for_data_req_done(host, host->areq->mrq);
if (status == MMC_BLK_NEW_REQUEST)
return status;
while (1) {
wait_event_interruptible(context_info->wait,
(context_info->is_done_rcv ||
context_info->is_new_req));
if (context_info->is_done_rcv) {
struct mmc_command *cmd;
context_info->is_done_rcv = false;
cmd = host->areq->mrq->cmd;
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card)) {
status = host->areq->err_check(host->card,
host->areq);
break; /* return status */
} else {
mmc_retune_recheck(host);
pr_info("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host),
cmd->opcode, cmd->error);
cmd->retries--;
cmd->error = 0;
__mmc_start_request(host, host->areq->mrq);
continue; /* wait for done/new event again */
}
}
return MMC_BLK_NEW_REQUEST;
}
mmc_retune_release(host);
/*
* Check BKOPS urgency for each R1 response
......@@ -683,7 +691,7 @@ struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
{
enum mmc_blk_status status;
int start_err = 0;
struct mmc_async_req *data = host->areq;
struct mmc_async_req *previous = host->areq;
/* Prepare a new request */
if (areq)
......@@ -691,13 +699,12 @@ struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
/* Finalize previous request */
status = mmc_finalize_areq(host);
/* The previous request is still going on... */
if (status == MMC_BLK_NEW_REQUEST) {
if (ret_stat)
*ret_stat = status;
/* The previous request is still going on... */
if (status == MMC_BLK_NEW_REQUEST)
return NULL;
}
/* Fine so far, start the new request! */
if (status == MMC_BLK_SUCCESS && areq)
......@@ -716,9 +723,7 @@ struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
else
host->areq = areq;
if (ret_stat)
*ret_stat = status;
return data;
return previous;
}
EXPORT_SYMBOL(mmc_start_areq);
......@@ -2555,6 +2560,12 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
}
EXPORT_SYMBOL(mmc_calc_max_discard);
bool mmc_card_is_blockaddr(struct mmc_card *card)
{
return card ? mmc_card_blockaddr(card) : false;
}
EXPORT_SYMBOL(mmc_card_is_blockaddr);
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
struct mmc_command cmd = {};
......
......@@ -790,6 +790,7 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
MMC_DEV_ATTR(ocr, "%08x\n", card->ocr);
MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en);
static ssize_t mmc_fwrev_show(struct device *dev,
struct device_attribute *attr,
......@@ -845,6 +846,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_rel_sectors.attr,
&dev_attr_ocr.attr,
&dev_attr_dsr.attr,
&dev_attr_cmdq_en.attr,
NULL,
};
ATTRIBUTE_GROUPS(mmc_std);
......@@ -1787,6 +1789,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
}
/*
* In some cases (e.g. RPMB or mmc_test), the Command Queue must be
* disabled for a time, so a flag is needed to indicate to re-enable the
* Command Queue.
*/
card->reenable_cmdq = card->ext_csd.cmdq_en;
/*
* The mandatory minimum values are defined for packed command.
* read: 5, write: 3
......
......@@ -305,7 +305,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
int mmc_send_csd(struct mmc_card *card, u32 *csd)
{
int ret, i;
u32 *csd_tmp;
__be32 *csd_tmp;
if (!mmc_host_is_spi(card->host))
return mmc_send_cxd_native(card->host, card->rca << 16,
......@@ -319,7 +319,7 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd)
if (ret)
goto err;
for (i = 0;i < 4;i++)
for (i = 0; i < 4; i++)
csd[i] = be32_to_cpu(csd_tmp[i]);
err:
......@@ -330,7 +330,7 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd)
int mmc_send_cid(struct mmc_host *host, u32 *cid)
{
int ret, i;
u32 *cid_tmp;
__be32 *cid_tmp;
if (!mmc_host_is_spi(host)) {
if (!host->card)
......@@ -347,7 +347,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid)
if (ret)
goto err;
for (i = 0;i < 4;i++)
for (i = 0; i < 4; i++)
cid[i] = be32_to_cpu(cid_tmp[i]);
err:
......@@ -838,3 +838,31 @@ int mmc_can_ext_csd(struct mmc_card *card)
{
return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3);
}
static int mmc_cmdq_switch(struct mmc_card *card, bool enable)
{
u8 val = enable ? EXT_CSD_CMDQ_MODE_ENABLED : 0;
int err;
if (!card->ext_csd.cmdq_support)
return -EOPNOTSUPP;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CMDQ_MODE_EN,
val, card->ext_csd.generic_cmd6_time);
if (!err)
card->ext_csd.cmdq_en = enable;
return err;
}
int mmc_cmdq_enable(struct mmc_card *card)
{
return mmc_cmdq_switch(card, true);
}
EXPORT_SYMBOL_GPL(mmc_cmdq_enable);
int mmc_cmdq_disable(struct mmc_card *card)
{
return mmc_cmdq_switch(card, false);
}
EXPORT_SYMBOL_GPL(mmc_cmdq_disable);
......@@ -46,6 +46,8 @@ int mmc_read_bkops_status(struct mmc_card *card);
void mmc_start_bkops(struct mmc_card *card, bool from_exception);
int mmc_can_reset(struct mmc_card *card);
int mmc_flush_cache(struct mmc_card *card);
int mmc_cmdq_enable(struct mmc_card *card);
int mmc_cmdq_disable(struct mmc_card *card);
#endif
......@@ -26,6 +26,7 @@
#include "card.h"
#include "host.h"
#include "bus.h"
#include "mmc_ops.h"
#define RESULT_OK 0
#define RESULT_FAIL 1
......@@ -3264,6 +3265,14 @@ static int mmc_test_probe(struct mmc_card *card)
if (ret)
return ret;
if (card->ext_csd.cmdq_en) {
mmc_claim_host(card->host);
ret = mmc_cmdq_disable(card);
mmc_release_host(card->host);
if (ret)
return ret;
}
dev_info(&card->dev, "Card claimed for testing.\n");
return 0;
......@@ -3271,6 +3280,11 @@ static int mmc_test_probe(struct mmc_card *card)
static void mmc_test_remove(struct mmc_card *card)
{
if (card->reenable_cmdq) {
mmc_claim_host(card->host);
mmc_cmdq_enable(card);
mmc_release_host(card->host);
}
mmc_test_free_result(card);
mmc_test_free_dbgfs_file(card);
}
......
This diff is collapsed.
......@@ -34,23 +34,25 @@ struct mmc_queue_req {
struct scatterlist *bounce_sg;
unsigned int bounce_sg_len;
struct mmc_async_req areq;
int task_id;
};
struct mmc_queue {
struct mmc_card *card;
struct task_struct *thread;
struct semaphore thread_sem;
bool new_request;
bool suspended;
bool asleep;
struct mmc_blk_data *blkdata;
struct request_queue *queue;
struct mmc_queue_req *mqrq;
struct mmc_queue_req *mqrq_cur;
struct mmc_queue_req *mqrq_prev;
int qdepth;
int qcnt;
unsigned long qslots;
};
extern int mmc_queue_alloc_shared_queue(struct mmc_card *card);
extern void mmc_queue_free_shared_queue(struct mmc_card *card);
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
const char *);
extern void mmc_cleanup_queue(struct mmc_queue *);
......@@ -64,4 +66,8 @@ extern void mmc_queue_bounce_post(struct mmc_queue_req *);
extern int mmc_access_rpmb(struct mmc_queue *);
extern struct mmc_queue_req *mmc_queue_req_find(struct mmc_queue *,
struct request *);
extern void mmc_queue_req_free(struct mmc_queue *, struct mmc_queue_req *);
#endif
......@@ -225,7 +225,7 @@ static int mmc_decode_scr(struct mmc_card *card)
static int mmc_read_ssr(struct mmc_card *card)
{
unsigned int au, es, et, eo;
u32 *raw_ssr;
__be32 *raw_ssr;
int i;
if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
......@@ -853,7 +853,7 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
/*
* Fetch SCR from card.
*/
err = mmc_app_send_scr(card, card->raw_scr);
err = mmc_app_send_scr(card);
if (err)
return err;
......
......@@ -232,14 +232,14 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
return 0;
}
int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
int mmc_app_send_scr(struct mmc_card *card)
{
int err;
struct mmc_request mrq = {};
struct mmc_command cmd = {};
struct mmc_data data = {};
struct scatterlist sg;
void *data_buf;
__be32 *scr;
/* NOTE: caller guarantees scr is heap-allocated */
......@@ -250,8 +250,8 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
/* dma onto stack is unsafe/nonportable, but callers to this
* routine normally provide temporary on-stack buffers ...
*/
data_buf = kmalloc(sizeof(card->raw_scr), GFP_KERNEL);
if (data_buf == NULL)
scr = kmalloc(sizeof(card->raw_scr), GFP_KERNEL);
if (!scr)
return -ENOMEM;
mrq.cmd = &cmd;
......@@ -267,23 +267,22 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, data_buf, 8);
sg_init_one(&sg, scr, 8);
mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
memcpy(scr, data_buf, sizeof(card->raw_scr));
kfree(data_buf);
card->raw_scr[0] = be32_to_cpu(scr[0]);
card->raw_scr[1] = be32_to_cpu(scr[1]);
kfree(scr);
if (cmd.error)
return cmd.error;
if (data.error)
return data.error;
scr[0] = be32_to_cpu(scr[0]);
scr[1] = be32_to_cpu(scr[1]);
return 0;
}
......
......@@ -22,7 +22,7 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
int mmc_app_send_scr(struct mmc_card *card);
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp);
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
......
......@@ -373,19 +373,16 @@ u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret)
u8 val;
if (!func) {
if (err_ret)
*err_ret = -EINVAL;
return 0xFF;
}
if (err_ret)
*err_ret = 0;
ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val);
if (ret) {
if (err_ret)
*err_ret = ret;
if (ret)
return 0xFF;
}
return val;
}
......@@ -407,6 +404,7 @@ void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret)
int ret;
if (!func) {
if (err_ret)
*err_ret = -EINVAL;
return;
}
......@@ -441,7 +439,7 @@ u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte,
if (err_ret)
*err_ret = ret;
if (ret)
val = 0xff;
return 0xff;
return val;
}
......@@ -529,15 +527,11 @@ u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret)
{
int ret;
if (err_ret)
*err_ret = 0;
ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2);
if (ret) {
if (err_ret)
*err_ret = ret;
if (ret)
return 0xFFFF;
}
return le16_to_cpup((__le16 *)func->tmpbuf);
}
......@@ -581,15 +575,11 @@ u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret)
{
int ret;
if (err_ret)
*err_ret = 0;
ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4);
if (ret) {
if (err_ret)
*err_ret = ret;
if (ret)
return 0xFFFFFFFF;
}
return le32_to_cpup((__le32 *)func->tmpbuf);
}
......@@ -635,19 +625,16 @@ unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr,
unsigned char val;
if (!func) {
if (err_ret)
*err_ret = -EINVAL;
return 0xFF;
}
if (err_ret)
*err_ret = 0;
ret = mmc_io_rw_direct(func->card, 0, 0, addr, 0, &val);
if (ret) {
if (err_ret)
*err_ret = ret;
if (ret)
return 0xFF;
}
return val;
}
......@@ -673,6 +660,7 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
int ret;
if (!func) {
if (err_ret)
*err_ret = -EINVAL;
return;
}
......
......@@ -152,7 +152,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
left_size = data.blksz * data.blocks;
nents = (left_size - 1) / seg_size + 1;
nents = DIV_ROUND_UP(left_size, seg_size);
if (nents > 1) {
if (sg_alloc_table(&sgtable, nents, GFP_KERNEL))
return -ENOMEM;
......@@ -161,10 +161,9 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
data.sg_len = nents;
for_each_sg(data.sg, sg_ptr, data.sg_len, i) {
sg_set_page(sg_ptr, virt_to_page(buf + (i * seg_size)),
min(seg_size, left_size),
offset_in_page(buf + (i * seg_size)));
left_size = left_size - seg_size;
sg_set_buf(sg_ptr, buf + i * seg_size,
min(seg_size, left_size));
left_size -= seg_size;
}
} else {
data.sg = &sg;
......
......@@ -26,9 +26,15 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
int sdio_reset(struct mmc_host *host);
unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz);
static inline bool mmc_is_io_op(u32 opcode)
static inline bool sdio_is_io_busy(u32 opcode, u32 arg)
{
return opcode == SD_IO_RW_DIRECT || opcode == SD_IO_RW_EXTENDED;
u32 addr;
addr = (arg >> 9) & 0x1FFFF;
return (opcode == SD_IO_RW_EXTENDED ||
(opcode == SD_IO_RW_DIRECT &&
!(addr == SDIO_CCCR_ABORT || addr == SDIO_CCCR_SUSPEND)));
}
#endif
......
......@@ -622,6 +622,27 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
help
If you say yes here SD-Cards may work on the EZkit.
config MMC_CAVIUM_OCTEON
tristate "Cavium OCTEON SD/MMC Card Interface support"
depends on CAVIUM_OCTEON_SOC
help
This selects Cavium OCTEON SD/MMC card Interface.
If you have an OCTEON board with a Multimedia Card slot,
say Y or M here.
If unsure, say N.
config MMC_CAVIUM_THUNDERX
tristate "Cavium ThunderX SD/MMC Card Interface support"
depends on PCI && 64BIT && (ARM64 || COMPILE_TEST)
depends on GPIOLIB
depends on OF_ADDRESS
help
This selects Cavium ThunderX SD/MMC Card Interface.
If you have an Cavium ARM64 board with a Multimedia Card slot
or builtin eMMC chip say Y or M here. If built as a module
the module will be called thunderx_mmc.ko.
config MMC_DW
tristate "Synopsys DesignWare Memory Card Interface"
depends on HAS_DMA
......@@ -799,6 +820,20 @@ config MMC_TOSHIBA_PCI
depends on PCI
help
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.
Note that the BCM2835 has two SD controllers: The Arasan
sdhci controller (supported by MMC_SDHCI_IPROC) and a custom
sdhost controller (supported by this driver).
If unsure, say N.
config MMC_MTK
tristate "MediaTek SD/MMC Card Interface support"
depends on HAS_DMA
......@@ -828,3 +863,11 @@ config MMC_SDHCI_BRCMSTB
Broadcom STB SoCs.
If unsure, say Y.
config MMC_SDHCI_XENON
tristate "Marvell Xenon eMMC/SD/SDIO SDHCI driver"
depends on MMC_SDHCI_PLTFM
help
This selects Marvell Xenon eMMC/SD/SDIO SDHCI.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
......@@ -42,6 +42,10 @@ obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
octeon-mmc-objs := cavium.o cavium-octeon.o
obj-$(CONFIG_MMC_CAVIUM_OCTEON) += octeon-mmc.o
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_EXYNOS) += dw_mmc-exynos.o
......@@ -59,6 +63,7 @@ obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o
obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o
obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o
obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o
obj-$(CONFIG_MMC_BCM2835) += bcm2835.o
obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o
......@@ -83,3 +88,6 @@ obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG
endif
obj-$(CONFIG_MMC_SDHCI_XENON) += sdhci-xenon-driver.o
sdhci-xenon-driver-y += sdhci-xenon.o sdhci-xenon-phy.o
......@@ -212,10 +212,7 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
if (host->dma_in_use) {
enum dma_data_direction dma_data_dir;
if (data->flags & MMC_DATA_WRITE)
dma_data_dir = DMA_TO_DEVICE;
else
dma_data_dir = DMA_FROM_DEVICE;
dma_data_dir = mmc_get_dma_dir(data);
if (dma_data_dir == DMA_FROM_DEVICE) {
/*
......@@ -390,10 +387,7 @@ static void goldfish_mmc_prepare_data(struct goldfish_mmc_host *host,
*/
sg_len = (data->blocks == 1) ? 1 : data->sg_len;
if (data->flags & MMC_DATA_WRITE)
dma_data_dir = DMA_TO_DEVICE;
else
dma_data_dir = DMA_FROM_DEVICE;
dma_data_dir = mmc_get_dma_dir(data);
host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
sg_len, dma_data_dir);
......
......@@ -954,8 +954,7 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
if (data)
dma_unmap_sg(&host->pdev->dev,
data->sg, data->sg_len,
((data->flags & MMC_DATA_WRITE)
? DMA_TO_DEVICE : DMA_FROM_DEVICE));
mmc_get_dma_dir(data));
}
/*
......@@ -993,8 +992,7 @@ static void atmci_dma_cleanup(struct atmel_mci *host)
if (data)
dma_unmap_sg(host->dma.chan->device->dev,
data->sg, data->sg_len,
((data->flags & MMC_DATA_WRITE)
? DMA_TO_DEVICE : DMA_FROM_DEVICE));
mmc_get_dma_dir(data));
}
/*
......@@ -1095,7 +1093,6 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
{
u32 iflags, tmp;
unsigned int sg_len;
enum dma_data_direction dir;
int i;
data->error = -EINPROGRESS;
......@@ -1107,13 +1104,10 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
/* Enable pdc mode */
atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE);
if (data->flags & MMC_DATA_READ) {
dir = DMA_FROM_DEVICE;
if (data->flags & MMC_DATA_READ)
iflags |= ATMCI_ENDRX | ATMCI_RXBUFF;
} else {
dir = DMA_TO_DEVICE;
else
iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE;
}
/* Set BLKLEN */
tmp = atmci_readl(host, ATMCI_MR);
......@@ -1123,7 +1117,8 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
/* Configure PDC */
host->data_size = data->blocks * data->blksz;
sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
mmc_get_dma_dir(data));
if ((!host->caps.has_rwproof)
&& (host->data->flags & MMC_DATA_WRITE)) {
......@@ -1135,9 +1130,8 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
}
if (host->data_size)
atmci_pdc_set_both_buf(host,
((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT));
atmci_pdc_set_both_buf(host, data->flags & MMC_DATA_READ ?
XFER_RECEIVE : XFER_TRANSMIT);
return iflags;
}
......@@ -1148,7 +1142,6 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
struct dma_async_tx_descriptor *desc;
struct scatterlist *sg;
unsigned int i;
enum dma_data_direction direction;
enum dma_transfer_direction slave_dirn;
unsigned int sglen;
u32 maxburst;
......@@ -1186,12 +1179,10 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
return -ENODEV;
if (data->flags & MMC_DATA_READ) {
direction = DMA_FROM_DEVICE;
host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
maxburst = atmci_convert_chksize(host,
host->dma_conf.src_maxburst);
} else {
direction = DMA_TO_DEVICE;
host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
maxburst = atmci_convert_chksize(host,
host->dma_conf.dst_maxburst);
......@@ -1202,7 +1193,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
ATMCI_DMAEN);
sglen = dma_map_sg(chan->device->dev, data->sg,
data->sg_len, direction);
data->sg_len, mmc_get_dma_dir(data));
dmaengine_slave_config(chan, &host->dma_conf);
desc = dmaengine_prep_slave_sg(chan,
......@@ -1217,7 +1208,8 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
return iflags;
unmap_exit:
dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction);
dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
mmc_get_dma_dir(data));
return -ENOMEM;
}
......
This diff is collapsed.
/*
* Driver for MMC and SSD cards for Cavium OCTEON SOCs.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2012-2017 Cavium Inc.
*/
#include <linux/dma-mapping.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <asm/octeon/octeon.h>
#include "cavium.h"
#define CVMX_MIO_BOOT_CTL CVMX_ADD_IO_SEG(0x00011800000000D0ull)
/*
* The l2c* functions below are used for the EMMC-17978 workaround.
*
* Due to a bug in the design of the MMC bus hardware, the 2nd to last
* cache block of a DMA read must be locked into the L2 Cache.
* Otherwise, data corruption may occur.
*/
static inline void *phys_to_ptr(u64 address)
{
return (void *)(address | (1ull << 63)); /* XKPHYS */
}
/*
* Lock a single line into L2. The line is zeroed before locking
* to make sure no dram accesses are made.
*/
static void l2c_lock_line(u64 addr)
{
char *addr_ptr = phys_to_ptr(addr);
asm volatile (
"cache 31, %[line]" /* Unlock the line */
::[line] "m" (*addr_ptr));
}
/* Unlock a single line in the L2 cache. */
static void l2c_unlock_line(u64 addr)
{
char *addr_ptr = phys_to_ptr(addr);
asm volatile (
"cache 23, %[line]" /* Unlock the line */
::[line] "m" (*addr_ptr));
}
/* Locks a memory region in the L2 cache. */
static void l2c_lock_mem_region(u64 start, u64 len)
{
u64 end;
/* Round start/end to cache line boundaries */
end = ALIGN(start + len - 1, CVMX_CACHE_LINE_SIZE);
start = ALIGN(start, CVMX_CACHE_LINE_SIZE);
while (start <= end) {
l2c_lock_line(start);
start += CVMX_CACHE_LINE_SIZE;
}
asm volatile("sync");
}
/* Unlock a memory region in the L2 cache. */
static void l2c_unlock_mem_region(u64 start, u64 len)
{
u64 end;
/* Round start/end to cache line boundaries */
end = ALIGN(start + len - 1, CVMX_CACHE_LINE_SIZE);
start = ALIGN(start, CVMX_CACHE_LINE_SIZE);
while (start <= end) {
l2c_unlock_line(start);
start += CVMX_CACHE_LINE_SIZE;
}
}
static void octeon_mmc_acquire_bus(struct cvm_mmc_host *host)
{
if (!host->has_ciu3) {
down(&octeon_bootbus_sem);
/* For CN70XX, switch the MMC controller onto the bus. */
if (OCTEON_IS_MODEL(OCTEON_CN70XX))
writeq(0, (void __iomem *)CVMX_MIO_BOOT_CTL);
} else {
down(&host->mmc_serializer);
}
}
static void octeon_mmc_release_bus(struct cvm_mmc_host *host)
{
if (!host->has_ciu3)
up(&octeon_bootbus_sem);
else
up(&host->mmc_serializer);
}
static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
{
writeq(val, host->base + MIO_EMM_INT(host));
if (!host->dma_active || (host->dma_active && !host->has_ciu3))
writeq(val, host->base + MIO_EMM_INT_EN(host));
}
static void octeon_mmc_set_shared_power(struct cvm_mmc_host *host, int dir)
{
if (dir == 0)
if (!atomic_dec_return(&host->shared_power_users))
gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
if (dir == 1)
if (atomic_inc_return(&host->shared_power_users) == 1)
gpiod_set_value_cansleep(host->global_pwr_gpiod, 1);
}
static void octeon_mmc_dmar_fixup(struct cvm_mmc_host *host,
struct mmc_command *cmd,
struct mmc_data *data,
u64 addr)
{
if (cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
return;
if (data->blksz * data->blocks <= 1024)
return;
host->n_minus_one = addr + (data->blksz * data->blocks) - 1024;
l2c_lock_mem_region(host->n_minus_one, 512);
}
static void octeon_mmc_dmar_fixup_done(struct cvm_mmc_host *host)
{
if (!host->n_minus_one)
return;
l2c_unlock_mem_region(host->n_minus_one, 512);
host->n_minus_one = 0;
}
static int octeon_mmc_probe(struct platform_device *pdev)
{
struct device_node *cn, *node = pdev->dev.of_node;
struct cvm_mmc_host *host;
struct resource *res;
void __iomem *base;
int mmc_irq[9];
int i, ret = 0;
u64 val;
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host)
return -ENOMEM;
spin_lock_init(&host->irq_handler_lock);
sema_init(&host->mmc_serializer, 1);
host->dev = &pdev->dev;
host->acquire_bus = octeon_mmc_acquire_bus;
host->release_bus = octeon_mmc_release_bus;
host->int_enable = octeon_mmc_int_enable;
host->set_shared_power = octeon_mmc_set_shared_power;
if (OCTEON_IS_MODEL(OCTEON_CN6XXX) ||
OCTEON_IS_MODEL(OCTEON_CNF7XXX)) {
host->dmar_fixup = octeon_mmc_dmar_fixup;
host->dmar_fixup_done = octeon_mmc_dmar_fixup_done;
}
host->sys_freq = octeon_get_io_clock_rate();
if (of_device_is_compatible(node, "cavium,octeon-7890-mmc")) {
host->big_dma_addr = true;
host->need_irq_handler_lock = true;
host->has_ciu3 = true;
host->use_sg = true;
/*
* First seven are the EMM_INT bits 0..6, then two for
* the EMM_DMA_INT bits
*/
for (i = 0; i < 9; i++) {
mmc_irq[i] = platform_get_irq(pdev, i);
if (mmc_irq[i] < 0)
return mmc_irq[i];
/* work around legacy u-boot device trees */
irq_set_irq_type(mmc_irq[i], IRQ_TYPE_EDGE_RISING);
}
} else {
host->big_dma_addr = false;
host->need_irq_handler_lock = false;
host->has_ciu3 = false;
/* First one is EMM second DMA */
for (i = 0; i < 2; i++) {
mmc_irq[i] = platform_get_irq(pdev, i);
if (mmc_irq[i] < 0)
return mmc_irq[i];
}
}
host->last_slot = -1;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Platform resource[0] is missing\n");
return -ENXIO;
}
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
host->base = (void __iomem *)base;
host->reg_off = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(&pdev->dev, "Platform resource[1] is missing\n");
return -EINVAL;
}
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
host->dma_base = (void __iomem *)base;
/*
* To keep the register addresses shared we intentionaly use
* a negative offset here, first register used on Octeon therefore
* starts at 0x20 (MIO_EMM_DMA_CFG).
*/
host->reg_off_dma = -0x20;
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
if (ret)
return ret;
/*
* Clear out any pending interrupts that may be left over from
* bootloader.
*/
val = readq(host->base + MIO_EMM_INT(host));
writeq(val, host->base + MIO_EMM_INT(host));
if (host->has_ciu3) {
/* Only CMD_DONE, DMA_DONE, CMD_ERR, DMA_ERR */
for (i = 1; i <= 4; i++) {
ret = devm_request_irq(&pdev->dev, mmc_irq[i],
cvm_mmc_interrupt,
0, cvm_mmc_irq_names[i], host);
if (ret < 0) {
dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
mmc_irq[i]);
return ret;
}
}
} else {
ret = devm_request_irq(&pdev->dev, mmc_irq[0],
cvm_mmc_interrupt, 0, KBUILD_MODNAME,
host);
if (ret < 0) {
dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
mmc_irq[0]);
return ret;
}
}
host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev,
"power-gpios",
GPIOD_OUT_HIGH);
if (IS_ERR(host->global_pwr_gpiod)) {
dev_err(&pdev->dev, "Invalid power GPIO\n");
return PTR_ERR(host->global_pwr_gpiod);
}
platform_set_drvdata(pdev, host);
i = 0;
for_each_child_of_node(node, cn) {
host->slot_pdev[i] =
of_platform_device_create(cn, NULL, &pdev->dev);
if (!host->slot_pdev[i]) {
i++;
continue;
}
ret = cvm_mmc_of_slot_probe(&host->slot_pdev[i]->dev, host);
if (ret) {
dev_err(&pdev->dev, "Error populating slots\n");
octeon_mmc_set_shared_power(host, 0);
return ret;
}
i++;
}
return 0;
}
static int octeon_mmc_remove(struct platform_device *pdev)
{
struct cvm_mmc_host *host = platform_get_drvdata(pdev);
u64 dma_cfg;
int i;
for (i = 0; i < CAVIUM_MAX_MMC; i++)
if (host->slot[i])
cvm_mmc_of_slot_remove(host->slot[i]);
dma_cfg = readq(host->dma_base + MIO_EMM_DMA_CFG(host));
dma_cfg &= ~MIO_EMM_DMA_CFG_EN;
writeq(dma_cfg, host->dma_base + MIO_EMM_DMA_CFG(host));
octeon_mmc_set_shared_power(host, 0);
return 0;
}
static const struct of_device_id octeon_mmc_match[] = {
{
.compatible = "cavium,octeon-6130-mmc",
},
{
.compatible = "cavium,octeon-7890-mmc",
},
{},
};
MODULE_DEVICE_TABLE(of, octeon_mmc_match);
static struct platform_driver octeon_mmc_driver = {
.probe = octeon_mmc_probe,
.remove = octeon_mmc_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = octeon_mmc_match,
},
};
static int __init octeon_mmc_init(void)
{
return platform_driver_register(&octeon_mmc_driver);
}
static void __exit octeon_mmc_cleanup(void)
{
platform_driver_unregister(&octeon_mmc_driver);
}
module_init(octeon_mmc_init);
module_exit(octeon_mmc_cleanup);
MODULE_AUTHOR("Cavium Inc. <support@cavium.com>");
MODULE_DESCRIPTION("Low-level driver for Cavium OCTEON MMC/SSD card");
MODULE_LICENSE("GPL");
/*
* Driver for MMC and SSD cards for Cavium ThunderX SOCs.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2016 Cavium Inc.
*/
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/mmc/mmc.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
#include "cavium.h"
static void thunder_mmc_acquire_bus(struct cvm_mmc_host *host)
{
down(&host->mmc_serializer);
}
static void thunder_mmc_release_bus(struct cvm_mmc_host *host)
{
up(&host->mmc_serializer);
}
static void thunder_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
{
writeq(val, host->base + MIO_EMM_INT(host));
writeq(val, host->base + MIO_EMM_INT_EN_SET(host));
}
static int thunder_mmc_register_interrupts(struct cvm_mmc_host *host,
struct pci_dev *pdev)
{
int nvec, ret, i;
nvec = pci_alloc_irq_vectors(pdev, 1, 9, PCI_IRQ_MSIX);
if (nvec < 0)
return nvec;
/* register interrupts */
for (i = 0; i < nvec; i++) {
ret = devm_request_irq(&pdev->dev, pci_irq_vector(pdev, i),
cvm_mmc_interrupt,
0, cvm_mmc_irq_names[i], host);
if (ret)
return ret;
}
return 0;
}
static int thunder_mmc_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct device_node *child_node;
struct cvm_mmc_host *host;
int ret, i = 0;
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host)
return -ENOMEM;
pci_set_drvdata(pdev, host);
ret = pcim_enable_device(pdev);
if (ret)
return ret;
ret = pci_request_regions(pdev, KBUILD_MODNAME);
if (ret)
return ret;
host->base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
if (!host->base)
return -EINVAL;
/* On ThunderX these are identical */
host->dma_base = host->base;
host->reg_off = 0x2000;
host->reg_off_dma = 0x160;
host->clk = devm_clk_get(dev, NULL);
if (IS_ERR(host->clk))
return PTR_ERR(host->clk);
ret = clk_prepare_enable(host->clk);
if (ret)
return ret;
host->sys_freq = clk_get_rate(host->clk);
spin_lock_init(&host->irq_handler_lock);
sema_init(&host->mmc_serializer, 1);
host->dev = dev;
host->acquire_bus = thunder_mmc_acquire_bus;
host->release_bus = thunder_mmc_release_bus;
host->int_enable = thunder_mmc_int_enable;
host->use_sg = true;
host->big_dma_addr = true;
host->need_irq_handler_lock = true;
host->last_slot = -1;
ret = dma_set_mask(dev, DMA_BIT_MASK(48));
if (ret)
goto error;
/*
* Clear out any pending interrupts that may be left over from
* bootloader. Writing 1 to the bits clears them.
*/
writeq(127, host->base + MIO_EMM_INT_EN(host));
writeq(3, host->base + MIO_EMM_DMA_INT_ENA_W1C(host));
/* Clear DMA FIFO */
writeq(BIT_ULL(16), host->base + MIO_EMM_DMA_FIFO_CFG(host));
ret = thunder_mmc_register_interrupts(host, pdev);
if (ret)
goto error;
for_each_child_of_node(node, child_node) {
/*
* mmc_of_parse and devm* require one device per slot.
* Create a dummy device per slot and set the node pointer to
* the slot. The easiest way to get this is using
* of_platform_device_create.
*/
if (of_device_is_compatible(child_node, "mmc-slot")) {
host->slot_pdev[i] = of_platform_device_create(child_node, NULL,
&pdev->dev);
if (!host->slot_pdev[i])
continue;
ret = cvm_mmc_of_slot_probe(&host->slot_pdev[i]->dev, host);
if (ret)
goto error;
}
i++;
}
dev_info(dev, "probed\n");
return 0;
error:
clk_disable_unprepare(host->clk);
return ret;
}
static void thunder_mmc_remove(struct pci_dev *pdev)
{
struct cvm_mmc_host *host = pci_get_drvdata(pdev);
u64 dma_cfg;
int i;
for (i = 0; i < CAVIUM_MAX_MMC; i++)
if (host->slot[i])
cvm_mmc_of_slot_remove(host->slot[i]);
dma_cfg = readq(host->dma_base + MIO_EMM_DMA_CFG(host));
dma_cfg &= ~MIO_EMM_DMA_CFG_EN;
writeq(dma_cfg, host->dma_base + MIO_EMM_DMA_CFG(host));
clk_disable_unprepare(host->clk);
}
static const struct pci_device_id thunder_mmc_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa010) },
{ 0, } /* end of table */
};
static struct pci_driver thunder_mmc_driver = {
.name = KBUILD_MODNAME,
.id_table = thunder_mmc_id_table,
.probe = thunder_mmc_probe,
.remove = thunder_mmc_remove,
};
module_pci_driver(thunder_mmc_driver);
MODULE_AUTHOR("Cavium Inc.");
MODULE_DESCRIPTION("Cavium ThunderX eMMC Driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, thunder_mmc_id_table);
This diff is collapsed.
/*
* Driver for MMC and SSD cards for Cavium OCTEON and ThunderX SOCs.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2012-2017 Cavium Inc.
*/
#ifndef _CAVIUM_MMC_H_
#define _CAVIUM_MMC_H_
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/mmc/host.h>
#include <linux/of.h>
#include <linux/scatterlist.h>
#include <linux/semaphore.h>
#define CAVIUM_MAX_MMC 4
/* DMA register addresses */
#define MIO_EMM_DMA_FIFO_CFG(x) (0x00 + x->reg_off_dma)
#define MIO_EMM_DMA_FIFO_ADR(x) (0x10 + x->reg_off_dma)
#define MIO_EMM_DMA_FIFO_CMD(x) (0x18 + x->reg_off_dma)
#define MIO_EMM_DMA_CFG(x) (0x20 + x->reg_off_dma)
#define MIO_EMM_DMA_ADR(x) (0x28 + x->reg_off_dma)
#define MIO_EMM_DMA_INT(x) (0x30 + x->reg_off_dma)
#define MIO_EMM_DMA_INT_W1S(x) (0x38 + x->reg_off_dma)
#define MIO_EMM_DMA_INT_ENA_W1S(x) (0x40 + x->reg_off_dma)
#define MIO_EMM_DMA_INT_ENA_W1C(x) (0x48 + x->reg_off_dma)
/* register addresses */
#define MIO_EMM_CFG(x) (0x00 + x->reg_off)
#define MIO_EMM_SWITCH(x) (0x48 + x->reg_off)
#define MIO_EMM_DMA(x) (0x50 + x->reg_off)
#define MIO_EMM_CMD(x) (0x58 + x->reg_off)
#define MIO_EMM_RSP_STS(x) (0x60 + x->reg_off)
#define MIO_EMM_RSP_LO(x) (0x68 + x->reg_off)
#define MIO_EMM_RSP_HI(x) (0x70 + x->reg_off)
#define MIO_EMM_INT(x) (0x78 + x->reg_off)
#define MIO_EMM_INT_EN(x) (0x80 + x->reg_off)
#define MIO_EMM_WDOG(x) (0x88 + x->reg_off)
#define MIO_EMM_SAMPLE(x) (0x90 + x->reg_off)
#define MIO_EMM_STS_MASK(x) (0x98 + x->reg_off)
#define MIO_EMM_RCA(x) (0xa0 + x->reg_off)
#define MIO_EMM_INT_EN_SET(x) (0xb0 + x->reg_off)
#define MIO_EMM_INT_EN_CLR(x) (0xb8 + x->reg_off)
#define MIO_EMM_BUF_IDX(x) (0xe0 + x->reg_off)
#define MIO_EMM_BUF_DAT(x) (0xe8 + x->reg_off)
struct cvm_mmc_host {
struct device *dev;
void __iomem *base;
void __iomem *dma_base;
int reg_off;
int reg_off_dma;
u64 emm_cfg;
u64 n_minus_one; /* OCTEON II workaround location */
int last_slot;
struct clk *clk;
int sys_freq;
struct mmc_request *current_req;
struct sg_mapping_iter smi;
bool dma_active;
bool use_sg;
bool has_ciu3;
bool big_dma_addr;
bool need_irq_handler_lock;
spinlock_t irq_handler_lock;
struct semaphore mmc_serializer;
struct gpio_desc *global_pwr_gpiod;
atomic_t shared_power_users;
struct cvm_mmc_slot *slot[CAVIUM_MAX_MMC];
struct platform_device *slot_pdev[CAVIUM_MAX_MMC];
void (*set_shared_power)(struct cvm_mmc_host *, int);
void (*acquire_bus)(struct cvm_mmc_host *);
void (*release_bus)(struct cvm_mmc_host *);
void (*int_enable)(struct cvm_mmc_host *, u64);
/* required on some MIPS models */
void (*dmar_fixup)(struct cvm_mmc_host *, struct mmc_command *,
struct mmc_data *, u64);
void (*dmar_fixup_done)(struct cvm_mmc_host *);
};
struct cvm_mmc_slot {
struct mmc_host *mmc; /* slot-level mmc_core object */
struct cvm_mmc_host *host; /* common hw for all slots */
u64 clock;
u64 cached_switch;
u64 cached_rca;
unsigned int cmd_cnt; /* sample delay */
unsigned int dat_cnt; /* sample delay */
int bus_id;
};
struct cvm_mmc_cr_type {
u8 ctype;
u8 rtype;
};
struct cvm_mmc_cr_mods {
u8 ctype_xor;
u8 rtype_xor;
};
/* Bitfield definitions */
#define MIO_EMM_DMA_FIFO_CFG_CLR BIT_ULL(16)
#define MIO_EMM_DMA_FIFO_CFG_INT_LVL GENMASK_ULL(12, 8)
#define MIO_EMM_DMA_FIFO_CFG_COUNT GENMASK_ULL(4, 0)
#define MIO_EMM_DMA_FIFO_CMD_RW BIT_ULL(62)
#define MIO_EMM_DMA_FIFO_CMD_INTDIS BIT_ULL(60)
#define MIO_EMM_DMA_FIFO_CMD_SWAP32 BIT_ULL(59)
#define MIO_EMM_DMA_FIFO_CMD_SWAP16 BIT_ULL(58)
#define MIO_EMM_DMA_FIFO_CMD_SWAP8 BIT_ULL(57)
#define MIO_EMM_DMA_FIFO_CMD_ENDIAN BIT_ULL(56)
#define MIO_EMM_DMA_FIFO_CMD_SIZE GENMASK_ULL(55, 36)
#define MIO_EMM_CMD_SKIP_BUSY BIT_ULL(62)
#define MIO_EMM_CMD_BUS_ID GENMASK_ULL(61, 60)
#define MIO_EMM_CMD_VAL BIT_ULL(59)
#define MIO_EMM_CMD_DBUF BIT_ULL(55)
#define MIO_EMM_CMD_OFFSET GENMASK_ULL(54, 49)
#define MIO_EMM_CMD_CTYPE_XOR GENMASK_ULL(42, 41)
#define MIO_EMM_CMD_RTYPE_XOR GENMASK_ULL(40, 38)
#define MIO_EMM_CMD_IDX GENMASK_ULL(37, 32)
#define MIO_EMM_CMD_ARG GENMASK_ULL(31, 0)
#define MIO_EMM_DMA_SKIP_BUSY BIT_ULL(62)
#define MIO_EMM_DMA_BUS_ID GENMASK_ULL(61, 60)
#define MIO_EMM_DMA_VAL BIT_ULL(59)
#define MIO_EMM_DMA_SECTOR BIT_ULL(58)
#define MIO_EMM_DMA_DAT_NULL BIT_ULL(57)
#define MIO_EMM_DMA_THRES GENMASK_ULL(56, 51)
#define MIO_EMM_DMA_REL_WR BIT_ULL(50)
#define MIO_EMM_DMA_RW BIT_ULL(49)
#define MIO_EMM_DMA_MULTI BIT_ULL(48)
#define MIO_EMM_DMA_BLOCK_CNT GENMASK_ULL(47, 32)
#define MIO_EMM_DMA_CARD_ADDR GENMASK_ULL(31, 0)
#define MIO_EMM_DMA_CFG_EN BIT_ULL(63)
#define MIO_EMM_DMA_CFG_RW BIT_ULL(62)
#define MIO_EMM_DMA_CFG_CLR BIT_ULL(61)
#define MIO_EMM_DMA_CFG_SWAP32 BIT_ULL(59)
#define MIO_EMM_DMA_CFG_SWAP16 BIT_ULL(58)
#define MIO_EMM_DMA_CFG_SWAP8 BIT_ULL(57)
#define MIO_EMM_DMA_CFG_ENDIAN BIT_ULL(56)
#define MIO_EMM_DMA_CFG_SIZE GENMASK_ULL(55, 36)
#define MIO_EMM_DMA_CFG_ADR GENMASK_ULL(35, 0)
#define MIO_EMM_INT_SWITCH_ERR BIT_ULL(6)
#define MIO_EMM_INT_SWITCH_DONE BIT_ULL(5)
#define MIO_EMM_INT_DMA_ERR BIT_ULL(4)
#define MIO_EMM_INT_CMD_ERR BIT_ULL(3)
#define MIO_EMM_INT_DMA_DONE BIT_ULL(2)
#define MIO_EMM_INT_CMD_DONE BIT_ULL(1)
#define MIO_EMM_INT_BUF_DONE BIT_ULL(0)
#define MIO_EMM_RSP_STS_BUS_ID GENMASK_ULL(61, 60)
#define MIO_EMM_RSP_STS_CMD_VAL BIT_ULL(59)
#define MIO_EMM_RSP_STS_SWITCH_VAL BIT_ULL(58)
#define MIO_EMM_RSP_STS_DMA_VAL BIT_ULL(57)
#define MIO_EMM_RSP_STS_DMA_PEND BIT_ULL(56)
#define MIO_EMM_RSP_STS_DBUF_ERR BIT_ULL(28)
#define MIO_EMM_RSP_STS_DBUF BIT_ULL(23)
#define MIO_EMM_RSP_STS_BLK_TIMEOUT BIT_ULL(22)
#define MIO_EMM_RSP_STS_BLK_CRC_ERR BIT_ULL(21)
#define MIO_EMM_RSP_STS_RSP_BUSYBIT BIT_ULL(20)
#define MIO_EMM_RSP_STS_STP_TIMEOUT BIT_ULL(19)
#define MIO_EMM_RSP_STS_STP_CRC_ERR BIT_ULL(18)
#define MIO_EMM_RSP_STS_STP_BAD_STS BIT_ULL(17)
#define MIO_EMM_RSP_STS_STP_VAL BIT_ULL(16)
#define MIO_EMM_RSP_STS_RSP_TIMEOUT BIT_ULL(15)
#define MIO_EMM_RSP_STS_RSP_CRC_ERR BIT_ULL(14)
#define MIO_EMM_RSP_STS_RSP_BAD_STS BIT_ULL(13)
#define MIO_EMM_RSP_STS_RSP_VAL BIT_ULL(12)
#define MIO_EMM_RSP_STS_RSP_TYPE GENMASK_ULL(11, 9)
#define MIO_EMM_RSP_STS_CMD_TYPE GENMASK_ULL(8, 7)
#define MIO_EMM_RSP_STS_CMD_IDX GENMASK_ULL(6, 1)
#define MIO_EMM_RSP_STS_CMD_DONE BIT_ULL(0)
#define MIO_EMM_SAMPLE_CMD_CNT GENMASK_ULL(25, 16)
#define MIO_EMM_SAMPLE_DAT_CNT GENMASK_ULL(9, 0)
#define MIO_EMM_SWITCH_BUS_ID GENMASK_ULL(61, 60)
#define MIO_EMM_SWITCH_EXE BIT_ULL(59)
#define MIO_EMM_SWITCH_ERR0 BIT_ULL(58)
#define MIO_EMM_SWITCH_ERR1 BIT_ULL(57)
#define MIO_EMM_SWITCH_ERR2 BIT_ULL(56)
#define MIO_EMM_SWITCH_HS_TIMING BIT_ULL(48)
#define MIO_EMM_SWITCH_BUS_WIDTH GENMASK_ULL(42, 40)
#define MIO_EMM_SWITCH_POWER_CLASS GENMASK_ULL(35, 32)
#define MIO_EMM_SWITCH_CLK_HI GENMASK_ULL(31, 16)
#define MIO_EMM_SWITCH_CLK_LO GENMASK_ULL(15, 0)
/* Protoypes */
irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id);
int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host);
int cvm_mmc_of_slot_remove(struct cvm_mmc_slot *slot);
extern const char *cvm_mmc_irq_names[];
#endif
......@@ -478,18 +478,14 @@ static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
int ret = 0;
host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
((data->flags & MMC_DATA_WRITE)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE));
mmc_get_dma_dir(data));
/* no individual DMA segment should need a partial FIFO */
for (i = 0; i < host->sg_len; i++) {
if (sg_dma_len(data->sg + i) & mask) {
dma_unmap_sg(mmc_dev(host->mmc),
data->sg, data->sg_len,
(data->flags & MMC_DATA_WRITE)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
mmc_get_dma_dir(data));
return -1;
}
}
......@@ -802,9 +798,7 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
davinci_abort_dma(host);
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
(data->flags & MMC_DATA_WRITE)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
mmc_get_dma_dir(data));
host->do_dma = false;
}
host->data_dir = DAVINCI_MMC_DATADIR_NONE;
......
This diff is collapsed.
......@@ -200,11 +200,6 @@ static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
return -ENODEV;
}
static inline int jz4740_mmc_get_dma_dir(struct mmc_data *data)
{
return (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
}
static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host,
struct mmc_data *data)
{
......@@ -215,7 +210,7 @@ static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host,
struct mmc_data *data)
{
struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data);
enum dma_data_direction dir = mmc_get_dma_dir(data);
dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
}
......@@ -227,7 +222,7 @@ static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
struct dma_chan *chan)
{
struct jz4740_mmc_host_next *next_data = &host->next_data;
enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data);
enum dma_data_direction dir = mmc_get_dma_dir(data);
int sg_len;
if (!next && data->host_cookie &&
......
This diff is collapsed.
......@@ -888,10 +888,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
u32 clock_rate;
unsigned long timeout;
if (data->flags & MMC_DATA_READ)
direction = DMA_FROM_DEVICE;
else
direction = DMA_TO_DEVICE;
direction = mmc_get_dma_dir(data);
mmc_spi_setup_data_message(host, multiple, direction);
t = &host->t;
......
......@@ -516,17 +516,14 @@ static void mmci_dma_data_error(struct mmci_host *host)
static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
{
struct dma_chan *chan;
enum dma_data_direction dir;
if (data->flags & MMC_DATA_READ) {
dir = DMA_FROM_DEVICE;
if (data->flags & MMC_DATA_READ)
chan = host->dma_rx_channel;
} else {
dir = DMA_TO_DEVICE;
else
chan = host->dma_tx_channel;
}
dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
mmc_get_dma_dir(data));
}
static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
......@@ -589,17 +586,14 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
struct dma_chan *chan;
struct dma_device *device;
struct dma_async_tx_descriptor *desc;
enum dma_data_direction buffer_dirn;
int nr_sg;
unsigned long flags = DMA_CTRL_ACK;
if (data->flags & MMC_DATA_READ) {
conf.direction = DMA_DEV_TO_MEM;
buffer_dirn = DMA_FROM_DEVICE;
chan = host->dma_rx_channel;
} else {
conf.direction = DMA_MEM_TO_DEV;
buffer_dirn = DMA_TO_DEVICE;
chan = host->dma_tx_channel;
}
......@@ -612,7 +606,8 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
return -EINVAL;
device = chan->device;
nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len,
mmc_get_dma_dir(data));
if (nr_sg == 0)
return -EINVAL;
......@@ -631,7 +626,8 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
return 0;
unmap_exit:
dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
dma_unmap_sg(device->dev, data->sg, data->sg_len,
mmc_get_dma_dir(data));
return -ENOMEM;
}
......
......@@ -256,7 +256,7 @@ static void moxart_dma_complete(void *param)
static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
{
u32 len, dir_data, dir_slave;
u32 len, dir_slave;
long dma_time;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *dma_chan;
......@@ -266,16 +266,14 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
if (data->flags & MMC_DATA_WRITE) {
dma_chan = host->dma_chan_tx;
dir_data = DMA_TO_DEVICE;
dir_slave = DMA_MEM_TO_DEV;
} else {
dma_chan = host->dma_chan_rx;
dir_data = DMA_FROM_DEVICE;
dir_slave = DMA_DEV_TO_MEM;
}
len = dma_map_sg(dma_chan->device->dev, data->sg,
data->sg_len, dir_data);
data->sg_len, mmc_get_dma_dir(data));
if (len > 0) {
desc = dmaengine_prep_slave_sg(dma_chan, data->sg,
......@@ -301,7 +299,7 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
dma_unmap_sg(dma_chan->device->dev,
data->sg, data->sg_len,
dir_data);
mmc_get_dma_dir(data));
}
......
This diff is collapsed.
......@@ -125,10 +125,10 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
return 1;
} else {
dma_addr_t phys_addr;
int dma_dir = (data->flags & MMC_DATA_READ) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE;
host->sg_frags = dma_map_sg(mmc_dev(host->mmc), data->sg,
data->sg_len, dma_dir);
host->sg_frags = dma_map_sg(mmc_dev(host->mmc),
data->sg, data->sg_len,
mmc_get_dma_dir(data));
phys_addr = sg_dma_address(data->sg);
mvsd_write(MVSD_SYS_ADDR_LOW, (u32)phys_addr & 0xffff);
mvsd_write(MVSD_SYS_ADDR_HI, (u32)phys_addr >> 16);
......@@ -294,8 +294,7 @@ static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data,
host->pio_size = 0;
} else {
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_frags,
(data->flags & MMC_DATA_READ) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
mmc_get_dma_dir(data));
}
if (err_status & MVSD_ERR_DATA_TIMEOUT)
......
......@@ -935,15 +935,6 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
}
static int
omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
{
if (data->flags & MMC_DATA_WRITE)
return DMA_TO_DEVICE;
else
return DMA_FROM_DEVICE;
}
static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host,
struct mmc_data *data)
{
......@@ -1055,7 +1046,7 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
dmaengine_terminate_all(chan);
dma_unmap_sg(chan->device->dev,
host->data->sg, host->data->sg_len,
omap_hsmmc_get_dma_dir(host, host->data));
mmc_get_dma_dir(host->data));
host->data->host_cookie = 0;
}
......@@ -1350,7 +1341,7 @@ static void omap_hsmmc_dma_callback(void *param)
if (!data->host_cookie)
dma_unmap_sg(chan->device->dev,
data->sg, data->sg_len,
omap_hsmmc_get_dma_dir(host, data));
mmc_get_dma_dir(data));
req_in_progress = host->req_in_progress;
host->dma_ch = -1;
......@@ -1383,7 +1374,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
/* Check if next job is already prepared */
if (next || data->host_cookie != host->next_data.cookie) {
dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
omap_hsmmc_get_dma_dir(host, data));
mmc_get_dma_dir(data));
} else {
dma_len = host->next_data.dma_len;
......@@ -1569,7 +1560,7 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data);
dma_unmap_sg(c->device->dev, data->sg, data->sg_len,
omap_hsmmc_get_dma_dir(host, data));
mmc_get_dma_dir(data));
data->host_cookie = 0;
}
}
......@@ -1770,8 +1761,8 @@ static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host)
*/
if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING) {
struct pinctrl *p = devm_pinctrl_get(host->dev);
if (!p) {
ret = -ENODEV;
if (IS_ERR(p)) {
ret = PTR_ERR(p);
goto err_free_irq;
}
if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT))) {
......
This diff is collapsed.
......@@ -263,10 +263,8 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
/* Platform specific code during sd probe slot goes here */
if (hid && !strcmp(hid, "80865ACA")) {
if (hid && !strcmp(hid, "80865ACA"))
host->mmc_host_ops.get_cd = bxt_get_cd;
host->mmc->caps |= MMC_CAP_AGGRESSIVE_PM;
}
return 0;
}
......@@ -302,7 +300,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_STOP_WITH_TC,
.caps = MMC_CAP_WAIT_WHILE_BUSY,
.caps = MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM,
.probe_slot = sdhci_acpi_sd_probe_slot,
};
......@@ -524,8 +522,12 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
static int sdhci_acpi_suspend(struct device *dev)
{
struct sdhci_acpi_host *c = dev_get_drvdata(dev);
struct sdhci_host *host = c->host;
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
return sdhci_suspend_host(c->host);
return sdhci_suspend_host(host);
}
static int sdhci_acpi_resume(struct device *dev)
......@@ -544,8 +546,12 @@ static int sdhci_acpi_resume(struct device *dev)
static int sdhci_acpi_runtime_suspend(struct device *dev)
{
struct sdhci_acpi_host *c = dev_get_drvdata(dev);
struct sdhci_host *host = c->host;
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
return sdhci_runtime_suspend_host(c->host);
return sdhci_runtime_suspend_host(host);
}
static int sdhci_acpi_runtime_resume(struct device *dev)
......
......@@ -29,6 +29,9 @@ static int sdhci_brcmstb_suspend(struct device *dev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int res;
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
res = sdhci_suspend_host(host);
if (res)
return res;
......
This diff is collapsed.
......@@ -889,6 +889,28 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
}
}
static void esdhc_reset_tuning(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 ctrl;
/* Rest the tuning circurt */
if (esdhc_is_usdhc(imx_data)) {
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
ctrl = readl(host->ioaddr + SDHCI_ACMD12_ERR);
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
writel(ctrl, host->ioaddr + SDHCI_ACMD12_ERR);
}
}
}
static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
{
u32 m;
......@@ -932,6 +954,10 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
host->ops->set_clock(host, host->clock);
esdhc_set_strobe_dll(host);
break;
case MMC_TIMING_LEGACY:
default:
esdhc_reset_tuning(host);
break;
}
esdhc_change_pinstate(host, timing);
......@@ -1323,6 +1349,9 @@ static int sdhci_esdhc_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
return sdhci_suspend_host(host);
}
......@@ -1347,6 +1376,9 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
ret = sdhci_runtime_suspend_host(host);
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
if (!sdhci_sdio_irq_enabled(host)) {
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
......
......@@ -37,6 +37,7 @@
/* Protocol Control Register */
#define ESDHC_PROCTL 0x28
#define ESDHC_VOLT_SEL 0x00000400
#define ESDHC_CTRL_4BITBUS (0x1 << 1)
#define ESDHC_CTRL_8BITBUS (0x2 << 1)
#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
......@@ -52,8 +53,14 @@
#define ESDHC_CLOCK_HCKEN 0x00000002
#define ESDHC_CLOCK_IPGEN 0x00000001
/* Tuning Block Control Register */
#define ESDHC_TBCTL 0x120
#define ESDHC_TB_EN 0x00000004
/* Control Register for DMA transfer */
#define ESDHC_DMA_SYSCTL 0x40c
#define ESDHC_PERIPHERAL_CLK_SEL 0x00080000
#define ESDHC_FLUSH_ASYNC_FIFO 0x00040000
#define ESDHC_DMA_SNOOP 0x00000040
#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
......@@ -991,12 +991,8 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
spin_unlock_irq(&host->lock);
if (mmc->ios.timing == MMC_TIMING_MMC_HS400)
sdhci_msm_hs400(host, &mmc->ios);
spin_lock_irq(&host->lock);
}
static void sdhci_msm_voltage_switch(struct sdhci_host *host)
......@@ -1089,13 +1085,9 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
goto out;
}
spin_unlock_irq(&host->lock);
sdhci_msm_hc_select_mode(host);
msm_set_clock_rate_for_bus_mode(host, clock);
spin_lock_irq(&host->lock);
out:
__sdhci_msm_set_clock(host, clock);
}
......
......@@ -157,21 +157,6 @@ static int sdhci_arasan_syscon_write(struct sdhci_host *host,
return ret;
}
static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
{
unsigned long freq;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
/* SDHCI timeout clock is in kHz */
freq = DIV_ROUND_UP(clk_get_rate(pltfm_host->clk), 1000);
/* or in MHz */
if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
freq = DIV_ROUND_UP(freq, 1000);
return freq;
}
static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
......@@ -194,9 +179,7 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
* through low speeds without power cycling.
*/
sdhci_set_clock(host, host->max_clk);
spin_unlock_irq(&host->lock);
phy_power_on(sdhci_arasan->phy);
spin_lock_irq(&host->lock);
sdhci_arasan->is_phy_on = true;
/*
......@@ -215,18 +198,14 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
}
if (ctrl_phy && sdhci_arasan->is_phy_on) {
spin_unlock_irq(&host->lock);
phy_power_off(sdhci_arasan->phy);
spin_lock_irq(&host->lock);
sdhci_arasan->is_phy_on = false;
}
sdhci_set_clock(host, clock);
if (ctrl_phy) {
spin_unlock_irq(&host->lock);
phy_power_on(sdhci_arasan->phy);
spin_lock_irq(&host->lock);
sdhci_arasan->is_phy_on = true;
}
}
......@@ -286,7 +265,7 @@ static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
static struct sdhci_ops sdhci_arasan_ops = {
.set_clock = sdhci_arasan_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_arasan_get_timeout_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,
......@@ -315,6 +294,9 @@ static int sdhci_arasan_suspend(struct device *dev)
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
int ret;
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
ret = sdhci_suspend_host(host);
if (ret)
return ret;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -3,6 +3,3 @@
struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno);
EXPORT_SYMBOL_GPL(sdhci_pci_get_data);
int sdhci_pci_spt_drive_strength;
EXPORT_SYMBOL_GPL(sdhci_pci_spt_drive_strength);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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