Commit 17a13590 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v4.4' of git://git.linaro.org/people/ulf.hansson/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Add new API to set VCCQ voltage - mmc_regulator_set_vqmmc()
   - Add new ioctl to allow userspace to send multi commands
   - Wait for card busy signalling before starting SDIO requests
   - Remove MMC_CLKGATE
   - Enable tuning for DDR50 mode
   - Some code clean-up/improvements to mmc pwrseq
   - Use highest priority for eMMC restart handler
   - Add DT bindings for eMMC hardware reset support
   - Extend the mmc_send_tuning() API
   - Improve ios show for debugfs
   - A couple of code optimizations

  MMC host:
   - Some generic OF improvements
   - Various code clean-ups
   - sirf: Add support for DDR50
   - sunxi: Add support for card busy detection
   - mediatek: Use MMC_CAP_RUNTIME_RESUME
   - mediatek: Add support for eMMC HW-reset
   - mediatek: Add support for HS400
   - dw_mmc: Convert to use the new mmc_regulator_set_vqmmc() API
   - dw_mmc: Add external DMA interface support
   - dw_mmc: Some various improvements
   - dw_mmc-rockchip: MMC tuning with the clock phase framework
   - sdhci: Properly clear IRQs during resume
   - sdhci: Enable tuning for DDR50 mode
   - sdhci-of-esdhc: Use IRQ mode for card detection
   - sdhci-of-esdhc: Support both BE and LE host controller
   - sdhci-pci: Build o2micro support in the same module
   - sdhci-pci: Support for new Intel host controllers
   - sdhci-acpi: Support for new Intel host controllers"

* tag 'mmc-v4.4' of git://git.linaro.org/people/ulf.hansson/mmc: (73 commits)
  mmc: dw_mmc: fix the wrong setting for UHS-DDR50 mode
  mmc: dw_mmc: fix the CardThreshold boundary at CardThrCtl register
  mmc: dw_mmc: NULL dereference in error message
  mmc: pwrseq: Use highest priority for eMMC restart handler
  mmc: mediatek: add HS400 support
  mmc: mmc: extend the mmc_send_tuning()
  mmc: mediatek: add implement of ops->hw_reset()
  mmc: mediatek: fix got GPD checksum error interrupt when data transfer
  mmc: mediatek: change the argument "ddr" to "timing"
  mmc: mediatek: make cmd_ints_mask to const
  mmc: dt-bindings: update Mediatek MMC bindings
  mmc: core: Add DT bindings for eMMC hardware reset support
  mmc: omap_hsmmc: Enable omap_hsmmc for Keystone 2
  mmc: sdhci-acpi: Add more ACPI HIDs for Intel controllers
  mmc: sdhci-pci: Add more PCI IDs for Intel controllers
  arm: lpc18xx_defconfig: remove CONFIG_MMC_DW_IDMAC
  arm: hisi_defconfig: remove CONFIG_MMC_DW_IDMAC
  arm: exynos_defconfig: remove CONFIG_MMC_DW_IDMAC
  arc: axs10x_defconfig: remove CONFIG_MMC_DW_IDMAC
  mips: pistachio_defconfig: remove CONFIG_MMC_DW_IDMAC
  ...
parents 66b01996 7cc8d580
...@@ -22,6 +22,8 @@ Optional properties: ...@@ -22,6 +22,8 @@ Optional properties:
- voltage-ranges : two cells are required, first cell specifies minimum - voltage-ranges : two cells are required, first cell specifies minimum
slot voltage (mV), second cell specifies maximum slot voltage (mV). slot voltage (mV), second cell specifies maximum slot voltage (mV).
Several ranges could be specified. Several ranges could be specified.
- little-endian : If the host controller is little-endian mode, specify
this property. The default endian mode is big-endian.
Example: Example:
......
...@@ -37,6 +37,7 @@ Optional properties: ...@@ -37,6 +37,7 @@ Optional properties:
- sd-uhs-sdr104: SD UHS SDR104 speed is supported - sd-uhs-sdr104: SD UHS SDR104 speed is supported
- sd-uhs-ddr50: SD UHS DDR50 speed is supported - sd-uhs-ddr50: SD UHS DDR50 speed is supported
- cap-power-off-card: powering off the card is safe - cap-power-off-card: powering off the card is safe
- cap-mmc-hw-reset: eMMC hardware reset is supported
- cap-sdio-irq: enable SDIO IRQ signalling on this interface - cap-sdio-irq: enable SDIO IRQ signalling on this interface
- full-pwr-cycle: full power cycle of the card is supported - full-pwr-cycle: full power cycle of the card is supported
- mmc-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported - mmc-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported
......
...@@ -17,6 +17,11 @@ Required properties: ...@@ -17,6 +17,11 @@ Required properties:
- vmmc-supply: power to the Core - vmmc-supply: power to the Core
- vqmmc-supply: power to the IO - vqmmc-supply: power to the IO
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
Examples: Examples:
mmc0: mmc@11230000 { mmc0: mmc@11230000 {
compatible = "mediatek,mt8173-mmc", "mediatek,mt8135-mmc"; compatible = "mediatek,mt8173-mmc", "mediatek,mt8135-mmc";
...@@ -24,9 +29,13 @@ mmc0: mmc@11230000 { ...@@ -24,9 +29,13 @@ mmc0: mmc@11230000 {
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>; interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
vmmc-supply = <&mt6397_vemc_3v3_reg>; vmmc-supply = <&mt6397_vemc_3v3_reg>;
vqmmc-supply = <&mt6397_vio18_reg>; vqmmc-supply = <&mt6397_vio18_reg>;
clocks = <&pericfg CLK_PERI_MSDC30_0>, <&topckgen CLK_TOP_MSDC50_0_H_SEL>; clocks = <&pericfg CLK_PERI_MSDC30_0>,
<&topckgen CLK_TOP_MSDC50_0_H_SEL>;
clock-names = "source", "hclk"; clock-names = "source", "hclk";
pinctrl-names = "default", "state_uhs"; pinctrl-names = "default", "state_uhs";
pinctrl-0 = <&mmc0_pins_default>; pinctrl-0 = <&mmc0_pins_default>;
pinctrl-1 = <&mmc0_pins_uhs>; pinctrl-1 = <&mmc0_pins_uhs>;
assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
hs400-ds-delay = <0x14015>;
}; };
...@@ -6,11 +6,12 @@ and the properties used by the MMCIF device. ...@@ -6,11 +6,12 @@ and the properties used by the MMCIF device.
Required properties: Required properties:
- compatible: must contain one of the following - compatible: should be "renesas,mmcif-<soctype>", "renesas,sh-mmcif" as a
fallback. Examples with <soctype> are:
- "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs - "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
- "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs - "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
- "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs - "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
- "renesas,sh-mmcif" for the generic MMCIF - "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs
- clocks: reference to the functional clock - clocks: reference to the functional clock
......
...@@ -14,6 +14,19 @@ Required Properties: ...@@ -14,6 +14,19 @@ Required Properties:
before RK3288 before RK3288
- "rockchip,rk3288-dw-mshc": for Rockchip RK3288 - "rockchip,rk3288-dw-mshc": for Rockchip RK3288
Optional Properties:
* clocks: from common clock binding: if ciu_drive and ciu_sample are
specified in clock-names, should contain handles to these clocks.
* clock-names: Apart from the clock-names described in synopsys-dw-mshc.txt
two more clocks "ciu-drive" and "ciu-sample" are supported. They are used
to control the clock phases, "ciu-sample" is required for tuning high-
speed modes.
* rockchip,default-sample-phase: The default phase to set ciu_sample at
probing, low speeds or in case where all phases work at tuning time.
If not specified 0 deg will be used.
Example: Example:
rkdwmmc0@12200000 { rkdwmmc0@12200000 {
......
...@@ -75,6 +75,12 @@ Optional properties: ...@@ -75,6 +75,12 @@ Optional properties:
* vmmc-supply: The phandle to the regulator to use for vmmc. If this is * vmmc-supply: The phandle to the regulator to use for vmmc. If this is
specified we'll defer probe until we can find this regulator. specified we'll defer probe until we can find this regulator.
* dmas: List of DMA specifiers with the controller specific format as described
in the generic DMA client binding. Refer to dma.txt for details.
* dma-names: request names for generic DMA client binding. Must be "rx-tx".
Refer to dma.txt for details.
Aliases: Aliases:
- All the MSHC controller nodes should be represented in the aliases node using - All the MSHC controller nodes should be represented in the aliases node using
...@@ -95,6 +101,23 @@ board specific portions as listed below. ...@@ -95,6 +101,23 @@ board specific portions as listed below.
#size-cells = <0>; #size-cells = <0>;
}; };
[board specific internal DMA resources]
dwmmc0@12200000 {
clock-frequency = <400000000>;
clock-freq-min-max = <400000 200000000>;
num-slots = <1>;
broken-cd;
fifo-depth = <0x80>;
card-detect-delay = <200>;
vmmc-supply = <&buck8>;
bus-width = <8>;
cap-mmc-highspeed;
cap-sd-highspeed;
};
[board specific generic DMA request binding]
dwmmc0@12200000 { dwmmc0@12200000 {
clock-frequency = <400000000>; clock-frequency = <400000000>;
clock-freq-min-max = <400000 200000000>; clock-freq-min-max = <400000 200000000>;
...@@ -106,4 +129,6 @@ board specific portions as listed below. ...@@ -106,4 +129,6 @@ board specific portions as listed below.
bus-width = <8>; bus-width = <8>;
cap-mmc-highspeed; cap-mmc-highspeed;
cap-sd-highspeed; cap-sd-highspeed;
dmas = <&pdma 12>;
dma-names = "rx-tx";
}; };
...@@ -72,13 +72,3 @@ Note on raw_rpmb_size_mult: ...@@ -72,13 +72,3 @@ Note on raw_rpmb_size_mult:
"raw_rpmb_size_mult" is a mutliple of 128kB block. "raw_rpmb_size_mult" is a mutliple of 128kB block.
RPMB size in byte is calculated by using the following equation: RPMB size in byte is calculated by using the following equation:
RPMB partition size = 128kB x raw_rpmb_size_mult RPMB partition size = 128kB x raw_rpmb_size_mult
SD/MMC/SDIO Clock Gating Attribute
==================================
Read and write access is provided to following attribute.
This attribute appears only if CONFIG_MMC_CLKGATE is enabled.
clkgate_delay Tune the clock gating delay with desired value in milliseconds.
echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay
...@@ -89,7 +89,6 @@ CONFIG_MMC=y ...@@ -89,7 +89,6 @@ CONFIG_MMC=y
CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_DW=y CONFIG_MMC_DW=y
CONFIG_MMC_DW_IDMAC=y
# CONFIG_IOMMU_SUPPORT is not set # CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT3_FS=y CONFIG_EXT3_FS=y
CONFIG_EXT4_FS=y CONFIG_EXT4_FS=y
......
...@@ -95,7 +95,6 @@ CONFIG_MMC=y ...@@ -95,7 +95,6 @@ CONFIG_MMC=y
CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_DW=y CONFIG_MMC_DW=y
CONFIG_MMC_DW_IDMAC=y
# CONFIG_IOMMU_SUPPORT is not set # CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT3_FS=y CONFIG_EXT3_FS=y
CONFIG_EXT4_FS=y CONFIG_EXT4_FS=y
......
...@@ -96,7 +96,6 @@ CONFIG_MMC=y ...@@ -96,7 +96,6 @@ CONFIG_MMC=y
CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_DW=y CONFIG_MMC_DW=y
CONFIG_MMC_DW_IDMAC=y
# CONFIG_IOMMU_SUPPORT is not set # CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT3_FS=y CONFIG_EXT3_FS=y
CONFIG_EXT4_FS=y CONFIG_EXT4_FS=y
......
...@@ -90,7 +90,7 @@ &rk808 { ...@@ -90,7 +90,7 @@ &rk808 {
regulators { regulators {
vccio_sd: LDO_REG4 { vccio_sd: LDO_REG4 {
regulator-name = "vccio_sd"; regulator-name = "vccio_sd";
regulator-min-microvolt = <3300000>; regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>; regulator-max-microvolt = <3300000>;
regulator-state-mem { regulator-state-mem {
regulator-off-in-suspend; regulator-off-in-suspend;
...@@ -116,7 +116,12 @@ &sdmmc { ...@@ -116,7 +116,12 @@ &sdmmc {
cap-sd-highspeed; cap-sd-highspeed;
card-detect-delay = <200>; card-detect-delay = <200>;
cd-gpios = <&gpio7 5 GPIO_ACTIVE_LOW>; cd-gpios = <&gpio7 5 GPIO_ACTIVE_LOW>;
rockchip,default-sample-phase = <90>;
num-slots = <1>; num-slots = <1>;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-sdr104;
vmmc-supply = <&vcc33_sd>; vmmc-supply = <&vcc33_sd>;
vqmmc-supply = <&vccio_sd>; vqmmc-supply = <&vccio_sd>;
}; };
...@@ -149,7 +149,9 @@ &emmc { ...@@ -149,7 +149,9 @@ &emmc {
broken-cd; broken-cd;
bus-width = <8>; bus-width = <8>;
cap-mmc-highspeed; cap-mmc-highspeed;
rockchip,default-sample-phase = <158>;
disable-wp; disable-wp;
mmc-hs200-1_8v;
mmc-pwrseq = <&emmc_pwrseq>; mmc-pwrseq = <&emmc_pwrseq>;
non-removable; non-removable;
num-slots = <1>; num-slots = <1>;
...@@ -355,6 +357,10 @@ &sdio0 { ...@@ -355,6 +357,10 @@ &sdio0 {
num-slots = <1>; num-slots = <1>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&sdio0_clk &sdio0_cmd &sdio0_bus4>; pinctrl-0 = <&sdio0_clk &sdio0_cmd &sdio0_bus4>;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-sdr104;
vmmc-supply = <&vcc33_sys>; vmmc-supply = <&vcc33_sys>;
vqmmc-supply = <&vcc18_wl>; vqmmc-supply = <&vcc18_wl>;
}; };
......
...@@ -222,8 +222,9 @@ display-subsystem { ...@@ -222,8 +222,9 @@ display-subsystem {
sdmmc: dwmmc@ff0c0000 { sdmmc: dwmmc@ff0c0000 {
compatible = "rockchip,rk3288-dw-mshc"; compatible = "rockchip,rk3288-dw-mshc";
clock-freq-min-max = <400000 150000000>; clock-freq-min-max = <400000 150000000>;
clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>; clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
clock-names = "biu", "ciu"; <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>; fifo-depth = <0x100>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xff0c0000 0x4000>; reg = <0xff0c0000 0x4000>;
...@@ -233,8 +234,9 @@ sdmmc: dwmmc@ff0c0000 { ...@@ -233,8 +234,9 @@ sdmmc: dwmmc@ff0c0000 {
sdio0: dwmmc@ff0d0000 { sdio0: dwmmc@ff0d0000 {
compatible = "rockchip,rk3288-dw-mshc"; compatible = "rockchip,rk3288-dw-mshc";
clock-freq-min-max = <400000 150000000>; clock-freq-min-max = <400000 150000000>;
clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>; clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>,
clock-names = "biu", "ciu"; <&cru SCLK_SDIO0_DRV>, <&cru SCLK_SDIO0_SAMPLE>;
clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>; fifo-depth = <0x100>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xff0d0000 0x4000>; reg = <0xff0d0000 0x4000>;
...@@ -244,8 +246,9 @@ sdio0: dwmmc@ff0d0000 { ...@@ -244,8 +246,9 @@ sdio0: dwmmc@ff0d0000 {
sdio1: dwmmc@ff0e0000 { sdio1: dwmmc@ff0e0000 {
compatible = "rockchip,rk3288-dw-mshc"; compatible = "rockchip,rk3288-dw-mshc";
clock-freq-min-max = <400000 150000000>; clock-freq-min-max = <400000 150000000>;
clocks = <&cru HCLK_SDIO1>, <&cru SCLK_SDIO1>; clocks = <&cru HCLK_SDIO1>, <&cru SCLK_SDIO1>,
clock-names = "biu", "ciu"; <&cru SCLK_SDIO1_DRV>, <&cru SCLK_SDIO1_SAMPLE>;
clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>; fifo-depth = <0x100>;
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xff0e0000 0x4000>; reg = <0xff0e0000 0x4000>;
...@@ -255,8 +258,9 @@ sdio1: dwmmc@ff0e0000 { ...@@ -255,8 +258,9 @@ sdio1: dwmmc@ff0e0000 {
emmc: dwmmc@ff0f0000 { emmc: dwmmc@ff0f0000 {
compatible = "rockchip,rk3288-dw-mshc"; compatible = "rockchip,rk3288-dw-mshc";
clock-freq-min-max = <400000 150000000>; clock-freq-min-max = <400000 150000000>;
clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>; clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
clock-names = "biu", "ciu"; <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>; fifo-depth = <0x100>;
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xff0f0000 0x4000>; reg = <0xff0f0000 0x4000>;
......
...@@ -166,7 +166,6 @@ CONFIG_MMC_SDHCI=y ...@@ -166,7 +166,6 @@ CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_S3C=y CONFIG_MMC_SDHCI_S3C=y
CONFIG_MMC_SDHCI_S3C_DMA=y CONFIG_MMC_SDHCI_S3C_DMA=y
CONFIG_MMC_DW=y CONFIG_MMC_DW=y
CONFIG_MMC_DW_IDMAC=y
CONFIG_MMC_DW_EXYNOS=y CONFIG_MMC_DW_EXYNOS=y
CONFIG_RTC_CLASS=y CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MAX77686=y CONFIG_RTC_DRV_MAX77686=y
......
...@@ -69,7 +69,6 @@ CONFIG_NOP_USB_XCEIV=y ...@@ -69,7 +69,6 @@ CONFIG_NOP_USB_XCEIV=y
CONFIG_MMC=y CONFIG_MMC=y
CONFIG_RTC_CLASS=y CONFIG_RTC_CLASS=y
CONFIG_MMC_DW=y CONFIG_MMC_DW=y
CONFIG_MMC_DW_IDMAC=y
CONFIG_MMC_DW_PLTFM=y CONFIG_MMC_DW_PLTFM=y
CONFIG_RTC_DRV_PL031=y CONFIG_RTC_DRV_PL031=y
CONFIG_DMADEVICES=y CONFIG_DMADEVICES=y
......
...@@ -119,7 +119,6 @@ CONFIG_USB_EHCI_HCD=y ...@@ -119,7 +119,6 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_MMC=y CONFIG_MMC=y
CONFIG_MMC_DW=y CONFIG_MMC_DW=y
CONFIG_MMC_DW_IDMAC=y
CONFIG_NEW_LEDS=y CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS=y
CONFIG_LEDS_PCA9532=y CONFIG_LEDS_PCA9532=y
......
...@@ -257,7 +257,6 @@ CONFIG_MMC=y ...@@ -257,7 +257,6 @@ CONFIG_MMC=y
CONFIG_MMC_BLOCK_MINORS=16 CONFIG_MMC_BLOCK_MINORS=16
CONFIG_MMC_TEST=m CONFIG_MMC_TEST=m
CONFIG_MMC_DW=y CONFIG_MMC_DW=y
CONFIG_MMC_DW_IDMAC=y
CONFIG_NEW_LEDS=y CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS=y
CONFIG_RTC_CLASS=y CONFIG_RTC_CLASS=y
......
...@@ -45,8 +45,8 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw, ...@@ -45,8 +45,8 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
#define PSECS_PER_SEC 1000000000000LL #define PSECS_PER_SEC 1000000000000LL
/* /*
* Each fine delay is between 40ps-80ps. Assume each fine delay is 60ps to * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
* simplify calculations. So 45degs could be anywhere between 33deg and 66deg. * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
*/ */
#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
...@@ -69,7 +69,7 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw) ...@@ -69,7 +69,7 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw)
delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
degrees += delay_num * factor / 10000; degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
} }
return degrees % 360; return degrees % 360;
...@@ -82,25 +82,41 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees) ...@@ -82,25 +82,41 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
u8 nineties, remainder; u8 nineties, remainder;
u8 delay_num; u8 delay_num;
u32 raw_value; u32 raw_value;
u64 delay; u32 delay;
/* allow 22 to be 22.5 */
degrees++;
/* floor to 22.5 increment */
degrees -= ((degrees) * 10 % 225) / 10;
nineties = degrees / 90; nineties = degrees / 90;
/* 22.5 multiples */ remainder = (degrees % 90);
remainder = (degrees % 90) / 22;
/*
delay = PSECS_PER_SEC; * Due to the inexact nature of the "fine" delay, we might
do_div(delay, rate); * actually go non-monotonic. We don't go _too_ monotonic
/* / 360 / 22.5 */ * though, so we should be OK. Here are options of how we may
do_div(delay, 16); * work:
do_div(delay, ROCKCHIP_MMC_DELAY_ELEMENT_PSEC); *
* Ideally we end up with:
* 1.0, 2.0, ..., 69.0, 70.0, ..., 89.0, 90.0
*
* On one extreme (if delay is actually 44ps):
* .73, 1.5, ..., 50.6, 51.3, ..., 65.3, 90.0
* The other (if delay is actually 77ps):
* 1.3, 2.6, ..., 88.6. 89.8, ..., 114.0, 90
*
* It's possible we might make a delay that is up to 25
* degrees off from what we think we're making. That's OK
* though because we should be REALLY far from any bad range.
*/
/*
* Convert to delay; do a little extra work to make sure we
* don't overflow 32-bit / 64-bit numbers.
*/
delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
delay *= remainder; delay *= remainder;
delay_num = (u8) min(delay, 255ULL); delay = DIV_ROUND_CLOSEST(delay,
(rate / 1000) * 36 *
(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
delay_num = (u8) min_t(u32, delay, 255);
raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
......
...@@ -387,6 +387,24 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( ...@@ -387,6 +387,24 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
return ERR_PTR(err); return ERR_PTR(err);
} }
static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr,
struct mmc_blk_ioc_data *idata)
{
struct mmc_ioc_cmd *ic = &idata->ic;
if (copy_to_user(&(ic_ptr->response), ic->response,
sizeof(ic->response)))
return -EFAULT;
if (!idata->ic.write_flag) {
if (copy_to_user((void __user *)(unsigned long)ic->data_ptr,
idata->buf, idata->buf_bytes))
return -EFAULT;
}
return 0;
}
static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
u32 retries_max) u32 retries_max)
{ {
...@@ -447,12 +465,9 @@ static int ioctl_do_sanitize(struct mmc_card *card) ...@@ -447,12 +465,9 @@ static int ioctl_do_sanitize(struct mmc_card *card)
return err; return err;
} }
static int mmc_blk_ioctl_cmd(struct block_device *bdev, static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
struct mmc_ioc_cmd __user *ic_ptr) struct mmc_blk_ioc_data *idata)
{ {
struct mmc_blk_ioc_data *idata;
struct mmc_blk_data *md;
struct mmc_card *card;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
struct mmc_data data = {0}; struct mmc_data data = {0};
struct mmc_request mrq = {NULL}; struct mmc_request mrq = {NULL};
...@@ -461,33 +476,12 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -461,33 +476,12 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
int is_rpmb = false; int is_rpmb = false;
u32 status = 0; u32 status = 0;
/* if (!card || !md || !idata)
* The caller must have CAP_SYS_RAWIO, and must be calling this on the return -EINVAL;
* whole block device, not on a partition. This prevents overspray
* between sibling partitions.
*/
if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
return -EPERM;
idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
if (IS_ERR(idata))
return PTR_ERR(idata);
md = mmc_blk_get(bdev->bd_disk);
if (!md) {
err = -EINVAL;
goto cmd_err;
}
if (md->area_type & MMC_BLK_DATA_AREA_RPMB) if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
is_rpmb = true; is_rpmb = true;
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
goto cmd_done;
}
cmd.opcode = idata->ic.opcode; cmd.opcode = idata->ic.opcode;
cmd.arg = idata->ic.arg; cmd.arg = idata->ic.arg;
cmd.flags = idata->ic.flags; cmd.flags = idata->ic.flags;
...@@ -530,23 +524,21 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -530,23 +524,21 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mrq.cmd = &cmd; mrq.cmd = &cmd;
mmc_get_card(card);
err = mmc_blk_part_switch(card, md); err = mmc_blk_part_switch(card, md);
if (err) if (err)
goto cmd_rel_host; return err;
if (idata->ic.is_acmd) { if (idata->ic.is_acmd) {
err = mmc_app_cmd(card->host, card); err = mmc_app_cmd(card->host, card);
if (err) if (err)
goto cmd_rel_host; return err;
} }
if (is_rpmb) { if (is_rpmb) {
err = mmc_set_blockcount(card, data.blocks, err = mmc_set_blockcount(card, data.blocks,
idata->ic.write_flag & (1 << 31)); idata->ic.write_flag & (1 << 31));
if (err) if (err)
goto cmd_rel_host; return err;
} }
if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) && if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) &&
...@@ -557,7 +549,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -557,7 +549,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
pr_err("%s: ioctl_do_sanitize() failed. err = %d", pr_err("%s: ioctl_do_sanitize() failed. err = %d",
__func__, err); __func__, err);
goto cmd_rel_host; return err;
} }
mmc_wait_for_req(card->host, &mrq); mmc_wait_for_req(card->host, &mrq);
...@@ -565,14 +557,12 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -565,14 +557,12 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
if (cmd.error) { if (cmd.error) {
dev_err(mmc_dev(card->host), "%s: cmd error %d\n", dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
__func__, cmd.error); __func__, cmd.error);
err = cmd.error; return cmd.error;
goto cmd_rel_host;
} }
if (data.error) { if (data.error) {
dev_err(mmc_dev(card->host), "%s: data error %d\n", dev_err(mmc_dev(card->host), "%s: data error %d\n",
__func__, data.error); __func__, data.error);
err = data.error; return data.error;
goto cmd_rel_host;
} }
/* /*
...@@ -582,18 +572,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -582,18 +572,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
if (idata->ic.postsleep_min_us) if (idata->ic.postsleep_min_us)
usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us); usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
if (copy_to_user(&(ic_ptr->response), cmd.resp, sizeof(cmd.resp))) { memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp));
err = -EFAULT;
goto cmd_rel_host;
}
if (!idata->ic.write_flag) {
if (copy_to_user((void __user *)(unsigned long) idata->ic.data_ptr,
idata->buf, idata->buf_bytes)) {
err = -EFAULT;
goto cmd_rel_host;
}
}
if (is_rpmb) { if (is_rpmb) {
/* /*
...@@ -607,24 +586,132 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -607,24 +586,132 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
__func__, status, err); __func__, status, err);
} }
cmd_rel_host: return err;
}
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_ioc_cmd __user *ic_ptr)
{
struct mmc_blk_ioc_data *idata;
struct mmc_blk_data *md;
struct mmc_card *card;
int err = 0, ioc_err = 0;
idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
if (IS_ERR(idata))
return PTR_ERR(idata);
md = mmc_blk_get(bdev->bd_disk);
if (!md) {
err = -EINVAL;
goto cmd_err;
}
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
goto cmd_done;
}
mmc_get_card(card);
ioc_err = __mmc_blk_ioctl_cmd(card, md, idata);
mmc_put_card(card); mmc_put_card(card);
err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata);
cmd_done: cmd_done:
mmc_blk_put(md); mmc_blk_put(md);
cmd_err: cmd_err:
kfree(idata->buf); kfree(idata->buf);
kfree(idata); kfree(idata);
return err; return ioc_err ? ioc_err : err;
}
static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
struct mmc_ioc_multi_cmd __user *user)
{
struct mmc_blk_ioc_data **idata = NULL;
struct mmc_ioc_cmd __user *cmds = user->cmds;
struct mmc_card *card;
struct mmc_blk_data *md;
int i, err = 0, ioc_err = 0;
__u64 num_of_cmds;
if (copy_from_user(&num_of_cmds, &user->num_of_cmds,
sizeof(num_of_cmds)))
return -EFAULT;
if (num_of_cmds > MMC_IOC_MAX_CMDS)
return -EINVAL;
idata = kcalloc(num_of_cmds, sizeof(*idata), GFP_KERNEL);
if (!idata)
return -ENOMEM;
for (i = 0; i < num_of_cmds; i++) {
idata[i] = mmc_blk_ioctl_copy_from_user(&cmds[i]);
if (IS_ERR(idata[i])) {
err = PTR_ERR(idata[i]);
num_of_cmds = i;
goto cmd_err;
}
}
md = mmc_blk_get(bdev->bd_disk);
if (!md)
goto cmd_err;
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
goto cmd_done;
}
mmc_get_card(card);
for (i = 0; i < num_of_cmds && !ioc_err; i++)
ioc_err = __mmc_blk_ioctl_cmd(card, md, idata[i]);
mmc_put_card(card);
/* copy to user if data and response */
for (i = 0; i < num_of_cmds && !err; i++)
err = mmc_blk_ioctl_copy_to_user(&cmds[i], idata[i]);
cmd_done:
mmc_blk_put(md);
cmd_err:
for (i = 0; i < num_of_cmds; i++) {
kfree(idata[i]->buf);
kfree(idata[i]);
}
kfree(idata);
return ioc_err ? ioc_err : err;
} }
static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int ret = -EINVAL; /*
if (cmd == MMC_IOC_CMD) * The caller must have CAP_SYS_RAWIO, and must be calling this on the
ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg); * whole block device, not on a partition. This prevents overspray
return ret; * between sibling partitions.
*/
if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
return -EPERM;
switch (cmd) {
case MMC_IOC_CMD:
return mmc_blk_ioctl_cmd(bdev,
(struct mmc_ioc_cmd __user *)arg);
case MMC_IOC_MULTI_CMD:
return mmc_blk_ioctl_multi_cmd(bdev,
(struct mmc_ioc_multi_cmd __user *)arg);
default:
return -EINVAL;
}
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
......
# #
# MMC core configuration # MMC core configuration
# #
config MMC_CLKGATE
bool "MMC host clock gating"
help
This will attempt to aggressively gate the clock to the MMC card.
This is done to save power due to gating off the logic and bus
noise when the MMC card is not in use. Your host driver has to
support handling this in order for it to be of any use.
If unsure, say N.
This diff is collapsed.
...@@ -40,9 +40,6 @@ void mmc_init_erase(struct mmc_card *card); ...@@ -40,9 +40,6 @@ void mmc_init_erase(struct mmc_card *card);
void mmc_set_chip_select(struct mmc_host *host, int mode); void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz); void mmc_set_clock(struct mmc_host *host, unsigned int hz);
void mmc_gate_clock(struct mmc_host *host);
void mmc_ungate_clock(struct mmc_host *host);
void mmc_set_ungated(struct mmc_host *host);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width); void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
......
...@@ -126,6 +126,12 @@ static int mmc_ios_show(struct seq_file *s, void *data) ...@@ -126,6 +126,12 @@ static int mmc_ios_show(struct seq_file *s, void *data)
case MMC_TIMING_SD_HS: case MMC_TIMING_SD_HS:
str = "sd high-speed"; str = "sd high-speed";
break; break;
case MMC_TIMING_UHS_SDR12:
str = "sd uhs SDR12";
break;
case MMC_TIMING_UHS_SDR25:
str = "sd uhs SDR25";
break;
case MMC_TIMING_UHS_SDR50: case MMC_TIMING_UHS_SDR50:
str = "sd uhs SDR50"; str = "sd uhs SDR50";
break; break;
...@@ -166,6 +172,25 @@ static int mmc_ios_show(struct seq_file *s, void *data) ...@@ -166,6 +172,25 @@ static int mmc_ios_show(struct seq_file *s, void *data)
} }
seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str); seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str);
switch (ios->drv_type) {
case MMC_SET_DRIVER_TYPE_A:
str = "driver type A";
break;
case MMC_SET_DRIVER_TYPE_B:
str = "driver type B";
break;
case MMC_SET_DRIVER_TYPE_C:
str = "driver type C";
break;
case MMC_SET_DRIVER_TYPE_D:
str = "driver type D";
break;
default:
str = "invalid";
break;
}
seq_printf(s, "driver type:\t%u (%s)\n", ios->drv_type, str);
return 0; return 0;
} }
...@@ -230,11 +255,6 @@ void mmc_add_host_debugfs(struct mmc_host *host) ...@@ -230,11 +255,6 @@ void mmc_add_host_debugfs(struct mmc_host *host)
&mmc_clock_fops)) &mmc_clock_fops))
goto err_node; goto err_node;
#ifdef CONFIG_MMC_CLKGATE
if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
root, &host->clk_delay))
goto err_node;
#endif
#ifdef CONFIG_FAIL_MMC_REQUEST #ifdef CONFIG_FAIL_MMC_REQUEST
if (fail_request) if (fail_request)
setup_fault_attr(&fail_default_attr, fail_request); setup_fault_attr(&fail_default_attr, fail_request);
......
...@@ -61,246 +61,6 @@ void mmc_unregister_host_class(void) ...@@ -61,246 +61,6 @@ void mmc_unregister_host_class(void)
class_unregister(&mmc_host_class); class_unregister(&mmc_host_class);
} }
#ifdef CONFIG_MMC_CLKGATE
static ssize_t clkgate_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
}
static ssize_t clkgate_delay_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
unsigned long flags, value;
if (kstrtoul(buf, 0, &value))
return -EINVAL;
spin_lock_irqsave(&host->clk_lock, flags);
host->clkgate_delay = value;
spin_unlock_irqrestore(&host->clk_lock, flags);
return count;
}
/*
* Enabling clock gating will make the core call out to the host
* once up and once down when it performs a request or card operation
* intermingled in any fashion. The driver will see this through
* set_ios() operations with ios.clock field set to 0 to gate (disable)
* the block clock, and to the old frequency to enable it again.
*/
static void mmc_host_clk_gate_delayed(struct mmc_host *host)
{
unsigned long tick_ns;
unsigned long freq = host->ios.clock;
unsigned long flags;
if (!freq) {
pr_debug("%s: frequency set to 0 in disable function, "
"this means the clock is already disabled.\n",
mmc_hostname(host));
return;
}
/*
* New requests may have appeared while we were scheduling,
* then there is no reason to delay the check before
* clk_disable().
*/
spin_lock_irqsave(&host->clk_lock, flags);
/*
* Delay n bus cycles (at least 8 from MMC spec) before attempting
* to disable the MCI block clock. The reference count may have
* gone up again after this delay due to rescheduling!
*/
if (!host->clk_requests) {
spin_unlock_irqrestore(&host->clk_lock, flags);
tick_ns = DIV_ROUND_UP(1000000000, freq);
ndelay(host->clk_delay * tick_ns);
} else {
/* New users appeared while waiting for this work */
spin_unlock_irqrestore(&host->clk_lock, flags);
return;
}
mutex_lock(&host->clk_gate_mutex);
spin_lock_irqsave(&host->clk_lock, flags);
if (!host->clk_requests) {
spin_unlock_irqrestore(&host->clk_lock, flags);
/* This will set host->ios.clock to 0 */
mmc_gate_clock(host);
spin_lock_irqsave(&host->clk_lock, flags);
pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
}
spin_unlock_irqrestore(&host->clk_lock, flags);
mutex_unlock(&host->clk_gate_mutex);
}
/*
* Internal work. Work to disable the clock at some later point.
*/
static void mmc_host_clk_gate_work(struct work_struct *work)
{
struct mmc_host *host = container_of(work, struct mmc_host,
clk_gate_work.work);
mmc_host_clk_gate_delayed(host);
}
/**
* mmc_host_clk_hold - ungate hardware MCI clocks
* @host: host to ungate.
*
* Makes sure the host ios.clock is restored to a non-zero value
* past this call. Increase clock reference count and ungate clock
* if we're the first user.
*/
void mmc_host_clk_hold(struct mmc_host *host)
{
unsigned long flags;
/* cancel any clock gating work scheduled by mmc_host_clk_release() */
cancel_delayed_work_sync(&host->clk_gate_work);
mutex_lock(&host->clk_gate_mutex);
spin_lock_irqsave(&host->clk_lock, flags);
if (host->clk_gated) {
spin_unlock_irqrestore(&host->clk_lock, flags);
mmc_ungate_clock(host);
spin_lock_irqsave(&host->clk_lock, flags);
pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
}
host->clk_requests++;
spin_unlock_irqrestore(&host->clk_lock, flags);
mutex_unlock(&host->clk_gate_mutex);
}
/**
* mmc_host_may_gate_card - check if this card may be gated
* @card: card to check.
*/
static bool mmc_host_may_gate_card(struct mmc_card *card)
{
/* If there is no card we may gate it */
if (!card)
return true;
/*
* Don't gate SDIO cards! These need to be clocked at all times
* since they may be independent systems generating interrupts
* and other events. The clock requests counter from the core will
* go down to zero since the core does not need it, but we will not
* gate the clock, because there is somebody out there that may still
* be using it.
*/
return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
}
/**
* mmc_host_clk_release - gate off hardware MCI clocks
* @host: host to gate.
*
* Calls the host driver with ios.clock set to zero as often as possible
* in order to gate off hardware MCI clocks. Decrease clock reference
* count and schedule disabling of clock.
*/
void mmc_host_clk_release(struct mmc_host *host)
{
unsigned long flags;
spin_lock_irqsave(&host->clk_lock, flags);
host->clk_requests--;
if (mmc_host_may_gate_card(host->card) &&
!host->clk_requests)
schedule_delayed_work(&host->clk_gate_work,
msecs_to_jiffies(host->clkgate_delay));
spin_unlock_irqrestore(&host->clk_lock, flags);
}
/**
* mmc_host_clk_rate - get current clock frequency setting
* @host: host to get the clock frequency for.
*
* Returns current clock frequency regardless of gating.
*/
unsigned int mmc_host_clk_rate(struct mmc_host *host)
{
unsigned long freq;
unsigned long flags;
spin_lock_irqsave(&host->clk_lock, flags);
if (host->clk_gated)
freq = host->clk_old;
else
freq = host->ios.clock;
spin_unlock_irqrestore(&host->clk_lock, flags);
return freq;
}
/**
* mmc_host_clk_init - set up clock gating code
* @host: host with potential clock to control
*/
static inline void mmc_host_clk_init(struct mmc_host *host)
{
host->clk_requests = 0;
/* Hold MCI clock for 8 cycles by default */
host->clk_delay = 8;
/*
* Default clock gating delay is 0ms to avoid wasting power.
* This value can be tuned by writing into sysfs entry.
*/
host->clkgate_delay = 0;
host->clk_gated = false;
INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
spin_lock_init(&host->clk_lock);
mutex_init(&host->clk_gate_mutex);
}
/**
* mmc_host_clk_exit - shut down clock gating code
* @host: host with potential clock to control
*/
static inline void mmc_host_clk_exit(struct mmc_host *host)
{
/*
* Wait for any outstanding gate and then make sure we're
* ungated before exiting.
*/
if (cancel_delayed_work_sync(&host->clk_gate_work))
mmc_host_clk_gate_delayed(host);
if (host->clk_gated)
mmc_host_clk_hold(host);
/* There should be only one user now */
WARN_ON(host->clk_requests > 1);
}
static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
{
host->clkgate_delay_attr.show = clkgate_delay_show;
host->clkgate_delay_attr.store = clkgate_delay_store;
sysfs_attr_init(&host->clkgate_delay_attr.attr);
host->clkgate_delay_attr.attr.name = "clkgate_delay";
host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
mmc_hostname(host));
}
#else
static inline void mmc_host_clk_init(struct mmc_host *host)
{
}
static inline void mmc_host_clk_exit(struct mmc_host *host)
{
}
static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
{
}
#endif
void mmc_retune_enable(struct mmc_host *host) void mmc_retune_enable(struct mmc_host *host)
{ {
host->can_retune = 1; host->can_retune = 1;
...@@ -507,6 +267,8 @@ int mmc_of_parse(struct mmc_host *host) ...@@ -507,6 +267,8 @@ int mmc_of_parse(struct mmc_host *host)
host->caps |= MMC_CAP_UHS_DDR50; host->caps |= MMC_CAP_UHS_DDR50;
if (of_property_read_bool(np, "cap-power-off-card")) if (of_property_read_bool(np, "cap-power-off-card"))
host->caps |= MMC_CAP_POWER_OFF_CARD; host->caps |= MMC_CAP_POWER_OFF_CARD;
if (of_property_read_bool(np, "cap-mmc-hw-reset"))
host->caps |= MMC_CAP_HW_RESET;
if (of_property_read_bool(np, "cap-sdio-irq")) if (of_property_read_bool(np, "cap-sdio-irq"))
host->caps |= MMC_CAP_SDIO_IRQ; host->caps |= MMC_CAP_SDIO_IRQ;
if (of_property_read_bool(np, "full-pwr-cycle")) if (of_property_read_bool(np, "full-pwr-cycle"))
...@@ -583,8 +345,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) ...@@ -583,8 +345,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
return NULL; return NULL;
} }
mmc_host_clk_init(host);
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq); init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan); INIT_DELAYED_WORK(&host->detect, mmc_rescan);
...@@ -633,7 +393,6 @@ int mmc_add_host(struct mmc_host *host) ...@@ -633,7 +393,6 @@ int mmc_add_host(struct mmc_host *host)
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
mmc_add_host_debugfs(host); mmc_add_host_debugfs(host);
#endif #endif
mmc_host_clk_sysfs_init(host);
mmc_start_host(host); mmc_start_host(host);
register_pm_notifier(&host->pm_notify); register_pm_notifier(&host->pm_notify);
...@@ -663,8 +422,6 @@ void mmc_remove_host(struct mmc_host *host) ...@@ -663,8 +422,6 @@ void mmc_remove_host(struct mmc_host *host)
device_del(&host->class_dev); device_del(&host->class_dev);
led_trigger_unregister_simple(host->led); led_trigger_unregister_simple(host->led);
mmc_host_clk_exit(host);
} }
EXPORT_SYMBOL(mmc_remove_host); EXPORT_SYMBOL(mmc_remove_host);
......
...@@ -1931,14 +1931,12 @@ static int mmc_reset(struct mmc_host *host) ...@@ -1931,14 +1931,12 @@ static int mmc_reset(struct mmc_host *host)
if (!mmc_can_reset(card)) if (!mmc_can_reset(card))
return -EOPNOTSUPP; return -EOPNOTSUPP;
mmc_host_clk_hold(host);
mmc_set_clock(host, host->f_init); mmc_set_clock(host, host->f_init);
host->ops->hw_reset(host); host->ops->hw_reset(host);
/* Set initial state and call mmc_set_ios */ /* Set initial state and call mmc_set_ios */
mmc_set_initial_state(host); mmc_set_initial_state(host);
mmc_host_clk_release(host);
return mmc_init_card(host, card->ocr, card); return mmc_init_card(host, card->ocr, card);
} }
...@@ -2006,14 +2004,13 @@ int mmc_attach_mmc(struct mmc_host *host) ...@@ -2006,14 +2004,13 @@ int mmc_attach_mmc(struct mmc_host *host)
mmc_release_host(host); mmc_release_host(host);
err = mmc_add_card(host->card); err = mmc_add_card(host->card);
mmc_claim_host(host);
if (err) if (err)
goto remove_card; goto remove_card;
mmc_claim_host(host);
return 0; return 0;
remove_card: remove_card:
mmc_release_host(host);
mmc_remove_card(host->card); mmc_remove_card(host->card);
mmc_claim_host(host); mmc_claim_host(host);
host->card = NULL; host->card = NULL;
......
...@@ -579,7 +579,6 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, ...@@ -579,7 +579,6 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
return err; return err;
} }
EXPORT_SYMBOL_GPL(__mmc_switch);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms) unsigned int timeout_ms)
...@@ -589,7 +588,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, ...@@ -589,7 +588,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
} }
EXPORT_SYMBOL_GPL(mmc_switch); EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_send_tuning(struct mmc_host *host) int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error)
{ {
struct mmc_request mrq = {NULL}; struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
...@@ -599,16 +598,13 @@ int mmc_send_tuning(struct mmc_host *host) ...@@ -599,16 +598,13 @@ int mmc_send_tuning(struct mmc_host *host)
const u8 *tuning_block_pattern; const u8 *tuning_block_pattern;
int size, err = 0; int size, err = 0;
u8 *data_buf; u8 *data_buf;
u32 opcode;
if (ios->bus_width == MMC_BUS_WIDTH_8) { if (ios->bus_width == MMC_BUS_WIDTH_8) {
tuning_block_pattern = tuning_blk_pattern_8bit; tuning_block_pattern = tuning_blk_pattern_8bit;
size = sizeof(tuning_blk_pattern_8bit); size = sizeof(tuning_blk_pattern_8bit);
opcode = MMC_SEND_TUNING_BLOCK_HS200;
} else if (ios->bus_width == MMC_BUS_WIDTH_4) { } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
tuning_block_pattern = tuning_blk_pattern_4bit; tuning_block_pattern = tuning_blk_pattern_4bit;
size = sizeof(tuning_blk_pattern_4bit); size = sizeof(tuning_blk_pattern_4bit);
opcode = MMC_SEND_TUNING_BLOCK;
} else } else
return -EINVAL; return -EINVAL;
...@@ -639,6 +635,9 @@ int mmc_send_tuning(struct mmc_host *host) ...@@ -639,6 +635,9 @@ int mmc_send_tuning(struct mmc_host *host)
mmc_wait_for_req(host, &mrq); mmc_wait_for_req(host, &mrq);
if (cmd_error)
*cmd_error = cmd.error;
if (cmd.error) { if (cmd.error) {
err = cmd.error; err = cmd.error;
goto out; goto out;
......
...@@ -28,6 +28,9 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width); ...@@ -28,6 +28,9 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
int mmc_can_ext_csd(struct mmc_card *card); int mmc_can_ext_csd(struct mmc_card *card);
int mmc_switch_status_error(struct mmc_host *host, u32 status); int mmc_switch_status_error(struct mmc_host *host, u32 status);
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, bool use_busy_signal, bool send_status,
bool ignore_crc);
#endif #endif
...@@ -76,7 +76,7 @@ struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host, ...@@ -76,7 +76,7 @@ struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
if (!pwrseq) if (!pwrseq)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW); pwrseq->reset_gpio = gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(pwrseq->reset_gpio)) { if (IS_ERR(pwrseq->reset_gpio)) {
ret = PTR_ERR(pwrseq->reset_gpio); ret = PTR_ERR(pwrseq->reset_gpio);
goto free; goto free;
...@@ -84,11 +84,11 @@ struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host, ...@@ -84,11 +84,11 @@ struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
/* /*
* register reset handler to ensure emmc reset also from * register reset handler to ensure emmc reset also from
* emergency_reboot(), priority 129 schedules it just before * emergency_reboot(), priority 255 is the highest priority
* system reboot * so it will be executed before any system reboot handler.
*/ */
pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb;
pwrseq->reset_nb.priority = 129; pwrseq->reset_nb.priority = 255;
register_restart_handler(&pwrseq->reset_nb); register_restart_handler(&pwrseq->reset_nb);
pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
......
...@@ -23,18 +23,21 @@ struct mmc_pwrseq_simple { ...@@ -23,18 +23,21 @@ struct mmc_pwrseq_simple {
struct mmc_pwrseq pwrseq; struct mmc_pwrseq pwrseq;
bool clk_enabled; bool clk_enabled;
struct clk *ext_clk; struct clk *ext_clk;
int nr_gpios; struct gpio_descs *reset_gpios;
struct gpio_desc *reset_gpios[0];
}; };
static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
int value) int value)
{ {
int i; int i;
struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
int values[reset_gpios->ndescs];
for (i = 0; i < pwrseq->nr_gpios; i++) for (i = 0; i < reset_gpios->ndescs; i++)
if (!IS_ERR(pwrseq->reset_gpios[i])) values[i] = value;
gpiod_set_value_cansleep(pwrseq->reset_gpios[i], value);
gpiod_set_array_value_cansleep(reset_gpios->ndescs, reset_gpios->desc,
values);
} }
static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host) static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
...@@ -75,11 +78,8 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host) ...@@ -75,11 +78,8 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)
{ {
struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
struct mmc_pwrseq_simple, pwrseq); struct mmc_pwrseq_simple, pwrseq);
int i;
for (i = 0; i < pwrseq->nr_gpios; i++) gpiod_put_array(pwrseq->reset_gpios);
if (!IS_ERR(pwrseq->reset_gpios[i]))
gpiod_put(pwrseq->reset_gpios[i]);
if (!IS_ERR(pwrseq->ext_clk)) if (!IS_ERR(pwrseq->ext_clk))
clk_put(pwrseq->ext_clk); clk_put(pwrseq->ext_clk);
...@@ -98,14 +98,9 @@ struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host, ...@@ -98,14 +98,9 @@ struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
struct device *dev) struct device *dev)
{ {
struct mmc_pwrseq_simple *pwrseq; struct mmc_pwrseq_simple *pwrseq;
int i, nr_gpios, ret = 0; int ret = 0;
nr_gpios = of_gpio_named_count(dev->of_node, "reset-gpios");
if (nr_gpios < 0)
nr_gpios = 0;
pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios * pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
sizeof(struct gpio_desc *), GFP_KERNEL);
if (!pwrseq) if (!pwrseq)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -116,22 +111,12 @@ struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host, ...@@ -116,22 +111,12 @@ struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
goto free; goto free;
} }
for (i = 0; i < nr_gpios; i++) { pwrseq->reset_gpios = gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
pwrseq->reset_gpios[i] = gpiod_get_index(dev, "reset", i, if (IS_ERR(pwrseq->reset_gpios)) {
GPIOD_OUT_HIGH); ret = PTR_ERR(pwrseq->reset_gpios);
if (IS_ERR(pwrseq->reset_gpios[i]) && goto clk_put;
PTR_ERR(pwrseq->reset_gpios[i]) != -ENOENT &&
PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) {
ret = PTR_ERR(pwrseq->reset_gpios[i]);
while (i--)
gpiod_put(pwrseq->reset_gpios[i]);
goto clk_put;
}
} }
pwrseq->nr_gpios = nr_gpios;
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops; pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
return &pwrseq->pwrseq; return &pwrseq->pwrseq;
......
...@@ -35,25 +35,7 @@ ...@@ -35,25 +35,7 @@
#define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128 #define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128
#endif #endif
/*
* This hook just adds a quirk for all sdio devices
*/
static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
{
if (mmc_card_sdio(card))
card->quirks |= data;
}
static const struct mmc_fixup mmc_fixup_methods[] = { static const struct mmc_fixup mmc_fixup_methods[] = {
/* by default sdio devices are considered CLK_GATING broken */
/* good cards will be whitelisted as they are tested */
SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
add_quirk_for_sdio_devices,
MMC_QUIRK_BROKEN_CLK_GATING),
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
......
...@@ -357,8 +357,6 @@ int mmc_sd_switch_hs(struct mmc_card *card) ...@@ -357,8 +357,6 @@ int mmc_sd_switch_hs(struct mmc_card *card)
if (card->sw_caps.hs_max_dtr == 0) if (card->sw_caps.hs_max_dtr == 0)
return 0; return 0;
err = -EIO;
status = kmalloc(64, GFP_KERNEL); status = kmalloc(64, GFP_KERNEL);
if (!status) { if (!status) {
pr_err("%s: could not allocate a buffer for " pr_err("%s: could not allocate a buffer for "
...@@ -628,9 +626,25 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) ...@@ -628,9 +626,25 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
* SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
*/ */
if (!mmc_host_is_spi(card->host) && if (!mmc_host_is_spi(card->host) &&
(card->sd_bus_speed == UHS_SDR50_BUS_SPEED || (card->sd_bus_speed == UHS_SDR50_BUS_SPEED ||
card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) card->sd_bus_speed == UHS_DDR50_BUS_SPEED ||
card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) {
err = mmc_execute_tuning(card); err = mmc_execute_tuning(card);
/*
* As SD Specifications Part1 Physical Layer Specification
* Version 3.01 says, CMD19 tuning is available for unlocked
* cards in transfer state of 1.8V signaling mode. The small
* difference between v3.00 and 3.01 spec means that CMD19
* tuning is also available for DDR50 mode.
*/
if (err && card->sd_bus_speed == UHS_DDR50_BUS_SPEED) {
pr_warn("%s: ddr50 tuning failed\n",
mmc_hostname(card->host));
err = 0;
}
}
out: out:
kfree(status); kfree(status);
...@@ -786,9 +800,7 @@ static int mmc_sd_get_ro(struct mmc_host *host) ...@@ -786,9 +800,7 @@ static int mmc_sd_get_ro(struct mmc_host *host)
if (!host->ops->get_ro) if (!host->ops->get_ro)
return -1; return -1;
mmc_host_clk_hold(host);
ro = host->ops->get_ro(host); ro = host->ops->get_ro(host);
mmc_host_clk_release(host);
return ro; return ro;
} }
...@@ -1231,14 +1243,13 @@ int mmc_attach_sd(struct mmc_host *host) ...@@ -1231,14 +1243,13 @@ int mmc_attach_sd(struct mmc_host *host)
mmc_release_host(host); mmc_release_host(host);
err = mmc_add_card(host->card); err = mmc_add_card(host->card);
mmc_claim_host(host);
if (err) if (err)
goto remove_card; goto remove_card;
mmc_claim_host(host);
return 0; return 0;
remove_card: remove_card:
mmc_release_host(host);
mmc_remove_card(host->card); mmc_remove_card(host->card);
host->card = NULL; host->card = NULL;
mmc_claim_host(host); mmc_claim_host(host);
......
...@@ -897,11 +897,10 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host) ...@@ -897,11 +897,10 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host)
*/ */
static int mmc_sdio_suspend(struct mmc_host *host) static int mmc_sdio_suspend(struct mmc_host *host)
{ {
if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { mmc_claim_host(host);
mmc_claim_host(host);
if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host))
sdio_disable_wide(host->card); sdio_disable_wide(host->card);
mmc_release_host(host);
}
if (!mmc_card_keep_power(host)) { if (!mmc_card_keep_power(host)) {
mmc_power_off(host); mmc_power_off(host);
...@@ -910,6 +909,8 @@ static int mmc_sdio_suspend(struct mmc_host *host) ...@@ -910,6 +909,8 @@ static int mmc_sdio_suspend(struct mmc_host *host)
mmc_retune_needed(host); mmc_retune_needed(host);
} }
mmc_release_host(host);
return 0; return 0;
} }
...@@ -955,13 +956,10 @@ static int mmc_sdio_resume(struct mmc_host *host) ...@@ -955,13 +956,10 @@ static int mmc_sdio_resume(struct mmc_host *host)
} }
if (!err && host->sdio_irqs) { if (!err && host->sdio_irqs) {
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) { if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
wake_up_process(host->sdio_irq_thread); wake_up_process(host->sdio_irq_thread);
} else if (host->caps & MMC_CAP_SDIO_IRQ) { else if (host->caps & MMC_CAP_SDIO_IRQ)
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1); host->ops->enable_sdio_irq(host, 1);
mmc_host_clk_release(host);
}
} }
mmc_release_host(host); mmc_release_host(host);
...@@ -1018,15 +1016,24 @@ static int mmc_sdio_power_restore(struct mmc_host *host) ...@@ -1018,15 +1016,24 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
static int mmc_sdio_runtime_suspend(struct mmc_host *host) static int mmc_sdio_runtime_suspend(struct mmc_host *host)
{ {
/* No references to the card, cut the power to it. */ /* No references to the card, cut the power to it. */
mmc_claim_host(host);
mmc_power_off(host); mmc_power_off(host);
mmc_release_host(host);
return 0; return 0;
} }
static int mmc_sdio_runtime_resume(struct mmc_host *host) static int mmc_sdio_runtime_resume(struct mmc_host *host)
{ {
int ret;
/* Restore power and re-initialize. */ /* Restore power and re-initialize. */
mmc_claim_host(host);
mmc_power_up(host, host->card->ocr); mmc_power_up(host, host->card->ocr);
return mmc_sdio_power_restore(host); ret = mmc_sdio_power_restore(host);
mmc_release_host(host);
return ret;
} }
static int mmc_sdio_reset(struct mmc_host *host) static int mmc_sdio_reset(struct mmc_host *host)
......
...@@ -168,21 +168,15 @@ static int sdio_irq_thread(void *_host) ...@@ -168,21 +168,15 @@ static int sdio_irq_thread(void *_host)
} }
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (host->caps & MMC_CAP_SDIO_IRQ) { if (host->caps & MMC_CAP_SDIO_IRQ)
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1); host->ops->enable_sdio_irq(host, 1);
mmc_host_clk_release(host);
}
if (!kthread_should_stop()) if (!kthread_should_stop())
schedule_timeout(period); schedule_timeout(period);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
} while (!kthread_should_stop()); } while (!kthread_should_stop());
if (host->caps & MMC_CAP_SDIO_IRQ) { if (host->caps & MMC_CAP_SDIO_IRQ)
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 0); host->ops->enable_sdio_irq(host, 0);
mmc_host_clk_release(host);
}
pr_debug("%s: IRQ thread exiting with code %d\n", pr_debug("%s: IRQ thread exiting with code %d\n",
mmc_hostname(host), ret); mmc_hostname(host), ret);
...@@ -208,9 +202,7 @@ static int sdio_card_irq_get(struct mmc_card *card) ...@@ -208,9 +202,7 @@ static int sdio_card_irq_get(struct mmc_card *card)
return err; return err;
} }
} else if (host->caps & MMC_CAP_SDIO_IRQ) { } else if (host->caps & MMC_CAP_SDIO_IRQ) {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1); host->ops->enable_sdio_irq(host, 1);
mmc_host_clk_release(host);
} }
} }
...@@ -229,9 +221,7 @@ static int sdio_card_irq_put(struct mmc_card *card) ...@@ -229,9 +221,7 @@ static int sdio_card_irq_put(struct mmc_card *card)
atomic_set(&host->sdio_irq_thread_abort, 1); atomic_set(&host->sdio_irq_thread_abort, 1);
kthread_stop(host->sdio_irq_thread); kthread_stop(host->sdio_irq_thread);
} else if (host->caps & MMC_CAP_SDIO_IRQ) { } else if (host->caps & MMC_CAP_SDIO_IRQ) {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 0); host->ops->enable_sdio_irq(host, 0);
mmc_host_clk_release(host);
} }
} }
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#ifndef _MMC_SDIO_OPS_H #ifndef _MMC_SDIO_OPS_H
#define _MMC_SDIO_OPS_H #define _MMC_SDIO_OPS_H
#include <linux/mmc/sdio.h>
int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
unsigned addr, u8 in, u8* out); unsigned addr, u8 in, u8* out);
...@@ -19,5 +21,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, ...@@ -19,5 +21,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
int sdio_reset(struct mmc_host *host); int sdio_reset(struct mmc_host *host);
static inline bool mmc_is_io_op(u32 opcode)
{
return opcode == SD_IO_RW_DIRECT || opcode == SD_IO_RW_EXTENDED;
}
#endif #endif
...@@ -67,7 +67,7 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER ...@@ -67,7 +67,7 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
has the effect of scrambling the addresses and formats of data has the effect of scrambling the addresses and formats of data
accessed in sizes other than the datum size. accessed in sizes other than the datum size.
This is the case for the Freescale eSDHC and Nintendo Wii SDHCI. This is the case for the Nintendo Wii SDHCI.
config MMC_SDHCI_PCI config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus" tristate "SDHCI support on PCI bus"
...@@ -140,8 +140,8 @@ config MMC_SDHCI_OF_AT91 ...@@ -140,8 +140,8 @@ config MMC_SDHCI_OF_AT91
config MMC_SDHCI_OF_ESDHC config MMC_SDHCI_OF_ESDHC
tristate "SDHCI OF support for the Freescale eSDHC controller" tristate "SDHCI OF support for the Freescale eSDHC controller"
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
depends on PPC depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE
select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER select MMC_SDHCI_IO_ACCESSORS
help help
This selects the Freescale eSDHC controller support. This selects the Freescale eSDHC controller support.
...@@ -366,7 +366,7 @@ config MMC_OMAP ...@@ -366,7 +366,7 @@ config MMC_OMAP
config MMC_OMAP_HS config MMC_OMAP_HS
tristate "TI OMAP High Speed Multimedia Card Interface support" tristate "TI OMAP High Speed Multimedia Card Interface support"
depends on HAS_DMA depends on HAS_DMA
depends on ARCH_OMAP2PLUS || COMPILE_TEST depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST
help help
This selects the TI OMAP High Speed Multimedia card Interface. This selects the TI OMAP High Speed Multimedia card Interface.
If you have an omap2plus board with a Multimedia Card slot, If you have an omap2plus board with a Multimedia Card slot,
...@@ -473,7 +473,7 @@ config MMC_DAVINCI ...@@ -473,7 +473,7 @@ config MMC_DAVINCI
config MMC_GOLDFISH config MMC_GOLDFISH
tristate "goldfish qemu Multimedia Card Interface support" tristate "goldfish qemu Multimedia Card Interface support"
depends on GOLDFISH depends on GOLDFISH || COMPILE_TEST
help help
This selects the Goldfish Multimedia card Interface emulation This selects the Goldfish Multimedia card Interface emulation
found on the Goldfish Android virtual device emulation. found on the Goldfish Android virtual device emulation.
...@@ -615,15 +615,7 @@ config MMC_DW ...@@ -615,15 +615,7 @@ config MMC_DW
help help
This selects support for the Synopsys DesignWare Mobile Storage IP This selects support for the Synopsys DesignWare Mobile Storage IP
block, this provides host support for SD and MMC interfaces, in both block, this provides host support for SD and MMC interfaces, in both
PIO and external DMA modes. PIO, internal DMA mode and external DMA mode.
config MMC_DW_IDMAC
bool "Internal DMAC interface"
depends on MMC_DW
help
This selects support for the internal DMAC block within the Synopsys
Designware Mobile Storage IP block. This disables the external DMA
interface.
config MMC_DW_PLTFM config MMC_DW_PLTFM
tristate "Synopsys Designware MCI Support as platform device" tristate "Synopsys Designware MCI Support as platform device"
...@@ -652,7 +644,6 @@ config MMC_DW_K3 ...@@ -652,7 +644,6 @@ config MMC_DW_K3
tristate "K3 specific extensions for Synopsys DW Memory Card Interface" tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
depends on MMC_DW depends on MMC_DW
select MMC_DW_PLTFM select MMC_DW_PLTFM
select MMC_DW_IDMAC
help help
This selects support for Hisilicon K3 SoC specific extensions to the This selects support for Hisilicon K3 SoC specific extensions to the
Synopsys DesignWare Memory Card Interface driver. Select this option Synopsys DesignWare Memory Card Interface driver. Select this option
......
...@@ -9,8 +9,8 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o ...@@ -9,8 +9,8 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-o2micro.o
obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o
......
...@@ -446,7 +446,7 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates) ...@@ -446,7 +446,7 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates)
return loc; return loc;
} }
static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot) static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
{ {
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv = host->priv;
...@@ -461,7 +461,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot) ...@@ -461,7 +461,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
mci_writel(host, TMOUT, ~0); mci_writel(host, TMOUT, ~0);
smpl = dw_mci_exynos_move_next_clksmpl(host); smpl = dw_mci_exynos_move_next_clksmpl(host);
if (!mmc_send_tuning(mmc)) if (!mmc_send_tuning(mmc, opcode, NULL))
candiates |= (1 << smpl); candiates |= (1 << smpl);
} while (start_smpl != smpl); } while (start_smpl != smpl);
......
...@@ -59,6 +59,8 @@ int dw_mci_pltfm_register(struct platform_device *pdev, ...@@ -59,6 +59,8 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
host->pdata = pdev->dev.platform_data; host->pdata = pdev->dev.platform_data;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/* Get registers' physical base address */
host->phy_regs = (void *)(regs->start);
host->regs = devm_ioremap_resource(&pdev->dev, regs); host->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(host->regs)) if (IS_ERR(host->regs))
return PTR_ERR(host->regs); return PTR_ERR(host->regs);
......
...@@ -13,12 +13,19 @@ ...@@ -13,12 +13,19 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/dw_mmc.h> #include <linux/mmc/dw_mmc.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/slab.h>
#include "dw_mmc.h" #include "dw_mmc.h"
#include "dw_mmc-pltfm.h" #include "dw_mmc-pltfm.h"
#define RK3288_CLKGEN_DIV 2 #define RK3288_CLKGEN_DIV 2
struct dw_mci_rockchip_priv_data {
struct clk *drv_clk;
struct clk *sample_clk;
int default_sample_phase;
};
static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr) static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
{ {
*cmdr |= SDMMC_CMD_USE_HOLD_REG; *cmdr |= SDMMC_CMD_USE_HOLD_REG;
...@@ -33,6 +40,7 @@ static int dw_mci_rk3288_setup_clock(struct dw_mci *host) ...@@ -33,6 +40,7 @@ static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{ {
struct dw_mci_rockchip_priv_data *priv = host->priv;
int ret; int ret;
unsigned int cclkin; unsigned int cclkin;
u32 bus_hz; u32 bus_hz;
...@@ -66,6 +74,158 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) ...@@ -66,6 +74,158 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
/* force dw_mci_setup_bus() */ /* force dw_mci_setup_bus() */
host->current_speed = 0; host->current_speed = 0;
} }
/* Make sure we use phases which we can enumerate with */
if (!IS_ERR(priv->sample_clk))
clk_set_phase(priv->sample_clk, priv->default_sample_phase);
}
#define NUM_PHASES 360
#define TUNING_ITERATION_TO_PHASE(i) (DIV_ROUND_UP((i) * 360, NUM_PHASES))
static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
{
struct dw_mci *host = slot->host;
struct dw_mci_rockchip_priv_data *priv = host->priv;
struct mmc_host *mmc = slot->mmc;
int ret = 0;
int i;
bool v, prev_v = 0, first_v;
struct range_t {
int start;
int end; /* inclusive */
};
struct range_t *ranges;
unsigned int range_count = 0;
int longest_range_len = -1;
int longest_range = -1;
int middle_phase;
if (IS_ERR(priv->sample_clk)) {
dev_err(host->dev, "Tuning clock (sample_clk) not defined.\n");
return -EIO;
}
ranges = kmalloc_array(NUM_PHASES / 2 + 1, sizeof(*ranges), GFP_KERNEL);
if (!ranges)
return -ENOMEM;
/* Try each phase and extract good ranges */
for (i = 0; i < NUM_PHASES; ) {
clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(i));
v = !mmc_send_tuning(mmc, opcode, NULL);
if (i == 0)
first_v = v;
if ((!prev_v) && v) {
range_count++;
ranges[range_count-1].start = i;
}
if (v) {
ranges[range_count-1].end = i;
i++;
} else if (i == NUM_PHASES - 1) {
/* No extra skipping rules if we're at the end */
i++;
} else {
/*
* No need to check too close to an invalid
* one since testing bad phases is slow. Skip
* 20 degrees.
*/
i += DIV_ROUND_UP(20 * NUM_PHASES, 360);
/* Always test the last one */
if (i >= NUM_PHASES)
i = NUM_PHASES - 1;
}
prev_v = v;
}
if (range_count == 0) {
dev_warn(host->dev, "All phases bad!");
ret = -EIO;
goto free;
}
/* wrap around case, merge the end points */
if ((range_count > 1) && first_v && v) {
ranges[0].start = ranges[range_count-1].start;
range_count--;
}
if (ranges[0].start == 0 && ranges[0].end == NUM_PHASES - 1) {
clk_set_phase(priv->sample_clk, priv->default_sample_phase);
dev_info(host->dev, "All phases work, using default phase %d.",
priv->default_sample_phase);
goto free;
}
/* Find the longest range */
for (i = 0; i < range_count; i++) {
int len = (ranges[i].end - ranges[i].start + 1);
if (len < 0)
len += NUM_PHASES;
if (longest_range_len < len) {
longest_range_len = len;
longest_range = i;
}
dev_dbg(host->dev, "Good phase range %d-%d (%d len)\n",
TUNING_ITERATION_TO_PHASE(ranges[i].start),
TUNING_ITERATION_TO_PHASE(ranges[i].end),
len
);
}
dev_dbg(host->dev, "Best phase range %d-%d (%d len)\n",
TUNING_ITERATION_TO_PHASE(ranges[longest_range].start),
TUNING_ITERATION_TO_PHASE(ranges[longest_range].end),
longest_range_len
);
middle_phase = ranges[longest_range].start + longest_range_len / 2;
middle_phase %= NUM_PHASES;
dev_info(host->dev, "Successfully tuned phase to %d\n",
TUNING_ITERATION_TO_PHASE(middle_phase));
clk_set_phase(priv->sample_clk,
TUNING_ITERATION_TO_PHASE(middle_phase));
free:
kfree(ranges);
return ret;
}
static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
{
struct device_node *np = host->dev->of_node;
struct dw_mci_rockchip_priv_data *priv;
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
if (of_property_read_u32(np, "rockchip,default-sample-phase",
&priv->default_sample_phase))
priv->default_sample_phase = 0;
priv->drv_clk = devm_clk_get(host->dev, "ciu-drive");
if (IS_ERR(priv->drv_clk))
dev_dbg(host->dev, "ciu_drv not available\n");
priv->sample_clk = devm_clk_get(host->dev, "ciu-sample");
if (IS_ERR(priv->sample_clk))
dev_dbg(host->dev, "ciu_sample not available\n");
host->priv = priv;
return 0;
} }
static int dw_mci_rockchip_init(struct dw_mci *host) static int dw_mci_rockchip_init(struct dw_mci *host)
...@@ -95,6 +255,8 @@ static const struct dw_mci_drv_data rk3288_drv_data = { ...@@ -95,6 +255,8 @@ static const struct dw_mci_drv_data rk3288_drv_data = {
.caps = dw_mci_rk3288_dwmmc_caps, .caps = dw_mci_rk3288_dwmmc_caps,
.prepare_command = dw_mci_rockchip_prepare_command, .prepare_command = dw_mci_rockchip_prepare_command,
.set_ios = dw_mci_rk3288_set_ios, .set_ios = dw_mci_rk3288_set_ios,
.execute_tuning = dw_mci_rk3288_execute_tuning,
.parse_dt = dw_mci_rk3288_parse_dt,
.setup_clock = dw_mci_rk3288_setup_clock, .setup_clock = dw_mci_rk3288_setup_clock,
.init = dw_mci_rockchip_init, .init = dw_mci_rockchip_init,
}; };
......
This diff is collapsed.
...@@ -148,6 +148,15 @@ ...@@ -148,6 +148,15 @@
#define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \
((r) & 0xFFF) << 16 | \ ((r) & 0xFFF) << 16 | \
((t) & 0xFFF)) ((t) & 0xFFF))
/* HCON register defines */
#define DMA_INTERFACE_IDMA (0x0)
#define DMA_INTERFACE_DWDMA (0x1)
#define DMA_INTERFACE_GDMA (0x2)
#define DMA_INTERFACE_NODMA (0x3)
#define SDMMC_GET_TRANS_MODE(x) (((x)>>16) & 0x3)
#define SDMMC_GET_SLOT_NUM(x) ((((x)>>1) & 0x1F) + 1)
#define SDMMC_GET_HDATA_WIDTH(x) (((x)>>7) & 0x7)
#define SDMMC_GET_ADDR_CONFIG(x) (((x)>>27) & 0x1)
/* Internal DMAC interrupt defines */ /* Internal DMAC interrupt defines */
#define SDMMC_IDMAC_INT_AI BIT(9) #define SDMMC_IDMAC_INT_AI BIT(9)
#define SDMMC_IDMAC_INT_NI BIT(8) #define SDMMC_IDMAC_INT_NI BIT(8)
...@@ -163,7 +172,7 @@ ...@@ -163,7 +172,7 @@
/* Version ID register define */ /* Version ID register define */
#define SDMMC_GET_VERID(x) ((x) & 0xFFFF) #define SDMMC_GET_VERID(x) ((x) & 0xFFFF)
/* Card read threshold */ /* Card read threshold */
#define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) #define SDMMC_SET_RD_THLD(v, x) (((v) & 0xFFF) << 16 | (x))
#define SDMMC_UHS_18V BIT(0) #define SDMMC_UHS_18V BIT(0)
/* All ctrl reset bits */ /* All ctrl reset bits */
#define SDMMC_CTRL_ALL_RESET_FLAGS \ #define SDMMC_CTRL_ALL_RESET_FLAGS \
...@@ -281,7 +290,7 @@ struct dw_mci_drv_data { ...@@ -281,7 +290,7 @@ struct dw_mci_drv_data {
void (*prepare_command)(struct dw_mci *host, u32 *cmdr); void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host); int (*parse_dt)(struct dw_mci *host);
int (*execute_tuning)(struct dw_mci_slot *slot); int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode);
int (*prepare_hs400_tuning)(struct dw_mci *host, int (*prepare_hs400_tuning)(struct dw_mci *host,
struct mmc_ios *ios); struct mmc_ios *ios);
int (*switch_voltage)(struct mmc_host *mmc, int (*switch_voltage)(struct mmc_host *mmc,
......
...@@ -1511,6 +1511,7 @@ static const struct of_device_id mmc_spi_of_match_table[] = { ...@@ -1511,6 +1511,7 @@ static const struct of_device_id mmc_spi_of_match_table[] = {
{ .compatible = "mmc-spi-slot", }, { .compatible = "mmc-spi-slot", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, mmc_spi_of_match_table);
static struct spi_driver mmc_spi_driver = { static struct spi_driver mmc_spi_driver = {
.driver = { .driver = {
......
...@@ -711,6 +711,7 @@ static const struct of_device_id moxart_mmc_match[] = { ...@@ -711,6 +711,7 @@ static const struct of_device_id moxart_mmc_match[] = {
{ .compatible = "faraday,ftsdc010" }, { .compatible = "faraday,ftsdc010" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, moxart_mmc_match);
static struct platform_driver moxart_mmc_driver = { static struct platform_driver moxart_mmc_driver = {
.probe = moxart_probe, .probe = moxart_probe,
......
This diff is collapsed.
...@@ -1490,6 +1490,7 @@ static const struct of_device_id mmc_omap_match[] = { ...@@ -1490,6 +1490,7 @@ static const struct of_device_id mmc_omap_match[] = {
{ .compatible = "ti,omap2420-mmc", }, { .compatible = "ti,omap2420-mmc", },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, mmc_omap_match);
#endif #endif
static struct platform_driver mmc_omap_driver = { static struct platform_driver mmc_omap_driver = {
......
...@@ -207,7 +207,9 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = { ...@@ -207,7 +207,9 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
.caps2 = MMC_CAP2_HC_ERASE_SZ, .caps2 = MMC_CAP2_HC_ERASE_SZ,
.flags = SDHCI_ACPI_RUNTIME_PM, .flags = SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC |
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
.probe_slot = sdhci_acpi_emmc_probe_slot, .probe_slot = sdhci_acpi_emmc_probe_slot,
}; };
...@@ -239,6 +241,9 @@ struct sdhci_acpi_uid_slot { ...@@ -239,6 +241,9 @@ struct sdhci_acpi_uid_slot {
}; };
static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
{ "80865ACA", NULL, &sdhci_acpi_slot_int_sd },
{ "80865ACC", NULL, &sdhci_acpi_slot_int_emmc },
{ "80865AD0", NULL, &sdhci_acpi_slot_int_sdio },
{ "80860F14" , "1" , &sdhci_acpi_slot_int_emmc }, { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
{ "80860F14" , "3" , &sdhci_acpi_slot_int_sd }, { "80860F14" , "3" , &sdhci_acpi_slot_int_sd },
{ "80860F16" , NULL, &sdhci_acpi_slot_int_sd }, { "80860F16" , NULL, &sdhci_acpi_slot_int_sd },
...@@ -247,11 +252,15 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { ...@@ -247,11 +252,15 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
{ "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio }, { "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio },
{ "INT3436" , NULL, &sdhci_acpi_slot_int_sdio }, { "INT3436" , NULL, &sdhci_acpi_slot_int_sdio },
{ "INT344D" , NULL, &sdhci_acpi_slot_int_sdio }, { "INT344D" , NULL, &sdhci_acpi_slot_int_sdio },
{ "PNP0FFF" , "3" , &sdhci_acpi_slot_int_sd },
{ "PNP0D40" }, { "PNP0D40" },
{ }, { },
}; };
static const struct acpi_device_id sdhci_acpi_ids[] = { static const struct acpi_device_id sdhci_acpi_ids[] = {
{ "80865ACA" },
{ "80865ACC" },
{ "80865AD0" },
{ "80860F14" }, { "80860F14" },
{ "80860F16" }, { "80860F16" },
{ "INT33BB" }, { "INT33BB" },
......
...@@ -273,7 +273,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) ...@@ -273,7 +273,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
dev_dbg(dev, "is_8bit=%c\n", dev_dbg(dev, "is_8bit=%c\n",
(host->mmc->caps | MMC_CAP_8_BIT_DATA) ? 'Y' : 'N'); (host->mmc->caps & MMC_CAP_8_BIT_DATA) ? 'Y' : 'N');
ret = sdhci_bcm_kona_sd_reset(host); ret = sdhci_bcm_kona_sd_reset(host);
if (ret) if (ret)
......
...@@ -759,7 +759,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) ...@@ -759,7 +759,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
min = ESDHC_TUNE_CTRL_MIN; min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) { while (min < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, min); esdhc_prepare_tuning(host, min);
if (!mmc_send_tuning(host->mmc)) if (!mmc_send_tuning(host->mmc, opcode, NULL))
break; break;
min += ESDHC_TUNE_CTRL_STEP; min += ESDHC_TUNE_CTRL_STEP;
} }
...@@ -768,7 +768,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) ...@@ -768,7 +768,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
max = min + ESDHC_TUNE_CTRL_STEP; max = min + ESDHC_TUNE_CTRL_STEP;
while (max < ESDHC_TUNE_CTRL_MAX) { while (max < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, max); esdhc_prepare_tuning(host, max);
if (mmc_send_tuning(host->mmc)) { if (mmc_send_tuning(host->mmc, opcode, NULL)) {
max -= ESDHC_TUNE_CTRL_STEP; max -= ESDHC_TUNE_CTRL_STEP;
break; break;
} }
...@@ -778,7 +778,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) ...@@ -778,7 +778,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
/* use average delay to get the best timing */ /* use average delay to get the best timing */
avg = (min + max) / 2; avg = (min + max) / 2;
esdhc_prepare_tuning(host, avg); esdhc_prepare_tuning(host, avg);
ret = mmc_send_tuning(host->mmc); ret = mmc_send_tuning(host->mmc, opcode, NULL);
esdhc_post_tuning(host); esdhc_post_tuning(host);
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n", dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
SDHCI_QUIRK_PIO_NEEDS_DELAY | \ SDHCI_QUIRK_PIO_NEEDS_DELAY | \
SDHCI_QUIRK_NO_HISPD_BIT) SDHCI_QUIRK_NO_HISPD_BIT)
#define ESDHC_PROCTL 0x28
#define ESDHC_SYSTEM_CONTROL 0x2c #define ESDHC_SYSTEM_CONTROL 0x2c
#define ESDHC_CLOCK_MASK 0x0000fff0 #define ESDHC_CLOCK_MASK 0x0000fff0
#define ESDHC_PREDIV_SHIFT 8 #define ESDHC_PREDIV_SHIFT 8
......
...@@ -373,7 +373,7 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) ...@@ -373,7 +373,7 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
if (rc) if (rc)
return rc; return rc;
rc = mmc_send_tuning(mmc); rc = mmc_send_tuning(mmc, opcode, NULL);
if (!rc) { if (!rc) {
/* Tuning is successful at this tuning point */ /* Tuning is successful at this tuning point */
tuned_phases[tuned_phase_cnt++] = phase; tuned_phases[tuned_phase_cnt++] = phase;
......
...@@ -111,7 +111,6 @@ static int sdhci_at91_probe(struct platform_device *pdev) ...@@ -111,7 +111,6 @@ static int sdhci_at91_probe(struct platform_device *pdev)
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "failed to set gck"); dev_err(&pdev->dev, "failed to set gck");
goto hclock_disable_unprepare; goto hclock_disable_unprepare;
return -EINVAL;
} }
/* /*
* We need to check if we have the requested rate for gck because in * We need to check if we have the requested rate for gck because in
......
This diff is collapsed.
...@@ -444,11 +444,7 @@ static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) ...@@ -444,11 +444,7 @@ static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
else else
scratch &= ~0x47; scratch &= ~0x47;
ret = pci_write_config_byte(chip->pdev, 0xAE, scratch); return pci_write_config_byte(chip->pdev, 0xAE, scratch);
if (ret)
return ret;
return 0;
} }
static int jmicron_probe(struct sdhci_pci_chip *chip) static int jmicron_probe(struct sdhci_pci_chip *chip)
...@@ -1112,6 +1108,62 @@ static const struct pci_device_id pci_ids[] = { ...@@ -1112,6 +1108,62 @@ static const struct pci_device_id pci_ids[] = {
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
}, },
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_DNV_EMMC,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BXT_EMMC,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BXT_SDIO,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BXT_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_APL_EMMC,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_APL_SDIO,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_APL_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
},
{ {
.vendor = PCI_VENDOR_ID_O2, .vendor = PCI_VENDOR_ID_O2,
.device = PCI_DEVICE_ID_O2_8120, .device = PCI_DEVICE_ID_O2_8120,
......
...@@ -60,7 +60,7 @@ static void o2_pci_led_enable(struct sdhci_pci_chip *chip) ...@@ -60,7 +60,7 @@ static void o2_pci_led_enable(struct sdhci_pci_chip *chip)
} }
void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
{ {
u32 scratch_32; u32 scratch_32;
int ret; int ret;
...@@ -145,7 +145,6 @@ void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) ...@@ -145,7 +145,6 @@ void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
scratch_32 |= 0x00080000; scratch_32 |= 0x00080000;
pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32); pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32);
} }
EXPORT_SYMBOL_GPL(sdhci_pci_o2_fujin2_pci_init);
int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
{ {
...@@ -179,7 +178,6 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) ...@@ -179,7 +178,6 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(sdhci_pci_o2_probe_slot);
int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
{ {
...@@ -385,11 +383,9 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) ...@@ -385,11 +383,9 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(sdhci_pci_o2_probe);
int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip)
{ {
sdhci_pci_o2_probe(chip); sdhci_pci_o2_probe(chip);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(sdhci_pci_o2_resume);
...@@ -64,8 +64,6 @@ ...@@ -64,8 +64,6 @@
#define O2_SD_VENDOR_SETTING 0x110 #define O2_SD_VENDOR_SETTING 0x110
#define O2_SD_VENDOR_SETTING2 0x1C8 #define O2_SD_VENDOR_SETTING2 0x1C8
extern void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip);
extern int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot); extern int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot);
extern int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip); extern int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip);
......
...@@ -24,6 +24,13 @@ ...@@ -24,6 +24,13 @@
#define PCI_DEVICE_ID_INTEL_SPT_EMMC 0x9d2b #define PCI_DEVICE_ID_INTEL_SPT_EMMC 0x9d2b
#define PCI_DEVICE_ID_INTEL_SPT_SDIO 0x9d2c #define PCI_DEVICE_ID_INTEL_SPT_SDIO 0x9d2c
#define PCI_DEVICE_ID_INTEL_SPT_SD 0x9d2d #define PCI_DEVICE_ID_INTEL_SPT_SD 0x9d2d
#define PCI_DEVICE_ID_INTEL_DNV_EMMC 0x19db
#define PCI_DEVICE_ID_INTEL_BXT_SD 0x0aca
#define PCI_DEVICE_ID_INTEL_BXT_EMMC 0x0acc
#define PCI_DEVICE_ID_INTEL_BXT_SDIO 0x0ad0
#define PCI_DEVICE_ID_INTEL_APL_SD 0x5aca
#define PCI_DEVICE_ID_INTEL_APL_EMMC 0x5acc
#define PCI_DEVICE_ID_INTEL_APL_SDIO 0x5ad0
/* /*
* PCI registers * PCI registers
......
...@@ -71,9 +71,7 @@ void sdhci_get_of_property(struct platform_device *pdev) ...@@ -71,9 +71,7 @@ void sdhci_get_of_property(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
const __be32 *clk;
u32 bus_width; u32 bus_width;
int size;
if (of_get_property(np, "sdhci,auto-cmd12", NULL)) if (of_get_property(np, "sdhci,auto-cmd12", NULL))
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
...@@ -101,9 +99,7 @@ void sdhci_get_of_property(struct platform_device *pdev) ...@@ -101,9 +99,7 @@ void sdhci_get_of_property(struct platform_device *pdev)
of_device_is_compatible(np, "fsl,mpc8536-esdhc")) of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
clk = of_get_property(np, "clock-frequency", &size); of_property_read_u32(np, "clock-frequency", &pltfm_host->clock);
if (clk && size == sizeof(*clk) && *clk)
pltfm_host->clock = be32_to_cpup(clk);
if (of_find_property(np, "keep-power-in-suspend", NULL)) if (of_find_property(np, "keep-power-in-suspend", NULL))
host->mmc->pm_caps |= MMC_PM_KEEP_POWER; host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
......
...@@ -50,7 +50,8 @@ static u32 sdhci_sirf_readl_le(struct sdhci_host *host, int reg) ...@@ -50,7 +50,8 @@ static u32 sdhci_sirf_readl_le(struct sdhci_host *host, int reg)
if (unlikely((reg == SDHCI_CAPABILITIES_1) && if (unlikely((reg == SDHCI_CAPABILITIES_1) &&
(host->mmc->caps & MMC_CAP_UHS_SDR50))) { (host->mmc->caps & MMC_CAP_UHS_SDR50))) {
/* fake CAP_1 register */ /* fake CAP_1 register */
val = SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING; val = SDHCI_SUPPORT_DDR50 |
SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING;
} }
if (unlikely(reg == SDHCI_SLOT_INT_STATUS)) { if (unlikely(reg == SDHCI_SLOT_INT_STATUS)) {
...@@ -97,7 +98,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) ...@@ -97,7 +98,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
clock_setting | phase, clock_setting | phase,
SDHCI_CLK_DELAY_SETTING); SDHCI_CLK_DELAY_SETTING);
if (!mmc_send_tuning(mmc)) { if (!mmc_send_tuning(mmc, opcode, NULL)) {
/* Tuning is successful at this tuning point */ /* Tuning is successful at this tuning point */
tuned_phase_cnt++; tuned_phase_cnt++;
dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
......
...@@ -1895,9 +1895,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -1895,9 +1895,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
tuning_count = host->tuning_count; tuning_count = host->tuning_count;
/* /*
* The Host Controller needs tuning only in case of SDR104 mode * The Host Controller needs tuning in case of SDR104 and DDR50
* and for SDR50 mode when Use Tuning for SDR50 is set in the * mode, and for SDR50 mode when Use Tuning for SDR50 is set in
* Capabilities register. * the Capabilities register.
* If the Host Controller supports the HS200 mode then the * If the Host Controller supports the HS200 mode then the
* tuning function has to be executed. * tuning function has to be executed.
*/ */
...@@ -1917,6 +1917,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -1917,6 +1917,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
break; break;
case MMC_TIMING_UHS_SDR104: case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_UHS_DDR50:
break; break;
case MMC_TIMING_UHS_SDR50: case MMC_TIMING_UHS_SDR50:
...@@ -2716,17 +2717,6 @@ int sdhci_resume_host(struct sdhci_host *host) ...@@ -2716,17 +2717,6 @@ int sdhci_resume_host(struct sdhci_host *host)
host->ops->enable_dma(host); host->ops->enable_dma(host);
} }
if (!device_may_wakeup(mmc_dev(host->mmc))) {
ret = request_threaded_irq(host->irq, sdhci_irq,
sdhci_thread_irq, IRQF_SHARED,
mmc_hostname(host->mmc), host);
if (ret)
return ret;
} else {
sdhci_disable_irq_wakeups(host);
disable_irq_wake(host->irq);
}
if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) && if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) &&
(host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) { (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) {
/* Card keeps power but host controller does not */ /* Card keeps power but host controller does not */
...@@ -2739,6 +2729,17 @@ int sdhci_resume_host(struct sdhci_host *host) ...@@ -2739,6 +2729,17 @@ int sdhci_resume_host(struct sdhci_host *host)
mmiowb(); mmiowb();
} }
if (!device_may_wakeup(mmc_dev(host->mmc))) {
ret = request_threaded_irq(host->irq, sdhci_irq,
sdhci_thread_irq, IRQF_SHARED,
mmc_hostname(host->mmc), host);
if (ret)
return ret;
} else {
sdhci_disable_irq_wakeups(host);
disable_irq_wake(host->irq);
}
sdhci_enable_card_detection(host); sdhci_enable_card_detection(host);
return ret; return ret;
......
...@@ -873,6 +873,13 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -873,6 +873,13 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
spin_unlock_irqrestore(&host->lock, iflags); spin_unlock_irqrestore(&host->lock, iflags);
} }
static int sunxi_mmc_card_busy(struct mmc_host *mmc)
{
struct sunxi_mmc_host *host = mmc_priv(mmc);
return !!(mmc_readl(host, REG_STAS) & SDXC_CARD_DATA_BUSY);
}
static const struct of_device_id sunxi_mmc_of_match[] = { static const struct of_device_id sunxi_mmc_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-mmc", }, { .compatible = "allwinner,sun4i-a10-mmc", },
{ .compatible = "allwinner,sun5i-a13-mmc", }, { .compatible = "allwinner,sun5i-a13-mmc", },
...@@ -888,6 +895,7 @@ static struct mmc_host_ops sunxi_mmc_ops = { ...@@ -888,6 +895,7 @@ static struct mmc_host_ops sunxi_mmc_ops = {
.get_cd = mmc_gpio_get_cd, .get_cd = mmc_gpio_get_cd,
.enable_sdio_irq = sunxi_mmc_enable_sdio_irq, .enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
.hw_reset = sunxi_mmc_hw_reset, .hw_reset = sunxi_mmc_hw_reset,
.card_busy = sunxi_mmc_card_busy,
}; };
static const struct sunxi_mmc_clk_delay sunxi_mmc_clk_delays[] = { static const struct sunxi_mmc_clk_delay sunxi_mmc_clk_delays[] = {
......
...@@ -563,7 +563,7 @@ static void add_offloaded_reg(struct vub300_mmc_host *vub300, ...@@ -563,7 +563,7 @@ static void add_offloaded_reg(struct vub300_mmc_host *vub300,
i += 1; i += 1;
continue; continue;
} }
}; }
__add_offloaded_reg_to_fifo(vub300, register_access, func); __add_offloaded_reg_to_fifo(vub300, register_access, func);
} }
...@@ -1372,7 +1372,7 @@ static void download_offload_pseudocode(struct vub300_mmc_host *vub300) ...@@ -1372,7 +1372,7 @@ static void download_offload_pseudocode(struct vub300_mmc_host *vub300)
l += snprintf(vub300->vub_name + l, l += snprintf(vub300->vub_name + l,
sizeof(vub300->vub_name) - l, "_%04X%04X", sizeof(vub300->vub_name) - l, "_%04X%04X",
sf->vendor, sf->device); sf->vendor, sf->device);
}; }
snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin"); snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin");
dev_info(&vub300->udev->dev, "requesting offload firmware %s\n", dev_info(&vub300->udev->dev, "requesting offload firmware %s\n",
vub300->vub_name); vub300->vub_name);
...@@ -1893,7 +1893,7 @@ static int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300, ...@@ -1893,7 +1893,7 @@ static int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300,
i += 1; i += 1;
continue; continue;
} }
}; }
if (vub300->total_offload_count == 0) if (vub300->total_offload_count == 0)
return 0; return 0;
else if (vub300->fn[func].offload_count == 0) else if (vub300->fn[func].offload_count == 0)
......
...@@ -809,7 +809,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -809,7 +809,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
cmd->error = -EINVAL; cmd->error = -EINVAL;
goto done; goto done;
}; }
} }
/* /*
......
...@@ -269,7 +269,6 @@ struct mmc_card { ...@@ -269,7 +269,6 @@ struct mmc_card {
/* for byte mode */ /* for byte mode */
#define MMC_QUIRK_NONSTD_SDIO (1<<2) /* non-standard SDIO card attached */ #define MMC_QUIRK_NONSTD_SDIO (1<<2) /* non-standard SDIO card attached */
/* (missing CIA registers) */ /* (missing CIA registers) */
#define MMC_QUIRK_BROKEN_CLK_GATING (1<<3) /* clock gating the sdio bus will make card fail */
#define MMC_QUIRK_NONSTD_FUNC_IF (1<<4) /* SDIO card has nonstd function interfaces */ #define MMC_QUIRK_NONSTD_FUNC_IF (1<<4) /* SDIO card has nonstd function interfaces */
#define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */ #define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */
#define MMC_QUIRK_INAND_CMD38 (1<<6) /* iNAND devices have broken CMD38 */ #define MMC_QUIRK_INAND_CMD38 (1<<6) /* iNAND devices have broken CMD38 */
......
...@@ -152,10 +152,8 @@ extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *); ...@@ -152,10 +152,8 @@ extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
struct mmc_command *, int); struct mmc_command *, int);
extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
bool, bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
extern int mmc_send_tuning(struct mmc_host *host); extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
#define MMC_ERASE_ARG 0x00000000 #define MMC_ERASE_ARG 0x00000000
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/mmc/core.h> #include <linux/mmc/core.h>
#include <linux/dmaengine.h>
#define MAX_MCI_SLOTS 2 #define MAX_MCI_SLOTS 2
...@@ -40,6 +41,17 @@ enum { ...@@ -40,6 +41,17 @@ enum {
struct mmc_data; struct mmc_data;
enum {
TRANS_MODE_PIO = 0,
TRANS_MODE_IDMAC,
TRANS_MODE_EDMAC
};
struct dw_mci_dma_slave {
struct dma_chan *ch;
enum dma_transfer_direction direction;
};
/** /**
* struct dw_mci - MMC controller state shared between all slots * struct dw_mci - MMC controller state shared between all slots
* @lock: Spinlock protecting the queue and associated data. * @lock: Spinlock protecting the queue and associated data.
...@@ -154,7 +166,14 @@ struct dw_mci { ...@@ -154,7 +166,14 @@ struct dw_mci {
dma_addr_t sg_dma; dma_addr_t sg_dma;
void *sg_cpu; void *sg_cpu;
const struct dw_mci_dma_ops *dma_ops; const struct dw_mci_dma_ops *dma_ops;
/* For idmac */
unsigned int ring_size; unsigned int ring_size;
/* For edmac */
struct dw_mci_dma_slave *dms;
/* Registers's physical base address */
void *phy_regs;
u32 cmd_status; u32 cmd_status;
u32 data_status; u32 data_status;
u32 stop_cmdr; u32 stop_cmdr;
...@@ -208,8 +227,8 @@ struct dw_mci { ...@@ -208,8 +227,8 @@ struct dw_mci {
struct dw_mci_dma_ops { struct dw_mci_dma_ops {
/* DMA Ops */ /* DMA Ops */
int (*init)(struct dw_mci *host); int (*init)(struct dw_mci *host);
void (*start)(struct dw_mci *host, unsigned int sg_len); int (*start)(struct dw_mci *host, unsigned int sg_len);
void (*complete)(struct dw_mci *host); void (*complete)(void *host);
void (*stop)(struct dw_mci *host); void (*stop)(struct dw_mci *host);
void (*cleanup)(struct dw_mci *host); void (*cleanup)(struct dw_mci *host);
void (*exit)(struct dw_mci *host); void (*exit)(struct dw_mci *host);
......
...@@ -292,18 +292,6 @@ struct mmc_host { ...@@ -292,18 +292,6 @@ struct mmc_host {
mmc_pm_flag_t pm_caps; /* supported pm features */ mmc_pm_flag_t pm_caps; /* supported pm features */
#ifdef CONFIG_MMC_CLKGATE
int clk_requests; /* internal reference counter */
unsigned int clk_delay; /* number of MCI clk hold cycles */
bool clk_gated; /* clock gated */
struct delayed_work clk_gate_work; /* delayed clock gate */
unsigned int clk_old; /* old clock value cache */
spinlock_t clk_lock; /* lock for clk fields */
struct mutex clk_gate_mutex; /* mutex for clock gating */
struct device_attribute clkgate_delay_attr;
unsigned long clkgate_delay;
#endif
/* host specific block data */ /* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_segs; /* see blk_queue_max_segments */ unsigned short max_segs; /* see blk_queue_max_segments */
...@@ -423,6 +411,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply); ...@@ -423,6 +411,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply);
int mmc_regulator_set_ocr(struct mmc_host *mmc, int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply, struct regulator *supply,
unsigned short vdd_bit); unsigned short vdd_bit);
int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios);
#else #else
static inline int mmc_regulator_get_ocrmask(struct regulator *supply) static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
{ {
...@@ -435,6 +424,12 @@ static inline int mmc_regulator_set_ocr(struct mmc_host *mmc, ...@@ -435,6 +424,12 @@ static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
{ {
return 0; return 0;
} }
static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc,
struct mmc_ios *ios)
{
return -EINVAL;
}
#endif #endif
int mmc_regulator_get_supply(struct mmc_host *mmc); int mmc_regulator_get_supply(struct mmc_host *mmc);
...@@ -479,26 +474,6 @@ static inline int mmc_host_packed_wr(struct mmc_host *host) ...@@ -479,26 +474,6 @@ static inline int mmc_host_packed_wr(struct mmc_host *host)
return host->caps2 & MMC_CAP2_PACKED_WR; return host->caps2 & MMC_CAP2_PACKED_WR;
} }
#ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_release(struct mmc_host *host);
unsigned int mmc_host_clk_rate(struct mmc_host *host);
#else
static inline void mmc_host_clk_hold(struct mmc_host *host)
{
}
static inline void mmc_host_clk_release(struct mmc_host *host)
{
}
static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
{
return host->ios.clock;
}
#endif
static inline int mmc_card_hs(struct mmc_card *card) static inline int mmc_card_hs(struct mmc_card *card)
{ {
return card->host->ios.timing == MMC_TIMING_SD_HS || return card->host->ios.timing == MMC_TIMING_SD_HS ||
......
...@@ -45,8 +45,24 @@ struct mmc_ioc_cmd { ...@@ -45,8 +45,24 @@ struct mmc_ioc_cmd {
}; };
#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr #define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr
#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd) /**
* struct mmc_ioc_multi_cmd - multi command information
* @num_of_cmds: Number of commands to send. Must be equal to or less than
* MMC_IOC_MAX_CMDS.
* @cmds: Array of commands with length equal to 'num_of_cmds'
*/
struct mmc_ioc_multi_cmd {
__u64 num_of_cmds;
struct mmc_ioc_cmd cmds[0];
};
#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
/*
* MMC_IOC_MULTI_CMD: Used to send an array of MMC commands described by
* the structure mmc_ioc_multi_cmd. The MMC driver will issue all
* commands in array in sequence to card.
*/
#define MMC_IOC_MULTI_CMD _IOWR(MMC_BLOCK_MAJOR, 1, struct mmc_ioc_multi_cmd)
/* /*
* Since this ioctl is only meant to enhance (and not replace) normal access * Since this ioctl is only meant to enhance (and not replace) normal access
* to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES * to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES
...@@ -54,4 +70,5 @@ struct mmc_ioc_cmd { ...@@ -54,4 +70,5 @@ struct mmc_ioc_cmd {
* block device operations. * block device operations.
*/ */
#define MMC_IOC_MAX_BYTES (512L * 256) #define MMC_IOC_MAX_BYTES (512L * 256)
#define MMC_IOC_MAX_CMDS 255
#endif /* LINUX_MMC_IOCTL_H */ #endif /* LINUX_MMC_IOCTL_H */
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