mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-18 17:16:27 +07:00
MMC core:
- Let the dma map ops deal with bouncing and drop dma_max_pfn() from the dma-mapping interface for ARM - Convert the generic MMC DT doc to YAML schemas - Drop questionable support for powered-on re-init of SDIO cards at runtime resume and for SDIO HW reset - Prevent questionable re-init of powered-on removable SDIO cards at system resume - Cleanup and clarify some SDIO core code MMC host: - tmio: Make runtime PM enablement more flexible for variants - tmio/renesas_sdhi: Rename DT doc tmio_mmc.txt to renesas,sdhi.txt to clarify - sdhci-pci: Add support for Intel EHL - sdhci-pci-o2micro: Enable support for 8-bit bus - sdhci-msm: Prevent acquiring a mutex while holding a spin_lock - sdhci-of-esdhc: Improve clock management and tuning - sdhci_am654: Enable support for 4 and 8-bit bus on J721E - sdhci-sprd: Use pinctrl for a proper signal voltage switch - sdhci-sprd: Add support for HS400 enhanced strobe mode - sdhci-sprd: Enable PHY DLL and allow delay config to stabilize the clock - sdhci-sprd: Add support for optional gate clock - sunxi-mmc: Convert DT doc to YAML schemas - meson-gx: Add support for broken DRAM access for DMA MEMSTICK core: - Fixup error path of memstick_init() -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAl0l7iYXHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCnZnRAA0nBPUsFMl559lySNwO+WjBVo z58dw+J3jDTZ5gFGAUOrnYkZfGEweRwzWnfED6Dyh+e+SJiRnSZH8XRTJEAUeTgi 9KWVr+VGpjZyctNJaMKTeJbPiu/50UVRLJeOGcdJWdMMC9ZlJjKKC2xgyVsInq7P wKE8T3k5afNxABgrKtOTKKONCPRNMVyHdMXzUNFLhlj/du9rR5K7f429RhpPU6GU 7jQ7z9147mwRYm5frn1nx3IvrJUaGyiiSs1ln1PnOV9LsUfVP5NluvbYA6nS4e3V jU64Rvf+9RIHTt2z+ZWTjqrNb/2Ug4faPHc7D4Yl4PEsesR51+tWbpLWUX7Mmm6d 2gbWFv3kzYvSU2G4ztMTrLcsQmd64W1GocXFPvh/UdfQf1200abenj17Gdl0h3Ze +NouYXwMw+n1wHNciotpaR8OMHGV6zo0dvDczpc3r73wzxoeNGdiuVlppFcIGvdA 950oPiqNrFtz2S1DZ9HLeISMajRts7B1nvsr9a/XXa8Us1M6whQDJbMDTynR4Fky j8Sw+9nCk0gupuNcfOrHN9TfOf6Tc5BtIvGqhVF6wmDRtRubfc9HReRheioU67EO PsWe+xpS/8pg/lJNzBm6i0isCmce+rNbZTtpil33yS4Tv85KhGw1XOZ6HLoPrOmN HYPJtDUvOMKlH6M1rJM= =vkWp -----END PGP SIGNATURE----- Merge tag 'mmc-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc Pull MMC updates from Ulf Hansson: "MMC core: - Let the dma map ops deal with bouncing and drop dma_max_pfn() from the dma-mapping interface for ARM - Convert the generic MMC DT doc to YAML schemas - Drop questionable support for powered-on re-init of SDIO cards at runtime resume and for SDIO HW reset - Prevent questionable re-init of powered-on removable SDIO cards at system resume - Cleanup and clarify some SDIO core code MMC host: - tmio: Make runtime PM enablement more flexible for variants - tmio/renesas_sdhi: Rename DT doc tmio_mmc.txt to renesas,sdhi.txt to clarify - sdhci-pci: Add support for Intel EHL - sdhci-pci-o2micro: Enable support for 8-bit bus - sdhci-msm: Prevent acquiring a mutex while holding a spin_lock - sdhci-of-esdhc: Improve clock management and tuning - sdhci_am654: Enable support for 4 and 8-bit bus on J721E - sdhci-sprd: Use pinctrl for a proper signal voltage switch - sdhci-sprd: Add support for HS400 enhanced strobe mode - sdhci-sprd: Enable PHY DLL and allow delay config to stabilize the clock - sdhci-sprd: Add support for optional gate clock - sunxi-mmc: Convert DT doc to YAML schemas - meson-gx: Add support for broken DRAM access for DMA MEMSTICK core: - Fixup error path of memstick_init()" * tag 'mmc-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (52 commits) mmc: sdhci_am654: Add dependency on MMC_SDHCI_AM654 mmc: alcor: remove a redundant greater or equal to zero comparison mmc: sdhci-msm: fix mutex while in spinlock mmc: sdhci_am654: Make some symbols static dma-mapping: remove dma_max_pfn mmc: core: let the dma map ops handle bouncing dt-binding: mmc: rename tmio_mmc.txt to renesas,sdhi.txt mmc: sdhci-sprd: Add pin control support for voltage switch dt-bindings: mmc: sprd: Add pinctrl support mmc: sdhci-sprd: Add start_signal_voltage_switch ops mmc: sdhci-pci: Add support for Intel EHL mmc: tmio: Use dma_max_mapping_size() instead of a workaround mmc: sdio: Drop unused in-parameter from mmc_sdio_init_card() mmc: sdio: Drop unused in-parameter to mmc_sdio_reinit_card() mmc: sdio: Don't re-initialize powered-on removable SDIO cards at resume mmc: sdio: Drop powered-on re-init at runtime resume and HW reset mmc: sdio: Move comment about re-initialization to mmc_sdio_reinit_card() mmc: sdio: Drop mmc_claim|release_host() in mmc_sdio_power_restore() mmc: sdio: Turn sdio_run_irqs() into static mmc: sdhci: Fix indenting on SDHCI_CTRL_8BITBUS ...
This commit is contained in:
commit
8931084c0d
@ -0,0 +1,98 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/mmc/allwinner,sun4i-a10-mmc.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Allwinner A10 MMC Controller Device Tree Bindings
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: "mmc-controller.yaml"
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Chen-Yu Tsai <wens@csie.org>
|
||||||
|
- Maxime Ripard <maxime.ripard@bootlin.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
"#address-cells": true
|
||||||
|
"#size-cells": true
|
||||||
|
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- const: allwinner,sun4i-a10-mmc
|
||||||
|
- const: allwinner,sun5i-a13-mmc
|
||||||
|
- const: allwinner,sun7i-a20-mmc
|
||||||
|
- const: allwinner,sun8i-a83t-emmc
|
||||||
|
- const: allwinner,sun9i-a80-mmc
|
||||||
|
- const: allwinner,sun50i-a64-emmc
|
||||||
|
- const: allwinner,sun50i-a64-mmc
|
||||||
|
- items:
|
||||||
|
- const: allwinner,sun8i-a83t-mmc
|
||||||
|
- const: allwinner,sun7i-a20-mmc
|
||||||
|
- items:
|
||||||
|
- const: allwinner,sun50i-h6-emmc
|
||||||
|
- const: allwinner,sun50i-a64-emmc
|
||||||
|
- items:
|
||||||
|
- const: allwinner,sun50i-h6-mmc
|
||||||
|
- const: allwinner,sun50i-a64-mmc
|
||||||
|
- items:
|
||||||
|
- const: allwinner,sun8i-r40-emmc
|
||||||
|
- const: allwinner,sun50i-a64-emmc
|
||||||
|
- items:
|
||||||
|
- const: allwinner,sun8i-r40-mmc
|
||||||
|
- const: allwinner,sun50i-a64-mmc
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
minItems: 2
|
||||||
|
maxItems: 4
|
||||||
|
items:
|
||||||
|
- description: Bus Clock
|
||||||
|
- description: Module Clock
|
||||||
|
- description: Output Clock
|
||||||
|
- description: Sample Clock
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
minItems: 2
|
||||||
|
maxItems: 4
|
||||||
|
items:
|
||||||
|
- const: ahb
|
||||||
|
- const: mmc
|
||||||
|
- const: output
|
||||||
|
- const: sample
|
||||||
|
|
||||||
|
resets:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
reset-names:
|
||||||
|
const: ahb
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
mmc0: mmc@1c0f000 {
|
||||||
|
compatible = "allwinner,sun5i-a13-mmc";
|
||||||
|
reg = <0x01c0f000 0x1000>;
|
||||||
|
clocks = <&ahb_gates 8>, <&mmc0_clk>;
|
||||||
|
clock-names = "ahb", "mmc";
|
||||||
|
interrupts = <32>;
|
||||||
|
bus-width = <4>;
|
||||||
|
cd-gpios = <&pio 7 1 0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
# FIXME: We should set it, but it would report all the generic
|
||||||
|
# properties as additional properties.
|
||||||
|
# additionalProperties: false
|
||||||
|
|
||||||
|
...
|
@ -22,6 +22,10 @@ Required properties:
|
|||||||
clock rate requested by the MMC core.
|
clock rate requested by the MMC core.
|
||||||
- resets : phandle of the internal reset line
|
- resets : phandle of the internal reset line
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- amlogic,dram-access-quirk: set when controller's internal DMA engine cannot access the
|
||||||
|
DRAM memory, like on the G12A dedicated SDIO controller.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
sd_emmc_a: mmc@70000 {
|
sd_emmc_a: mmc@70000 {
|
||||||
|
374
Documentation/devicetree/bindings/mmc/mmc-controller.yaml
Normal file
374
Documentation/devicetree/bindings/mmc/mmc-controller.yaml
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/mmc/mmc-controller.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: MMC Controller Generic Binding
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Ulf Hansson <ulf.hansson@linaro.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
These properties are common to multiple MMC host controllers. Any host
|
||||||
|
that requires the respective functionality should implement them using
|
||||||
|
these definitions.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
$nodename:
|
||||||
|
pattern: "^mmc(@.*)?$"
|
||||||
|
|
||||||
|
"#address-cells":
|
||||||
|
const: 1
|
||||||
|
description: |
|
||||||
|
The cell is the slot ID if a function subnode is used.
|
||||||
|
|
||||||
|
"#size-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
# Card Detection.
|
||||||
|
# If none of these properties are supplied, the host native card
|
||||||
|
# detect will be used. Only one of them should be provided.
|
||||||
|
|
||||||
|
broken-cd:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
There is no card detection available; polling must be used.
|
||||||
|
|
||||||
|
cd-gpios:
|
||||||
|
description:
|
||||||
|
The card detection will be done using the GPIO provided.
|
||||||
|
|
||||||
|
non-removable:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
Non-removable slot (like eMMC); assume always present.
|
||||||
|
|
||||||
|
# *NOTE* on CD and WP polarity. To use common for all SD/MMC host
|
||||||
|
# controllers line polarity properties, we have to fix the meaning
|
||||||
|
# of the "normal" and "inverted" line levels. We choose to follow
|
||||||
|
# the SDHCI standard, which specifies both those lines as "active
|
||||||
|
# low." Therefore, using the "cd-inverted" property means, that the
|
||||||
|
# CD line is active high, i.e. it is high, when a card is
|
||||||
|
# inserted. Similar logic applies to the "wp-inverted" property.
|
||||||
|
#
|
||||||
|
# CD and WP lines can be implemented on the hardware in one of two
|
||||||
|
# ways: as GPIOs, specified in cd-gpios and wp-gpios properties, or
|
||||||
|
# as dedicated pins. Polarity of dedicated pins can be specified,
|
||||||
|
# using *-inverted properties. GPIO polarity can also be specified
|
||||||
|
# using the GPIO_ACTIVE_LOW flag. This creates an ambiguity in the
|
||||||
|
# latter case. We choose to use the XOR logic for GPIO CD and WP
|
||||||
|
# lines. This means, the two properties are "superimposed," for
|
||||||
|
# example leaving the GPIO_ACTIVE_LOW flag clear and specifying the
|
||||||
|
# respective *-inverted property property results in a
|
||||||
|
# double-inversion and actually means the "normal" line polarity is
|
||||||
|
# in effect.
|
||||||
|
wp-inverted:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
The Write Protect line polarity is inverted.
|
||||||
|
|
||||||
|
cd-inverted:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
The CD line polarity is inverted.
|
||||||
|
|
||||||
|
# Other properties
|
||||||
|
|
||||||
|
bus-width:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [1, 4, 8]
|
||||||
|
default: 1
|
||||||
|
description:
|
||||||
|
Number of data lines.
|
||||||
|
|
||||||
|
max-frequency:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 400000
|
||||||
|
- maximum: 200000000
|
||||||
|
description:
|
||||||
|
Maximum operating frequency of the bus.
|
||||||
|
|
||||||
|
disable-wp:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
When set, no physical write-protect line is present. This
|
||||||
|
property should only be specified when the controller has a
|
||||||
|
dedicated write-protect detection logic. If a GPIO is always
|
||||||
|
used for the write-protect detection. If a GPIO is always used
|
||||||
|
for the write-protect detection logic, it is sufficient to not
|
||||||
|
specify the wp-gpios property in the absence of a write-protect
|
||||||
|
line.
|
||||||
|
|
||||||
|
wp-gpios:
|
||||||
|
description:
|
||||||
|
GPIO to use for the write-protect detection.
|
||||||
|
|
||||||
|
cd-debounce-delay-ms:
|
||||||
|
description:
|
||||||
|
Set delay time before detecting card after card insert
|
||||||
|
interrupt.
|
||||||
|
|
||||||
|
no-1-8-v:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
When specified, denotes that 1.8V card voltage is not supported
|
||||||
|
on this system, even if the controller claims it.
|
||||||
|
|
||||||
|
cap-sd-highspeed:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
SD high-speed timing is supported.
|
||||||
|
|
||||||
|
cap-mmc-highspeed:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
MMC high-speed timing is supported.
|
||||||
|
|
||||||
|
sd-uhs-sdr12:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
SD UHS SDR12 speed is supported.
|
||||||
|
|
||||||
|
sd-uhs-sdr25:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
SD UHS SDR25 speed is supported.
|
||||||
|
|
||||||
|
sd-uhs-sdr50:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
SD UHS SDR50 speed is supported.
|
||||||
|
|
||||||
|
sd-uhs-sdr104:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
SD UHS SDR104 speed is supported.
|
||||||
|
|
||||||
|
sd-uhs-ddr50:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
SD UHS DDR50 speed is supported.
|
||||||
|
|
||||||
|
cap-power-off-card:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
Powering off the card is safe.
|
||||||
|
|
||||||
|
cap-mmc-hw-reset:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
eMMC hardware reset is supported
|
||||||
|
|
||||||
|
cap-sdio-irq:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
enable SDIO IRQ signalling on this interface
|
||||||
|
|
||||||
|
full-pwr-cycle:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
Full power cycle of the card is supported.
|
||||||
|
|
||||||
|
mmc-ddr-1_2v:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
eMMC high-speed DDR mode (1.2V I/O) is supported.
|
||||||
|
|
||||||
|
mmc-ddr-1_8v:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
eMMC high-speed DDR mode (1.8V I/O) is supported.
|
||||||
|
|
||||||
|
mmc-ddr-3_3v:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
eMMC high-speed DDR mode (3.3V I/O) is supported.
|
||||||
|
|
||||||
|
mmc-hs200-1_2v:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
eMMC HS200 mode (1.2V I/O) is supported.
|
||||||
|
|
||||||
|
mmc-hs200-1_8v:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
eMMC HS200 mode (1.8V I/O) is supported.
|
||||||
|
|
||||||
|
mmc-hs400-1_2v:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
eMMC HS400 mode (1.2V I/O) is supported.
|
||||||
|
|
||||||
|
mmc-hs400-1_8v:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
eMMC HS400 mode (1.8V I/O) is supported.
|
||||||
|
|
||||||
|
mmc-hs400-enhanced-strobe:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
eMMC HS400 enhanced strobe mode is supported
|
||||||
|
|
||||||
|
dsr:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
- maximum: 0xffff
|
||||||
|
description:
|
||||||
|
Value the card Driver Stage Register (DSR) should be programmed
|
||||||
|
with.
|
||||||
|
|
||||||
|
no-sdio:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
Controller is limited to send SDIO commands during
|
||||||
|
initialization.
|
||||||
|
|
||||||
|
no-sd:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
Controller is limited to send SD commands during initialization.
|
||||||
|
|
||||||
|
no-mmc:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
Controller is limited to send MMC commands during
|
||||||
|
initialization.
|
||||||
|
|
||||||
|
fixed-emmc-driver-type:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
- maximum: 4
|
||||||
|
description:
|
||||||
|
For non-removable eMMC, enforce this driver type. The value is
|
||||||
|
the driver type as specified in the eMMC specification (table
|
||||||
|
206 in spec version 5.1)
|
||||||
|
|
||||||
|
post-power-on-delay-ms:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- default: 10
|
||||||
|
description:
|
||||||
|
It was invented for MMC pwrseq-simple which could be referred to
|
||||||
|
mmc-pwrseq-simple.txt. But now it\'s reused as a tunable delay
|
||||||
|
waiting for I/O signalling and card power supply to be stable,
|
||||||
|
regardless of whether pwrseq-simple is used. Default to 10ms if
|
||||||
|
no available.
|
||||||
|
|
||||||
|
supports-cqe:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
The presence of this property indicates that the corresponding
|
||||||
|
MMC host controller supports HW command queue feature.
|
||||||
|
|
||||||
|
disable-cqe-dcmd:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
The presence of this property indicates that the MMC
|
||||||
|
controller\'s command queue engine (CQE) does not support direct
|
||||||
|
commands (DCMDs).
|
||||||
|
|
||||||
|
keep-power-in-suspend:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
SDIO only. Preserves card power during a suspend/resume cycle.
|
||||||
|
|
||||||
|
# Deprecated: enable-sdio-wakeup
|
||||||
|
wakeup-source:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
SDIO only. Enables wake up of host system on SDIO IRQ assertion.
|
||||||
|
|
||||||
|
vmmc-supply:
|
||||||
|
description:
|
||||||
|
Supply for the card power
|
||||||
|
|
||||||
|
vqmmc-supply:
|
||||||
|
description:
|
||||||
|
Supply for the bus IO line power
|
||||||
|
|
||||||
|
mmc-pwrseq:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description:
|
||||||
|
System-on-Chip designs may specify a specific MMC power
|
||||||
|
sequence. To successfully detect an (e)MMC/SD/SDIO card, that
|
||||||
|
power sequence must be maintained while initializing the card.
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
"^.*@[0-9]+$":
|
||||||
|
type: object
|
||||||
|
description: |
|
||||||
|
On embedded systems the cards connected to a host may need
|
||||||
|
additional properties. These can be specified in subnodes to the
|
||||||
|
host controller node. The subnodes are identified by the
|
||||||
|
standard \'reg\' property. Which information exactly can be
|
||||||
|
specified depends on the bindings for the SDIO function driver
|
||||||
|
for the subnode, as specified by the compatible string.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
description: |
|
||||||
|
Name of SDIO function following generic names recommended
|
||||||
|
practice
|
||||||
|
|
||||||
|
reg:
|
||||||
|
items:
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 7
|
||||||
|
description:
|
||||||
|
Must contain the SDIO function number of the function this
|
||||||
|
subnode describes. A value of 0 denotes the memory SD
|
||||||
|
function, values from 1 to 7 denote the SDIO functions.
|
||||||
|
|
||||||
|
broken-hpi:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
Use this to indicate that the mmc-card has a broken hpi
|
||||||
|
implementation, and that hpi should not be used.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- reg
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
cd-debounce-delay-ms: [ cd-gpios ]
|
||||||
|
fixed-emmc-driver-type: [ non-removable ]
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
sdhci@ab000000 {
|
||||||
|
compatible = "sdhci";
|
||||||
|
reg = <0xab000000 0x200>;
|
||||||
|
interrupts = <23>;
|
||||||
|
bus-width = <4>;
|
||||||
|
cd-gpios = <&gpio 69 0>;
|
||||||
|
cd-inverted;
|
||||||
|
wp-gpios = <&gpio 70 0>;
|
||||||
|
max-frequency = <50000000>;
|
||||||
|
keep-power-in-suspend;
|
||||||
|
wakeup-source;
|
||||||
|
mmc-pwrseq = <&sdhci0_pwrseq>;
|
||||||
|
};
|
||||||
|
|
||||||
|
- |
|
||||||
|
mmc3: mmc@1c12000 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&mmc3_pins_a>;
|
||||||
|
vmmc-supply = <®_vmmc3>;
|
||||||
|
bus-width = <4>;
|
||||||
|
non-removable;
|
||||||
|
mmc-pwrseq = <&sdhci0_pwrseq>;
|
||||||
|
|
||||||
|
brcmf: bcrmf@1 {
|
||||||
|
reg = <1>;
|
||||||
|
compatible = "brcm,bcm43xx-fmac";
|
||||||
|
interrupt-parent = <&pio>;
|
||||||
|
interrupts = <10 8>;
|
||||||
|
interrupt-names = "host-wake";
|
||||||
|
};
|
||||||
|
};
|
@ -1,177 +1 @@
|
|||||||
These properties are common to multiple MMC host controllers. Any host
|
This file has moved to mmc-controller.yaml.
|
||||||
that requires the respective functionality should implement them using
|
|
||||||
these definitions.
|
|
||||||
|
|
||||||
Interpreted by the OF core:
|
|
||||||
- reg: Registers location and length.
|
|
||||||
- interrupts: Interrupts used by the MMC controller.
|
|
||||||
|
|
||||||
Card detection:
|
|
||||||
If no property below is supplied, host native card detect is used.
|
|
||||||
Only one of the properties in this section should be supplied:
|
|
||||||
- broken-cd: There is no card detection available; polling must be used.
|
|
||||||
- cd-gpios: Specify GPIOs for card detection, see gpio binding
|
|
||||||
- non-removable: non-removable slot (like eMMC); assume always present.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- bus-width: Number of data lines, can be <1>, <4>, or <8>. The default
|
|
||||||
will be <1> if the property is absent.
|
|
||||||
- wp-gpios: Specify GPIOs for write protection, see gpio binding
|
|
||||||
- cd-inverted: when present, polarity on the CD line is inverted. See the note
|
|
||||||
below for the case, when a GPIO is used for the CD line
|
|
||||||
- cd-debounce-delay-ms: Set delay time before detecting card after card insert interrupt.
|
|
||||||
It's only valid when cd-gpios is present.
|
|
||||||
- wp-inverted: when present, polarity on the WP line is inverted. See the note
|
|
||||||
below for the case, when a GPIO is used for the WP line
|
|
||||||
- disable-wp: When set no physical WP line is present. This property should
|
|
||||||
only be specified when the controller has a dedicated write-protect
|
|
||||||
detection logic. If a GPIO is always used for the write-protect detection
|
|
||||||
logic it is sufficient to not specify wp-gpios property in the absence of a WP
|
|
||||||
line.
|
|
||||||
- max-frequency: maximum operating clock frequency
|
|
||||||
- no-1-8-v: when present, denotes that 1.8v card voltage is not supported on
|
|
||||||
this system, even if the controller claims it is.
|
|
||||||
- cap-sd-highspeed: SD high-speed timing is supported
|
|
||||||
- cap-mmc-highspeed: MMC high-speed timing is supported
|
|
||||||
- sd-uhs-sdr12: SD UHS SDR12 speed is supported
|
|
||||||
- sd-uhs-sdr25: SD UHS SDR25 speed is supported
|
|
||||||
- sd-uhs-sdr50: SD UHS SDR50 speed is supported
|
|
||||||
- sd-uhs-sdr104: SD UHS SDR104 speed is supported
|
|
||||||
- sd-uhs-ddr50: SD UHS DDR50 speed is supported
|
|
||||||
- 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
|
|
||||||
- full-pwr-cycle: full power cycle of the card is supported
|
|
||||||
- mmc-ddr-3_3v: eMMC high-speed DDR mode(3.3V I/O) is supported
|
|
||||||
- mmc-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported
|
|
||||||
- mmc-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
|
|
||||||
- mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
|
|
||||||
- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
|
|
||||||
- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
|
|
||||||
- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
|
|
||||||
- mmc-hs400-enhanced-strobe: eMMC HS400 enhanced strobe mode is supported
|
|
||||||
- dsr: Value the card's (optional) Driver Stage Register (DSR) should be
|
|
||||||
programmed with. Valid range: [0 .. 0xffff].
|
|
||||||
- no-sdio: controller is limited to send sdio cmd during initialization
|
|
||||||
- no-sd: controller is limited to send sd cmd during initialization
|
|
||||||
- no-mmc: controller is limited to send mmc cmd during initialization
|
|
||||||
- fixed-emmc-driver-type: for non-removable eMMC, enforce this driver type.
|
|
||||||
The value <n> is the driver type as specified in the eMMC specification
|
|
||||||
(table 206 in spec version 5.1).
|
|
||||||
- post-power-on-delay-ms : It was invented for MMC pwrseq-simple which could
|
|
||||||
be referred to mmc-pwrseq-simple.txt. But now it's reused as a tunable delay
|
|
||||||
waiting for I/O signalling and card power supply to be stable, regardless of
|
|
||||||
whether pwrseq-simple is used. Default to 10ms if no available.
|
|
||||||
- supports-cqe : The presence of this property indicates that the corresponding
|
|
||||||
MMC host controller supports HW command queue feature.
|
|
||||||
- disable-cqe-dcmd: This property indicates that the MMC controller's command
|
|
||||||
queue engine (CQE) does not support direct commands (DCMDs).
|
|
||||||
|
|
||||||
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
|
|
||||||
polarity properties, we have to fix the meaning of the "normal" and "inverted"
|
|
||||||
line levels. We choose to follow the SDHCI standard, which specifies both those
|
|
||||||
lines as "active low." Therefore, using the "cd-inverted" property means, that
|
|
||||||
the CD line is active high, i.e. it is high, when a card is inserted. Similar
|
|
||||||
logic applies to the "wp-inverted" property.
|
|
||||||
|
|
||||||
CD and WP lines can be implemented on the hardware in one of two ways: as GPIOs,
|
|
||||||
specified in cd-gpios and wp-gpios properties, or as dedicated pins. Polarity of
|
|
||||||
dedicated pins can be specified, using *-inverted properties. GPIO polarity can
|
|
||||||
also be specified using the GPIO_ACTIVE_LOW flag. This creates an ambiguity
|
|
||||||
in the latter case. We choose to use the XOR logic for GPIO CD and WP lines.
|
|
||||||
This means, the two properties are "superimposed," for example leaving the
|
|
||||||
GPIO_ACTIVE_LOW flag clear and specifying the respective *-inverted property
|
|
||||||
property results in a double-inversion and actually means the "normal" line
|
|
||||||
polarity is in effect.
|
|
||||||
|
|
||||||
Optional SDIO properties:
|
|
||||||
- keep-power-in-suspend: Preserves card power during a suspend/resume cycle
|
|
||||||
- wakeup-source: Enables wake up of host system on SDIO IRQ assertion
|
|
||||||
(Legacy property supported: "enable-sdio-wakeup")
|
|
||||||
|
|
||||||
MMC power
|
|
||||||
---------
|
|
||||||
|
|
||||||
Controllers may implement power control from both the connected cards and
|
|
||||||
the IO signaling (for example to change to high-speed 1.8V signalling). If
|
|
||||||
the system supports this, then the following two properties should point
|
|
||||||
to valid regulator nodes:
|
|
||||||
|
|
||||||
- vqmmc-supply: supply node for IO line power
|
|
||||||
- vmmc-supply: supply node for card's power
|
|
||||||
|
|
||||||
|
|
||||||
MMC power sequences:
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
System on chip designs may specify a specific MMC power sequence. To
|
|
||||||
successfully detect an (e)MMC/SD/SDIO card, that power sequence must be
|
|
||||||
maintained while initializing the card.
|
|
||||||
|
|
||||||
Optional property:
|
|
||||||
- mmc-pwrseq: phandle to the MMC power sequence node. See "mmc-pwrseq-*"
|
|
||||||
for documentation of MMC power sequence bindings.
|
|
||||||
|
|
||||||
|
|
||||||
Use of Function subnodes
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
On embedded systems the cards connected to a host may need additional
|
|
||||||
properties. These can be specified in subnodes to the host controller node.
|
|
||||||
The subnodes are identified by the standard 'reg' property.
|
|
||||||
Which information exactly can be specified depends on the bindings for the
|
|
||||||
SDIO function driver for the subnode, as specified by the compatible string.
|
|
||||||
|
|
||||||
Required host node properties when using function subnodes:
|
|
||||||
- #address-cells: should be one. The cell is the slot id.
|
|
||||||
- #size-cells: should be zero.
|
|
||||||
|
|
||||||
Required function subnode properties:
|
|
||||||
- reg: Must contain the SDIO function number of the function this subnode
|
|
||||||
describes. A value of 0 denotes the memory SD function, values from
|
|
||||||
1 to 7 denote the SDIO functions.
|
|
||||||
|
|
||||||
Optional function subnode properties:
|
|
||||||
- compatible: name of SDIO function following generic names recommended practice
|
|
||||||
|
|
||||||
|
|
||||||
Examples
|
|
||||||
--------
|
|
||||||
|
|
||||||
Basic example:
|
|
||||||
|
|
||||||
sdhci@ab000000 {
|
|
||||||
compatible = "sdhci";
|
|
||||||
reg = <0xab000000 0x200>;
|
|
||||||
interrupts = <23>;
|
|
||||||
bus-width = <4>;
|
|
||||||
cd-gpios = <&gpio 69 0>;
|
|
||||||
cd-inverted;
|
|
||||||
wp-gpios = <&gpio 70 0>;
|
|
||||||
max-frequency = <50000000>;
|
|
||||||
keep-power-in-suspend;
|
|
||||||
wakeup-source;
|
|
||||||
mmc-pwrseq = <&sdhci0_pwrseq>
|
|
||||||
}
|
|
||||||
|
|
||||||
Example with sdio function subnode:
|
|
||||||
|
|
||||||
mmc3: mmc@1c12000 {
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&mmc3_pins_a>;
|
|
||||||
vmmc-supply = <®_vmmc3>;
|
|
||||||
bus-width = <4>;
|
|
||||||
non-removable;
|
|
||||||
mmc-pwrseq = <&sdhci0_pwrseq>
|
|
||||||
|
|
||||||
brcmf: bcrmf@1 {
|
|
||||||
reg = <1>;
|
|
||||||
compatible = "brcm,bcm43xx-fmac";
|
|
||||||
interrupt-parent = <&pio>;
|
|
||||||
interrupts = <10 8>; /* PH10 / EINT10 */
|
|
||||||
interrupt-names = "host-wake";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
@ -1,13 +1,4 @@
|
|||||||
* Toshiba Mobile IO SD/MMC controller
|
* Renesas SDHI SD/MMC controller
|
||||||
|
|
||||||
The tmio-mmc driver doesn't probe its devices actively, instead its binding to
|
|
||||||
devices is managed by either MFD drivers or by the sh_mobile_sdhi platform
|
|
||||||
driver. Those drivers supply the tmio-mmc driver with platform data, that either
|
|
||||||
describe hardware capabilities, known to them, or are obtained by them from
|
|
||||||
their own platform data or from their DT information. In the latter case all
|
|
||||||
compulsory and any optional properties, common to all SD/MMC drivers, as
|
|
||||||
described in mmc.txt, can be used. Additionally the following tmio_mmc-specific
|
|
||||||
optional bindings can be used.
|
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: should contain one or more of the following:
|
- compatible: should contain one or more of the following:
|
@ -8,7 +8,10 @@ Only deviations are documented here.
|
|||||||
[3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
[3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||||
|
|
||||||
Required Properties:
|
Required Properties:
|
||||||
- compatible: should be "ti,am654-sdhci-5.1"
|
- compatible: should be one of:
|
||||||
|
"ti,am654-sdhci-5.1": SDHCI on AM654 device.
|
||||||
|
"ti,j721e-sdhci-8bit": 8 bit SDHCI on J721E device.
|
||||||
|
"ti,j721e-sdhci-4bit": 4 bit SDHCI on J721E device.
|
||||||
- reg: Must be two entries.
|
- reg: Must be two entries.
|
||||||
- The first should be the sdhci register space
|
- The first should be the sdhci register space
|
||||||
- The second should the subsystem/phy register space
|
- The second should the subsystem/phy register space
|
||||||
@ -16,9 +19,13 @@ Required Properties:
|
|||||||
- clock-names: Tuple including "clk_xin" and "clk_ahb"
|
- clock-names: Tuple including "clk_xin" and "clk_ahb"
|
||||||
- interrupts: Interrupt specifiers
|
- interrupts: Interrupt specifiers
|
||||||
- ti,otap-del-sel: Output Tap Delay select
|
- ti,otap-del-sel: Output Tap Delay select
|
||||||
|
|
||||||
|
Optional Properties (Required for ti,am654-sdhci-5.1 and ti,j721e-sdhci-8bit):
|
||||||
- ti,trm-icp: DLL trim select
|
- ti,trm-icp: DLL trim select
|
||||||
- ti,driver-strength-ohm: driver strength in ohms.
|
- ti,driver-strength-ohm: driver strength in ohms.
|
||||||
Valid values are 33, 40, 50, 66 and 100 ohms.
|
Valid values are 33, 40, 50, 66 and 100 ohms.
|
||||||
|
Optional Properties:
|
||||||
|
- ti,strobe-sel: strobe select delay for HS400 speed mode. Default value: 0x0.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -14,10 +14,31 @@ Required properties:
|
|||||||
- clock-names: Should contain the following:
|
- clock-names: Should contain the following:
|
||||||
"sdio" - SDIO source clock (required)
|
"sdio" - SDIO source clock (required)
|
||||||
"enable" - gate clock which used for enabling/disabling the device (required)
|
"enable" - gate clock which used for enabling/disabling the device (required)
|
||||||
|
"2x_enable" - gate clock controlling the device for some special platforms (optional)
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- assigned-clocks: the same with "sdio" clock
|
- assigned-clocks: the same with "sdio" clock
|
||||||
- assigned-clock-parents: the default parent of "sdio" clock
|
- assigned-clock-parents: the default parent of "sdio" clock
|
||||||
|
- pinctrl-names: should be "default", "state_uhs"
|
||||||
|
- pinctrl-0: should contain default/high speed pin control
|
||||||
|
- pinctrl-1: should contain uhs mode pin control
|
||||||
|
|
||||||
|
PHY DLL delays are used to delay the data valid window, and align the window
|
||||||
|
to sampling clock. PHY DLL delays can be configured by following properties,
|
||||||
|
and each property contains 4 cells which are used to configure the clock data
|
||||||
|
write line delay value, clock read command line delay value, clock read data
|
||||||
|
positive edge delay value and clock read data negative edge delay value.
|
||||||
|
Each cell's delay value unit is cycle of the PHY clock.
|
||||||
|
|
||||||
|
- sprd,phy-delay-legacy: Delay value for legacy timing.
|
||||||
|
- sprd,phy-delay-sd-highspeed: Delay value for SD high-speed timing.
|
||||||
|
- sprd,phy-delay-sd-uhs-sdr50: Delay value for SD UHS SDR50 timing.
|
||||||
|
- sprd,phy-delay-sd-uhs-sdr104: Delay value for SD UHS SDR50 timing.
|
||||||
|
- sprd,phy-delay-mmc-highspeed: Delay value for MMC high-speed timing.
|
||||||
|
- sprd,phy-delay-mmc-ddr52: Delay value for MMC DDR52 timing.
|
||||||
|
- sprd,phy-delay-mmc-hs200: Delay value for MMC HS200 timing.
|
||||||
|
- sprd,phy-delay-mmc-hs400: Delay value for MMC HS400 timing.
|
||||||
|
- sprd,phy-delay-mmc-hs400es: Delay value for MMC HS400 enhanced strobe timing.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
@ -32,6 +53,11 @@ sdio0: sdio@20600000 {
|
|||||||
assigned-clocks = <&ap_clk CLK_EMMC_2X>;
|
assigned-clocks = <&ap_clk CLK_EMMC_2X>;
|
||||||
assigned-clock-parents = <&rpll CLK_RPLL_390M>;
|
assigned-clock-parents = <&rpll CLK_RPLL_390M>;
|
||||||
|
|
||||||
|
pinctrl-names = "default", "state_uhs";
|
||||||
|
pinctrl-0 = <&sd0_pins_default>;
|
||||||
|
pinctrl-1 = <&sd0_pins_uhs>;
|
||||||
|
|
||||||
|
sprd,phy-delay-sd-uhs-sdr104 = <0x3f 0x7f 0x2e 0x2e>;
|
||||||
bus-width = <8>;
|
bus-width = <8>;
|
||||||
non-removable;
|
non-removable;
|
||||||
no-sdio;
|
no-sdio;
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
* Allwinner sunxi MMC controller
|
|
||||||
|
|
||||||
The highspeed MMC host controller on Allwinner SoCs provides an interface
|
|
||||||
for MMC, SD and SDIO types of memory cards.
|
|
||||||
|
|
||||||
Supported maximum speeds are the ones of the eMMC standard 4.5 as well
|
|
||||||
as the speed of SD standard 3.0.
|
|
||||||
Absolute maximum transfer rate is 200MB/s
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible : should be one of:
|
|
||||||
* "allwinner,sun4i-a10-mmc"
|
|
||||||
* "allwinner,sun5i-a13-mmc"
|
|
||||||
* "allwinner,sun7i-a20-mmc"
|
|
||||||
* "allwinner,sun8i-a83t-emmc"
|
|
||||||
* "allwinner,sun9i-a80-mmc"
|
|
||||||
* "allwinner,sun50i-a64-emmc"
|
|
||||||
* "allwinner,sun50i-a64-mmc"
|
|
||||||
* "allwinner,sun50i-h6-emmc", "allwinner.sun50i-a64-emmc"
|
|
||||||
* "allwinner,sun50i-h6-mmc", "allwinner.sun50i-a64-mmc"
|
|
||||||
- reg : mmc controller base registers
|
|
||||||
- clocks : a list with 4 phandle + clock specifier pairs
|
|
||||||
- clock-names : must contain "ahb", "mmc", "output" and "sample"
|
|
||||||
- interrupts : mmc controller interrupt
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- resets : phandle + reset specifier pair
|
|
||||||
- reset-names : must contain "ahb"
|
|
||||||
- for cd, bus-width and additional generic mmc parameters
|
|
||||||
please refer to mmc.txt within this directory
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
- Within .dtsi:
|
|
||||||
mmc0: mmc@1c0f000 {
|
|
||||||
compatible = "allwinner,sun5i-a13-mmc";
|
|
||||||
reg = <0x01c0f000 0x1000>;
|
|
||||||
clocks = <&ahb_gates 8>, <&mmc0_clk>, <&mmc0_output_clk>, <&mmc0_sample_clk>;
|
|
||||||
clock-names = "ahb", "mod", "output", "sample";
|
|
||||||
interrupts = <0 32 4>;
|
|
||||||
status = "disabled";
|
|
||||||
};
|
|
||||||
|
|
||||||
- Within dts:
|
|
||||||
mmc0: mmc@1c0f000 {
|
|
||||||
pinctrl-names = "default", "default";
|
|
||||||
pinctrl-0 = <&mmc0_pins_a>;
|
|
||||||
pinctrl-1 = <&mmc0_cd_pin_reference_design>;
|
|
||||||
bus-width = <4>;
|
|
||||||
cd-gpios = <&pio 7 1 0>; /* PH1 */
|
|
||||||
cd-inverted;
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
@ -89,13 +89,6 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The ARM override for dma_max_pfn() */
|
|
||||||
static inline unsigned long dma_max_pfn(struct device *dev)
|
|
||||||
{
|
|
||||||
return dma_to_pfn(dev, *dev->dma_mask);
|
|
||||||
}
|
|
||||||
#define dma_max_pfn(dev) dma_max_pfn(dev)
|
|
||||||
|
|
||||||
/* do not use this function in a driver */
|
/* do not use this function in a driver */
|
||||||
static inline bool is_device_dma_coherent(struct device *dev)
|
static inline bool is_device_dma_coherent(struct device *dev)
|
||||||
{
|
{
|
||||||
|
@ -625,13 +625,18 @@ static int __init memstick_init(void)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
rc = bus_register(&memstick_bus_type);
|
rc = bus_register(&memstick_bus_type);
|
||||||
if (!rc)
|
if (rc)
|
||||||
rc = class_register(&memstick_host_class);
|
goto error_destroy_workqueue;
|
||||||
|
|
||||||
if (!rc)
|
rc = class_register(&memstick_host_class);
|
||||||
return 0;
|
if (rc)
|
||||||
|
goto error_bus_unregister;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_bus_unregister:
|
||||||
bus_unregister(&memstick_bus_type);
|
bus_unregister(&memstick_bus_type);
|
||||||
|
error_destroy_workqueue:
|
||||||
destroy_workqueue(workqueue);
|
destroy_workqueue(workqueue);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -227,45 +227,21 @@ void mmc_add_host_debugfs(struct mmc_host *host)
|
|||||||
struct dentry *root;
|
struct dentry *root;
|
||||||
|
|
||||||
root = debugfs_create_dir(mmc_hostname(host), NULL);
|
root = debugfs_create_dir(mmc_hostname(host), NULL);
|
||||||
if (IS_ERR(root))
|
|
||||||
/* Don't complain -- debugfs just isn't enabled */
|
|
||||||
return;
|
|
||||||
if (!root)
|
|
||||||
/* Complain -- debugfs is enabled, but it failed to
|
|
||||||
* create the directory. */
|
|
||||||
goto err_root;
|
|
||||||
|
|
||||||
host->debugfs_root = root;
|
host->debugfs_root = root;
|
||||||
|
|
||||||
if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
|
debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops);
|
||||||
goto err_node;
|
debugfs_create_x32("caps", S_IRUSR, root, &host->caps);
|
||||||
|
debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2);
|
||||||
if (!debugfs_create_x32("caps", S_IRUSR, root, &host->caps))
|
debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
|
||||||
goto err_node;
|
&mmc_clock_fops);
|
||||||
|
|
||||||
if (!debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2))
|
|
||||||
goto err_node;
|
|
||||||
|
|
||||||
if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
|
|
||||||
&mmc_clock_fops))
|
|
||||||
goto err_node;
|
|
||||||
|
|
||||||
#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);
|
||||||
host->fail_mmc_request = fail_default_attr;
|
host->fail_mmc_request = fail_default_attr;
|
||||||
if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
|
fault_create_debugfs_attr("fail_mmc_request", root,
|
||||||
root,
|
&host->fail_mmc_request);
|
||||||
&host->fail_mmc_request)))
|
|
||||||
goto err_node;
|
|
||||||
#endif
|
#endif
|
||||||
return;
|
|
||||||
|
|
||||||
err_node:
|
|
||||||
debugfs_remove_recursive(root);
|
|
||||||
host->debugfs_root = NULL;
|
|
||||||
err_root:
|
|
||||||
dev_err(&host->class_dev, "failed to initialize debugfs\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mmc_remove_host_debugfs(struct mmc_host *host)
|
void mmc_remove_host_debugfs(struct mmc_host *host)
|
||||||
@ -282,25 +258,9 @@ void mmc_add_card_debugfs(struct mmc_card *card)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
|
root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
|
||||||
if (IS_ERR(root))
|
|
||||||
/* Don't complain -- debugfs just isn't enabled */
|
|
||||||
return;
|
|
||||||
if (!root)
|
|
||||||
/* Complain -- debugfs is enabled, but it failed to
|
|
||||||
* create the directory. */
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
card->debugfs_root = root;
|
card->debugfs_root = root;
|
||||||
|
|
||||||
if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
|
debugfs_create_x32("state", S_IRUSR, root, &card->state);
|
||||||
goto err;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
err:
|
|
||||||
debugfs_remove_recursive(root);
|
|
||||||
card->debugfs_root = NULL;
|
|
||||||
dev_err(&card->dev, "failed to initialize debugfs\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mmc_remove_card_debugfs(struct mmc_card *card)
|
void mmc_remove_card_debugfs(struct mmc_card *card)
|
||||||
|
@ -3167,15 +3167,7 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
|
|||||||
struct mmc_test_dbgfs_file *df;
|
struct mmc_test_dbgfs_file *df;
|
||||||
|
|
||||||
if (card->debugfs_root)
|
if (card->debugfs_root)
|
||||||
file = debugfs_create_file(name, mode, card->debugfs_root,
|
debugfs_create_file(name, mode, card->debugfs_root, card, fops);
|
||||||
card, fops);
|
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(file)) {
|
|
||||||
dev_err(&card->dev,
|
|
||||||
"Can't create %s. Perhaps debugfs is disabled.\n",
|
|
||||||
name);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
df = kmalloc(sizeof(*df), GFP_KERNEL);
|
df = kmalloc(sizeof(*df), GFP_KERNEL);
|
||||||
if (!df) {
|
if (!df) {
|
||||||
|
@ -350,18 +350,15 @@ static const struct blk_mq_ops mmc_mq_ops = {
|
|||||||
static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
|
static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
|
||||||
{
|
{
|
||||||
struct mmc_host *host = card->host;
|
struct mmc_host *host = card->host;
|
||||||
u64 limit = BLK_BOUNCE_HIGH;
|
|
||||||
unsigned block_size = 512;
|
unsigned block_size = 512;
|
||||||
|
|
||||||
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
|
|
||||||
limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
|
|
||||||
|
|
||||||
blk_queue_flag_set(QUEUE_FLAG_NONROT, mq->queue);
|
blk_queue_flag_set(QUEUE_FLAG_NONROT, mq->queue);
|
||||||
blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);
|
blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);
|
||||||
if (mmc_can_erase(card))
|
if (mmc_can_erase(card))
|
||||||
mmc_queue_setup_discard(mq->queue, card);
|
mmc_queue_setup_discard(mq->queue, card);
|
||||||
|
|
||||||
blk_queue_bounce_limit(mq->queue, limit);
|
if (!mmc_dev(host)->dma_mask || !*mmc_dev(host)->dma_mask)
|
||||||
|
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH);
|
||||||
blk_queue_max_hw_sectors(mq->queue,
|
blk_queue_max_hw_sectors(mq->queue,
|
||||||
min(host->max_blk_count, host->max_req_size / 512));
|
min(host->max_blk_count, host->max_req_size / 512));
|
||||||
blk_queue_max_segments(mq->queue, host->max_segs);
|
blk_queue_max_segments(mq->queue, host->max_segs);
|
||||||
|
@ -559,7 +559,7 @@ static void mmc_sdio_resend_if_cond(struct mmc_host *host,
|
|||||||
* we're trying to reinitialise.
|
* we're trying to reinitialise.
|
||||||
*/
|
*/
|
||||||
static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
||||||
struct mmc_card *oldcard, int powered_resume)
|
struct mmc_card *oldcard)
|
||||||
{
|
{
|
||||||
struct mmc_card *card;
|
struct mmc_card *card;
|
||||||
int err;
|
int err;
|
||||||
@ -582,11 +582,9 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
|||||||
/*
|
/*
|
||||||
* Inform the card of the voltage
|
* Inform the card of the voltage
|
||||||
*/
|
*/
|
||||||
if (!powered_resume) {
|
err = mmc_send_io_op_cond(host, ocr, &rocr);
|
||||||
err = mmc_send_io_op_cond(host, ocr, &rocr);
|
if (err)
|
||||||
if (err)
|
goto err;
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For SPI, enable CRC as appropriate.
|
* For SPI, enable CRC as appropriate.
|
||||||
@ -645,7 +643,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
|||||||
* try to init uhs card. sdio_read_cccr will take over this task
|
* try to init uhs card. sdio_read_cccr will take over this task
|
||||||
* to make sure which speed mode should work.
|
* to make sure which speed mode should work.
|
||||||
*/
|
*/
|
||||||
if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
|
if (rocr & ocr & R4_18V_PRESENT) {
|
||||||
err = mmc_set_uhs_voltage(host, ocr_card);
|
err = mmc_set_uhs_voltage(host, ocr_card);
|
||||||
if (err == -EAGAIN) {
|
if (err == -EAGAIN) {
|
||||||
mmc_sdio_resend_if_cond(host, card);
|
mmc_sdio_resend_if_cond(host, card);
|
||||||
@ -659,7 +657,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
|||||||
/*
|
/*
|
||||||
* For native busses: set card RCA and quit open drain mode.
|
* For native busses: set card RCA and quit open drain mode.
|
||||||
*/
|
*/
|
||||||
if (!powered_resume && !mmc_host_is_spi(host)) {
|
if (!mmc_host_is_spi(host)) {
|
||||||
err = mmc_send_relative_addr(host, &card->rca);
|
err = mmc_send_relative_addr(host, &card->rca);
|
||||||
if (err)
|
if (err)
|
||||||
goto remove;
|
goto remove;
|
||||||
@ -687,7 +685,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
|||||||
/*
|
/*
|
||||||
* Select card, as all following commands rely on that.
|
* Select card, as all following commands rely on that.
|
||||||
*/
|
*/
|
||||||
if (!powered_resume && !mmc_host_is_spi(host)) {
|
if (!mmc_host_is_spi(host)) {
|
||||||
err = mmc_select_card(card);
|
err = mmc_select_card(card);
|
||||||
if (err)
|
if (err)
|
||||||
goto remove;
|
goto remove;
|
||||||
@ -816,10 +814,27 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
|
static int mmc_sdio_reinit_card(struct mmc_host *host)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset the card by performing the same steps that are taken by
|
||||||
|
* mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
|
||||||
|
*
|
||||||
|
* sdio_reset() is technically not needed. Having just powered up the
|
||||||
|
* hardware, it should already be in reset state. However, some
|
||||||
|
* platforms (such as SD8686 on OLPC) do not instantly cut power,
|
||||||
|
* meaning that a reset is required when restoring power soon after
|
||||||
|
* powering off. It is harmless in other cases.
|
||||||
|
*
|
||||||
|
* The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
|
||||||
|
* is not necessary for non-removable cards. However, it is required
|
||||||
|
* for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
|
||||||
|
* harmless in other situations.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
sdio_reset(host);
|
sdio_reset(host);
|
||||||
mmc_go_idle(host);
|
mmc_go_idle(host);
|
||||||
mmc_send_if_cond(host, host->card->ocr);
|
mmc_send_if_cond(host, host->card->ocr);
|
||||||
@ -828,8 +843,7 @@ static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return mmc_sdio_init_card(host, host->card->ocr, host->card,
|
return mmc_sdio_init_card(host, host->card->ocr, host->card);
|
||||||
powered_resume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -965,7 +979,11 @@ static int mmc_sdio_resume(struct mmc_host *host)
|
|||||||
/* Basic card reinitialization. */
|
/* Basic card reinitialization. */
|
||||||
mmc_claim_host(host);
|
mmc_claim_host(host);
|
||||||
|
|
||||||
/* Restore power if needed */
|
/*
|
||||||
|
* Restore power and reinitialize the card when needed. Note that a
|
||||||
|
* removable card is checked from a detect work later on in the resume
|
||||||
|
* process.
|
||||||
|
*/
|
||||||
if (!mmc_card_keep_power(host)) {
|
if (!mmc_card_keep_power(host)) {
|
||||||
mmc_power_up(host, host->card->ocr);
|
mmc_power_up(host, host->card->ocr);
|
||||||
/*
|
/*
|
||||||
@ -979,12 +997,8 @@ static int mmc_sdio_resume(struct mmc_host *host)
|
|||||||
pm_runtime_set_active(&host->card->dev);
|
pm_runtime_set_active(&host->card->dev);
|
||||||
pm_runtime_enable(&host->card->dev);
|
pm_runtime_enable(&host->card->dev);
|
||||||
}
|
}
|
||||||
}
|
err = mmc_sdio_reinit_card(host);
|
||||||
|
} else if (mmc_card_wake_sdio_irq(host)) {
|
||||||
/* No need to reinitialize powered-resumed nonremovable cards */
|
|
||||||
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
|
|
||||||
err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
|
|
||||||
} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
|
|
||||||
/* We may have switched to 1-bit mode during suspend */
|
/* We may have switched to 1-bit mode during suspend */
|
||||||
err = sdio_enable_4bit_bus(host->card);
|
err = sdio_enable_4bit_bus(host->card);
|
||||||
}
|
}
|
||||||
@ -1009,38 +1023,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mmc_sdio_power_restore(struct mmc_host *host)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reset the card by performing the same steps that are taken by
|
|
||||||
* mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
|
|
||||||
*
|
|
||||||
* sdio_reset() is technically not needed. Having just powered up the
|
|
||||||
* hardware, it should already be in reset state. However, some
|
|
||||||
* platforms (such as SD8686 on OLPC) do not instantly cut power,
|
|
||||||
* meaning that a reset is required when restoring power soon after
|
|
||||||
* powering off. It is harmless in other cases.
|
|
||||||
*
|
|
||||||
* The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
|
|
||||||
* is not necessary for non-removable cards. However, it is required
|
|
||||||
* for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
|
|
||||||
* harmless in other situations.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
mmc_claim_host(host);
|
|
||||||
|
|
||||||
ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
|
|
||||||
if (!ret && host->sdio_irqs)
|
|
||||||
mmc_signal_sdio_irq(host);
|
|
||||||
|
|
||||||
mmc_release_host(host);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
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. */
|
||||||
@ -1058,7 +1040,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
|
|||||||
/* Restore power and re-initialize. */
|
/* Restore power and re-initialize. */
|
||||||
mmc_claim_host(host);
|
mmc_claim_host(host);
|
||||||
mmc_power_up(host, host->card->ocr);
|
mmc_power_up(host, host->card->ocr);
|
||||||
ret = mmc_sdio_power_restore(host);
|
ret = mmc_sdio_reinit_card(host);
|
||||||
mmc_release_host(host);
|
mmc_release_host(host);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1067,7 +1049,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
|
|||||||
static int mmc_sdio_hw_reset(struct mmc_host *host)
|
static int mmc_sdio_hw_reset(struct mmc_host *host)
|
||||||
{
|
{
|
||||||
mmc_power_cycle(host, host->card->ocr);
|
mmc_power_cycle(host, host->card->ocr);
|
||||||
return mmc_sdio_power_restore(host);
|
return mmc_sdio_reinit_card(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mmc_sdio_sw_reset(struct mmc_host *host)
|
static int mmc_sdio_sw_reset(struct mmc_host *host)
|
||||||
@ -1079,7 +1061,7 @@ static int mmc_sdio_sw_reset(struct mmc_host *host)
|
|||||||
mmc_set_initial_state(host);
|
mmc_set_initial_state(host);
|
||||||
mmc_set_initial_signal_voltage(host);
|
mmc_set_initial_signal_voltage(host);
|
||||||
|
|
||||||
return mmc_sdio_reinit_card(host, 0);
|
return mmc_sdio_reinit_card(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct mmc_bus_ops mmc_sdio_ops = {
|
static const struct mmc_bus_ops mmc_sdio_ops = {
|
||||||
@ -1129,7 +1111,7 @@ int mmc_attach_sdio(struct mmc_host *host)
|
|||||||
/*
|
/*
|
||||||
* Detect and init the card.
|
* Detect and init the card.
|
||||||
*/
|
*/
|
||||||
err = mmc_sdio_init_card(host, rocr, NULL, 0);
|
err = mmc_sdio_init_card(host, rocr, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdio_run_irqs(struct mmc_host *host)
|
static void sdio_run_irqs(struct mmc_host *host)
|
||||||
{
|
{
|
||||||
mmc_claim_host(host);
|
mmc_claim_host(host);
|
||||||
if (host->sdio_irqs) {
|
if (host->sdio_irqs) {
|
||||||
@ -103,7 +103,6 @@ void sdio_run_irqs(struct mmc_host *host)
|
|||||||
}
|
}
|
||||||
mmc_release_host(host);
|
mmc_release_host(host);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sdio_run_irqs);
|
|
||||||
|
|
||||||
void sdio_irq_work(struct work_struct *work)
|
void sdio_irq_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
|
@ -996,7 +996,7 @@ config MMC_SDHCI_OMAP
|
|||||||
|
|
||||||
config MMC_SDHCI_AM654
|
config MMC_SDHCI_AM654
|
||||||
tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
|
tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
|
||||||
depends on MMC_SDHCI_PLTFM && OF
|
depends on MMC_SDHCI_PLTFM && OF && REGMAP_MMIO
|
||||||
select MMC_SDHCI_IO_ACCESSORS
|
select MMC_SDHCI_IO_ACCESSORS
|
||||||
help
|
help
|
||||||
This selects the Secure Digital Host Controller Interface (SDHCI)
|
This selects the Secure Digital Host Controller Interface (SDHCI)
|
||||||
|
@ -672,7 +672,7 @@ static void alcor_set_clock(struct alcor_sdmmc_host *host, unsigned int clock)
|
|||||||
tmp_clock = DIV_ROUND_UP(cfg->clk_src_freq, tmp_div);
|
tmp_clock = DIV_ROUND_UP(cfg->clk_src_freq, tmp_div);
|
||||||
tmp_diff = abs(clock - tmp_clock);
|
tmp_diff = abs(clock - tmp_clock);
|
||||||
|
|
||||||
if (tmp_diff >= 0 && tmp_diff < diff) {
|
if (tmp_diff < diff) {
|
||||||
diff = tmp_diff;
|
diff = tmp_diff;
|
||||||
clk_src = cfg->clk_src_reg;
|
clk_src = cfg->clk_src_reg;
|
||||||
clk_div = tmp_div;
|
clk_div = tmp_div;
|
||||||
|
@ -110,7 +110,6 @@ struct goldfish_mmc_host {
|
|||||||
struct mmc_request *mrq;
|
struct mmc_request *mrq;
|
||||||
struct mmc_command *cmd;
|
struct mmc_command *cmd;
|
||||||
struct mmc_data *data;
|
struct mmc_data *data;
|
||||||
struct mmc_host *mmc;
|
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
unsigned char id; /* 16xx chips have 2 MMC blocks */
|
unsigned char id; /* 16xx chips have 2 MMC blocks */
|
||||||
void *virt_base;
|
void *virt_base;
|
||||||
@ -172,7 +171,7 @@ goldfish_mmc_start_command(struct goldfish_mmc_host *host, struct mmc_command *c
|
|||||||
resptype = 3;
|
resptype = 3;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(mmc_dev(host->mmc),
|
dev_err(mmc_dev(mmc_from_priv(host)),
|
||||||
"Invalid response type: %04x\n", mmc_resp_type(cmd));
|
"Invalid response type: %04x\n", mmc_resp_type(cmd));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -218,8 +217,8 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
|
|||||||
data->sg->length);
|
data->sg->length);
|
||||||
}
|
}
|
||||||
host->data->bytes_xfered += data->sg->length;
|
host->data->bytes_xfered += data->sg->length;
|
||||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
|
dma_unmap_sg(mmc_dev(mmc_from_priv(host)), data->sg,
|
||||||
dma_data_dir);
|
host->sg_len, dma_data_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
host->data = NULL;
|
host->data = NULL;
|
||||||
@ -233,7 +232,7 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
|
|||||||
|
|
||||||
if (!data->stop) {
|
if (!data->stop) {
|
||||||
host->mrq = NULL;
|
host->mrq = NULL;
|
||||||
mmc_request_done(host->mmc, data->mrq);
|
mmc_request_done(mmc_from_priv(host), data->mrq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +274,7 @@ static void goldfish_mmc_cmd_done(struct goldfish_mmc_host *host,
|
|||||||
|
|
||||||
if (host->data == NULL || cmd->error) {
|
if (host->data == NULL || cmd->error) {
|
||||||
host->mrq = NULL;
|
host->mrq = NULL;
|
||||||
mmc_request_done(host->mmc, cmd->mrq);
|
mmc_request_done(mmc_from_priv(host), cmd->mrq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +309,7 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
|
|||||||
struct mmc_request *mrq = host->mrq;
|
struct mmc_request *mrq = host->mrq;
|
||||||
mrq->cmd->error = -ETIMEDOUT;
|
mrq->cmd->error = -ETIMEDOUT;
|
||||||
host->mrq = NULL;
|
host->mrq = NULL;
|
||||||
mmc_request_done(host->mmc, mrq);
|
mmc_request_done(mmc_from_priv(host), mrq);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_command)
|
if (end_command)
|
||||||
@ -336,12 +335,13 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
|
|||||||
u32 state = GOLDFISH_MMC_READ(host, MMC_STATE);
|
u32 state = GOLDFISH_MMC_READ(host, MMC_STATE);
|
||||||
pr_info("%s: Card detect now %d\n", __func__,
|
pr_info("%s: Card detect now %d\n", __func__,
|
||||||
(state & MMC_STATE_INSERTED));
|
(state & MMC_STATE_INSERTED));
|
||||||
mmc_detect_change(host->mmc, 0);
|
mmc_detect_change(mmc_from_priv(host), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!end_command && !end_transfer && !state_changed && !cmd_timeout) {
|
if (!end_command && !end_transfer && !state_changed && !cmd_timeout) {
|
||||||
status = GOLDFISH_MMC_READ(host, MMC_INT_STATUS);
|
status = GOLDFISH_MMC_READ(host, MMC_INT_STATUS);
|
||||||
dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
|
dev_info(mmc_dev(mmc_from_priv(host)), "spurious irq 0x%04x\n",
|
||||||
|
status);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
GOLDFISH_MMC_WRITE(host, MMC_INT_STATUS, status);
|
GOLDFISH_MMC_WRITE(host, MMC_INT_STATUS, status);
|
||||||
GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE, 0);
|
GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE, 0);
|
||||||
@ -380,7 +380,7 @@ static void goldfish_mmc_prepare_data(struct goldfish_mmc_host *host,
|
|||||||
|
|
||||||
dma_data_dir = mmc_get_dma_dir(data);
|
dma_data_dir = mmc_get_dma_dir(data);
|
||||||
|
|
||||||
host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
|
host->sg_len = dma_map_sg(mmc_dev(mmc_from_priv(host)), data->sg,
|
||||||
sg_len, dma_data_dir);
|
sg_len, dma_data_dir);
|
||||||
host->dma_done = 0;
|
host->dma_done = 0;
|
||||||
host->dma_in_use = 1;
|
host->dma_in_use = 1;
|
||||||
@ -458,7 +458,6 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
host = mmc_priv(mmc);
|
host = mmc_priv(mmc);
|
||||||
host->mmc = mmc;
|
|
||||||
|
|
||||||
pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end);
|
pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end);
|
||||||
host->reg_base = ioremap(res->start, resource_size(res));
|
host->reg_base = ioremap(res->start, resource_size(res));
|
||||||
@ -505,8 +504,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
|
ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_warn(mmc_dev(host->mmc),
|
dev_warn(mmc_dev(mmc), "Unable to create sysfs attributes\n");
|
||||||
"Unable to create sysfs attributes\n");
|
|
||||||
|
|
||||||
GOLDFISH_MMC_WRITE(host, MMC_SET_BUFFER, host->phys_base);
|
GOLDFISH_MMC_WRITE(host, MMC_SET_BUFFER, host->phys_base);
|
||||||
GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE,
|
GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE,
|
||||||
@ -522,7 +520,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
|
|||||||
dma_alloc_failed:
|
dma_alloc_failed:
|
||||||
iounmap(host->reg_base);
|
iounmap(host->reg_base);
|
||||||
ioremap_failed:
|
ioremap_failed:
|
||||||
mmc_free_host(host->mmc);
|
mmc_free_host(mmc);
|
||||||
err_alloc_host_failed:
|
err_alloc_host_failed:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -530,14 +528,15 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
|
|||||||
static int goldfish_mmc_remove(struct platform_device *pdev)
|
static int goldfish_mmc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
|
struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
|
||||||
|
struct mmc_host *mmc = mmc_from_priv(host);
|
||||||
|
|
||||||
BUG_ON(host == NULL);
|
BUG_ON(host == NULL);
|
||||||
|
|
||||||
mmc_remove_host(host->mmc);
|
mmc_remove_host(mmc);
|
||||||
free_irq(host->irq, host);
|
free_irq(host->irq, host);
|
||||||
dma_free_coherent(&pdev->dev, BUFFER_SIZE, host->virt_base, host->phys_base);
|
dma_free_coherent(&pdev->dev, BUFFER_SIZE, host->virt_base, host->phys_base);
|
||||||
iounmap(host->reg_base);
|
iounmap(host->reg_base);
|
||||||
mmc_free_host(host->mmc);
|
mmc_free_host(mmc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,42 +576,18 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
|
|||||||
struct mmc_host *mmc = slot->mmc;
|
struct mmc_host *mmc = slot->mmc;
|
||||||
struct atmel_mci *host = slot->host;
|
struct atmel_mci *host = slot->host;
|
||||||
struct dentry *root;
|
struct dentry *root;
|
||||||
struct dentry *node;
|
|
||||||
|
|
||||||
root = mmc->debugfs_root;
|
root = mmc->debugfs_root;
|
||||||
if (!root)
|
if (!root)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
node = debugfs_create_file("regs", S_IRUSR, root, host,
|
debugfs_create_file("regs", S_IRUSR, root, host, &atmci_regs_fops);
|
||||||
&atmci_regs_fops);
|
debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
|
||||||
if (IS_ERR(node))
|
debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
|
||||||
return;
|
debugfs_create_x32("pending_events", S_IRUSR, root,
|
||||||
if (!node)
|
(u32 *)&host->pending_events);
|
||||||
goto err;
|
debugfs_create_x32("completed_events", S_IRUSR, root,
|
||||||
|
(u32 *)&host->completed_events);
|
||||||
node = debugfs_create_file("req", S_IRUSR, root, slot,
|
|
||||||
&atmci_req_fops);
|
|
||||||
if (!node)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
|
|
||||||
if (!node)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
node = debugfs_create_x32("pending_events", S_IRUSR, root,
|
|
||||||
(u32 *)&host->pending_events);
|
|
||||||
if (!node)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
node = debugfs_create_x32("completed_events", S_IRUSR, root,
|
|
||||||
(u32 *)&host->completed_events);
|
|
||||||
if (!node)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
err:
|
|
||||||
dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_OF)
|
#if defined(CONFIG_OF)
|
||||||
|
@ -169,40 +169,18 @@ static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
|
|||||||
struct mmc_host *mmc = slot->mmc;
|
struct mmc_host *mmc = slot->mmc;
|
||||||
struct dw_mci *host = slot->host;
|
struct dw_mci *host = slot->host;
|
||||||
struct dentry *root;
|
struct dentry *root;
|
||||||
struct dentry *node;
|
|
||||||
|
|
||||||
root = mmc->debugfs_root;
|
root = mmc->debugfs_root;
|
||||||
if (!root)
|
if (!root)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
node = debugfs_create_file("regs", S_IRUSR, root, host,
|
debugfs_create_file("regs", S_IRUSR, root, host, &dw_mci_regs_fops);
|
||||||
&dw_mci_regs_fops);
|
debugfs_create_file("req", S_IRUSR, root, slot, &dw_mci_req_fops);
|
||||||
if (!node)
|
debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
|
||||||
goto err;
|
debugfs_create_x32("pending_events", S_IRUSR, root,
|
||||||
|
(u32 *)&host->pending_events);
|
||||||
node = debugfs_create_file("req", S_IRUSR, root, slot,
|
debugfs_create_x32("completed_events", S_IRUSR, root,
|
||||||
&dw_mci_req_fops);
|
(u32 *)&host->completed_events);
|
||||||
if (!node)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
|
|
||||||
if (!node)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
node = debugfs_create_x32("pending_events", S_IRUSR, root,
|
|
||||||
(u32 *)&host->pending_events);
|
|
||||||
if (!node)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
node = debugfs_create_x32("completed_events", S_IRUSR, root,
|
|
||||||
(u32 *)&host->completed_events);
|
|
||||||
if (!node)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
err:
|
|
||||||
dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
|
|
||||||
}
|
}
|
||||||
#endif /* defined(CONFIG_DEBUG_FS) */
|
#endif /* defined(CONFIG_DEBUG_FS) */
|
||||||
|
|
||||||
|
@ -116,6 +116,9 @@
|
|||||||
#define SD_EMMC_TXD 0x94
|
#define SD_EMMC_TXD 0x94
|
||||||
#define SD_EMMC_LAST_REG SD_EMMC_TXD
|
#define SD_EMMC_LAST_REG SD_EMMC_TXD
|
||||||
|
|
||||||
|
#define SD_EMMC_SRAM_DATA_BUF_LEN 1536
|
||||||
|
#define SD_EMMC_SRAM_DATA_BUF_OFF 0x200
|
||||||
|
|
||||||
#define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */
|
#define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */
|
||||||
#define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */
|
#define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */
|
||||||
#define SD_EMMC_CMD_TIMEOUT 1024 /* in ms */
|
#define SD_EMMC_CMD_TIMEOUT 1024 /* in ms */
|
||||||
@ -155,6 +158,8 @@ struct meson_host {
|
|||||||
unsigned long req_rate;
|
unsigned long req_rate;
|
||||||
bool ddr;
|
bool ddr;
|
||||||
|
|
||||||
|
bool dram_access_quirk;
|
||||||
|
|
||||||
struct pinctrl *pinctrl;
|
struct pinctrl *pinctrl;
|
||||||
struct pinctrl_state *pins_default;
|
struct pinctrl_state *pins_default;
|
||||||
struct pinctrl_state *pins_clk_gate;
|
struct pinctrl_state *pins_clk_gate;
|
||||||
@ -219,11 +224,20 @@ static struct mmc_command *meson_mmc_get_next_command(struct mmc_command *cmd)
|
|||||||
static void meson_mmc_get_transfer_mode(struct mmc_host *mmc,
|
static void meson_mmc_get_transfer_mode(struct mmc_host *mmc,
|
||||||
struct mmc_request *mrq)
|
struct mmc_request *mrq)
|
||||||
{
|
{
|
||||||
|
struct meson_host *host = mmc_priv(mmc);
|
||||||
struct mmc_data *data = mrq->data;
|
struct mmc_data *data = mrq->data;
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
int i;
|
int i;
|
||||||
bool use_desc_chain_mode = true;
|
bool use_desc_chain_mode = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When Controller DMA cannot directly access DDR memory, disable
|
||||||
|
* support for Chain Mode to directly use the internal SRAM using
|
||||||
|
* the bounce buffer mode.
|
||||||
|
*/
|
||||||
|
if (host->dram_access_quirk)
|
||||||
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been
|
* Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been
|
||||||
* reported. For some strange reason this occurs in descriptor
|
* reported. For some strange reason this occurs in descriptor
|
||||||
@ -1036,6 +1050,10 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
|||||||
host->dev = &pdev->dev;
|
host->dev = &pdev->dev;
|
||||||
dev_set_drvdata(&pdev->dev, host);
|
dev_set_drvdata(&pdev->dev, host);
|
||||||
|
|
||||||
|
/* The G12A SDIO Controller needs an SRAM bounce buffer */
|
||||||
|
host->dram_access_quirk = device_property_read_bool(&pdev->dev,
|
||||||
|
"amlogic,dram-access-quirk");
|
||||||
|
|
||||||
/* Get regulators and the supported OCR mask */
|
/* Get regulators and the supported OCR mask */
|
||||||
host->vqmmc_enabled = false;
|
host->vqmmc_enabled = false;
|
||||||
ret = mmc_regulator_get_supply(mmc);
|
ret = mmc_regulator_get_supply(mmc);
|
||||||
@ -1133,9 +1151,16 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
|||||||
goto err_init_clk;
|
goto err_init_clk;
|
||||||
|
|
||||||
mmc->caps |= MMC_CAP_CMD23;
|
mmc->caps |= MMC_CAP_CMD23;
|
||||||
mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
|
if (host->dram_access_quirk) {
|
||||||
|
/* Limit to the available sram memory */
|
||||||
|
mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size;
|
||||||
|
mmc->max_blk_count = mmc->max_segs;
|
||||||
|
} else {
|
||||||
|
mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
|
||||||
|
mmc->max_segs = SD_EMMC_DESC_BUF_LEN /
|
||||||
|
sizeof(struct sd_emmc_desc);
|
||||||
|
}
|
||||||
mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
|
mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
|
||||||
mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc);
|
|
||||||
mmc->max_seg_size = mmc->max_req_size;
|
mmc->max_seg_size = mmc->max_req_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1145,15 +1170,27 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
|||||||
*/
|
*/
|
||||||
mmc->caps2 &= ~MMC_CAP2_HS400;
|
mmc->caps2 &= ~MMC_CAP2_HS400;
|
||||||
|
|
||||||
/* data bounce buffer */
|
if (host->dram_access_quirk) {
|
||||||
host->bounce_buf_size = mmc->max_req_size;
|
/*
|
||||||
host->bounce_buf =
|
* The MMC Controller embeds 1,5KiB of internal SRAM
|
||||||
dma_alloc_coherent(host->dev, host->bounce_buf_size,
|
* that can be used to be used as bounce buffer.
|
||||||
&host->bounce_dma_addr, GFP_KERNEL);
|
* In the case of the G12A SDIO controller, use these
|
||||||
if (host->bounce_buf == NULL) {
|
* instead of the DDR memory
|
||||||
dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
|
*/
|
||||||
ret = -ENOMEM;
|
host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN;
|
||||||
goto err_free_irq;
|
host->bounce_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
|
||||||
|
host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF;
|
||||||
|
} else {
|
||||||
|
/* data bounce buffer */
|
||||||
|
host->bounce_buf_size = mmc->max_req_size;
|
||||||
|
host->bounce_buf =
|
||||||
|
dma_alloc_coherent(host->dev, host->bounce_buf_size,
|
||||||
|
&host->bounce_dma_addr, GFP_KERNEL);
|
||||||
|
if (host->bounce_buf == NULL) {
|
||||||
|
dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_free_irq;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
|
host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
|
||||||
@ -1170,8 +1207,9 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_bounce_buf:
|
err_bounce_buf:
|
||||||
dma_free_coherent(host->dev, host->bounce_buf_size,
|
if (!host->dram_access_quirk)
|
||||||
host->bounce_buf, host->bounce_dma_addr);
|
dma_free_coherent(host->dev, host->bounce_buf_size,
|
||||||
|
host->bounce_buf, host->bounce_dma_addr);
|
||||||
err_free_irq:
|
err_free_irq:
|
||||||
free_irq(host->irq, host);
|
free_irq(host->irq, host);
|
||||||
err_init_clk:
|
err_init_clk:
|
||||||
@ -1195,8 +1233,10 @@ static int meson_mmc_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
|
dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
|
||||||
host->descs, host->descs_dma_addr);
|
host->descs, host->descs_dma_addr);
|
||||||
dma_free_coherent(host->dev, host->bounce_buf_size,
|
|
||||||
host->bounce_buf, host->bounce_dma_addr);
|
if (!host->dram_access_quirk)
|
||||||
|
dma_free_coherent(host->dev, host->bounce_buf_size,
|
||||||
|
host->bounce_buf, host->bounce_dma_addr);
|
||||||
|
|
||||||
clk_disable_unprepare(host->mmc_clk);
|
clk_disable_unprepare(host->mmc_clk);
|
||||||
clk_disable_unprepare(host->core_clk);
|
clk_disable_unprepare(host->core_clk);
|
||||||
|
@ -610,13 +610,12 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
|
|||||||
renesas_sdhi_sdbuf_width(host, enable ? width : 16);
|
renesas_sdhi_sdbuf_width(host, enable ? width : 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct renesas_sdhi_quirks sdhi_quirks_h3_m3w_es1 = {
|
static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400 = {
|
||||||
.hs400_disabled = true,
|
.hs400_disabled = true,
|
||||||
.hs400_4taps = true,
|
.hs400_4taps = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct renesas_sdhi_quirks sdhi_quirks_h3_es2 = {
|
static const struct renesas_sdhi_quirks sdhi_quirks_4tap = {
|
||||||
.hs400_disabled = false,
|
|
||||||
.hs400_4taps = true,
|
.hs400_4taps = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -625,10 +624,10 @@ static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct soc_device_attribute sdhi_quirks_match[] = {
|
static const struct soc_device_attribute sdhi_quirks_match[] = {
|
||||||
{ .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_h3_m3w_es1 },
|
{ .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400 },
|
||||||
{ .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_h3_es2 },
|
{ .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap },
|
||||||
{ .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_h3_m3w_es1 },
|
{ .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
|
||||||
{ .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_h3_m3w_es1 },
|
{ .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
|
||||||
{ .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 },
|
{ .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 },
|
||||||
{ /* Sentinel. */ },
|
{ /* Sentinel. */ },
|
||||||
};
|
};
|
||||||
@ -775,6 +774,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|||||||
/* All SDHI have SDIO status bits which must be 1 */
|
/* All SDHI have SDIO status bits which must be 1 */
|
||||||
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
|
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
|
||||||
|
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
ret = renesas_sdhi_clk_enable(host);
|
ret = renesas_sdhi_clk_enable(host);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto efree;
|
goto efree;
|
||||||
@ -855,6 +856,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|||||||
efree:
|
efree:
|
||||||
tmio_mmc_host_free(host);
|
tmio_mmc_host_free(host);
|
||||||
|
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
|
EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
|
||||||
@ -866,6 +869,8 @@ int renesas_sdhi_remove(struct platform_device *pdev)
|
|||||||
tmio_mmc_host_remove(host);
|
tmio_mmc_host_remove(host);
|
||||||
renesas_sdhi_clk_disable(host);
|
renesas_sdhi_clk_disable(host);
|
||||||
|
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
|
EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
|
||||||
|
@ -1449,33 +1449,18 @@ DEFINE_SHOW_ATTRIBUTE(s3cmci_regs);
|
|||||||
static void s3cmci_debugfs_attach(struct s3cmci_host *host)
|
static void s3cmci_debugfs_attach(struct s3cmci_host *host)
|
||||||
{
|
{
|
||||||
struct device *dev = &host->pdev->dev;
|
struct device *dev = &host->pdev->dev;
|
||||||
|
struct dentry *root;
|
||||||
|
|
||||||
host->debug_root = debugfs_create_dir(dev_name(dev), NULL);
|
root = debugfs_create_dir(dev_name(dev), NULL);
|
||||||
if (IS_ERR(host->debug_root)) {
|
host->debug_root = root;
|
||||||
dev_err(dev, "failed to create debugfs root\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
host->debug_state = debugfs_create_file("state", 0444,
|
debugfs_create_file("state", 0444, root, host, &s3cmci_state_fops);
|
||||||
host->debug_root, host,
|
debugfs_create_file("regs", 0444, root, host, &s3cmci_regs_fops);
|
||||||
&s3cmci_state_fops);
|
|
||||||
|
|
||||||
if (IS_ERR(host->debug_state))
|
|
||||||
dev_err(dev, "failed to create debug state file\n");
|
|
||||||
|
|
||||||
host->debug_regs = debugfs_create_file("regs", 0444,
|
|
||||||
host->debug_root, host,
|
|
||||||
&s3cmci_regs_fops);
|
|
||||||
|
|
||||||
if (IS_ERR(host->debug_regs))
|
|
||||||
dev_err(dev, "failed to create debug regs file\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s3cmci_debugfs_remove(struct s3cmci_host *host)
|
static void s3cmci_debugfs_remove(struct s3cmci_host *host)
|
||||||
{
|
{
|
||||||
debugfs_remove(host->debug_regs);
|
debugfs_remove_recursive(host->debug_root);
|
||||||
debugfs_remove(host->debug_state);
|
|
||||||
debugfs_remove(host->debug_root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -67,8 +67,6 @@ struct s3cmci_host {
|
|||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
struct dentry *debug_root;
|
struct dentry *debug_root;
|
||||||
struct dentry *debug_state;
|
|
||||||
struct dentry *debug_regs;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
|
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
|
||||||
|
@ -575,11 +575,14 @@ static int msm_init_cm_dll(struct sdhci_host *host)
|
|||||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||||
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||||
int wait_cnt = 50;
|
int wait_cnt = 50;
|
||||||
unsigned long flags;
|
unsigned long flags, xo_clk = 0;
|
||||||
u32 config;
|
u32 config;
|
||||||
const struct sdhci_msm_offset *msm_offset =
|
const struct sdhci_msm_offset *msm_offset =
|
||||||
msm_host->offset;
|
msm_host->offset;
|
||||||
|
|
||||||
|
if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk))
|
||||||
|
xo_clk = clk_get_rate(msm_host->xo_clk);
|
||||||
|
|
||||||
spin_lock_irqsave(&host->lock, flags);
|
spin_lock_irqsave(&host->lock, flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -627,10 +630,10 @@ static int msm_init_cm_dll(struct sdhci_host *host)
|
|||||||
config &= CORE_FLL_CYCLE_CNT;
|
config &= CORE_FLL_CYCLE_CNT;
|
||||||
if (config)
|
if (config)
|
||||||
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
|
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
|
||||||
clk_get_rate(msm_host->xo_clk));
|
xo_clk);
|
||||||
else
|
else
|
||||||
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
|
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
|
||||||
clk_get_rate(msm_host->xo_clk));
|
xo_clk);
|
||||||
|
|
||||||
config = readl_relaxed(host->ioaddr +
|
config = readl_relaxed(host->ioaddr +
|
||||||
msm_offset->core_dll_config_2);
|
msm_offset->core_dll_config_2);
|
||||||
|
@ -830,9 +830,17 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||||
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
|
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
|
||||||
bool hs400_tuning;
|
bool hs400_tuning;
|
||||||
|
unsigned int clk;
|
||||||
u32 val;
|
u32 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* For tuning mode, the sd clock divisor value
|
||||||
|
* must be larger than 3 according to reference manual.
|
||||||
|
*/
|
||||||
|
clk = esdhc->peripheral_clock / 3;
|
||||||
|
if (host->clock > clk)
|
||||||
|
esdhc_of_set_clock(host, clk);
|
||||||
|
|
||||||
if (esdhc->quirk_limited_clk_division &&
|
if (esdhc->quirk_limited_clk_division &&
|
||||||
host->flags & SDHCI_HS400_TUNING)
|
host->flags & SDHCI_HS400_TUNING)
|
||||||
esdhc_of_set_clock(host, host->clock);
|
esdhc_of_set_clock(host, host->clock);
|
||||||
@ -1040,11 +1048,12 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
|
|||||||
/*
|
/*
|
||||||
* esdhc->peripheral_clock would be assigned with a value
|
* esdhc->peripheral_clock would be assigned with a value
|
||||||
* which is eSDHC base clock when use periperal clock.
|
* which is eSDHC base clock when use periperal clock.
|
||||||
* For ls1046a, the clock value got by common clk API is
|
* For some platforms, the clock value got by common clk
|
||||||
* peripheral clock while the eSDHC base clock is 1/2
|
* API is peripheral clock while the eSDHC base clock is
|
||||||
* peripheral clock.
|
* 1/2 peripheral clock.
|
||||||
*/
|
*/
|
||||||
if (of_device_is_compatible(np, "fsl,ls1046a-esdhc"))
|
if (of_device_is_compatible(np, "fsl,ls1046a-esdhc") ||
|
||||||
|
of_device_is_compatible(np, "fsl,ls1028a-esdhc"))
|
||||||
esdhc->peripheral_clock = clk_get_rate(clk) / 2;
|
esdhc->peripheral_clock = clk_get_rate(clk) / 2;
|
||||||
else
|
else
|
||||||
esdhc->peripheral_clock = clk_get_rate(clk);
|
esdhc->peripheral_clock = clk_get_rate(clk);
|
||||||
|
@ -1668,6 +1668,8 @@ static const struct pci_device_id pci_ids[] = {
|
|||||||
SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd),
|
SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd),
|
||||||
SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc),
|
SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc),
|
||||||
SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd),
|
SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd),
|
||||||
|
SDHCI_PCI_DEVICE(INTEL, EHL_EMMC, intel_glk_emmc),
|
||||||
|
SDHCI_PCI_DEVICE(INTEL, EHL_SD, intel_byt_sd),
|
||||||
SDHCI_PCI_DEVICE(INTEL, CML_EMMC, intel_glk_emmc),
|
SDHCI_PCI_DEVICE(INTEL, CML_EMMC, intel_glk_emmc),
|
||||||
SDHCI_PCI_DEVICE(INTEL, CML_SD, intel_byt_sd),
|
SDHCI_PCI_DEVICE(INTEL, CML_SD, intel_byt_sd),
|
||||||
SDHCI_PCI_DEVICE(O2, 8120, o2),
|
SDHCI_PCI_DEVICE(O2, 8120, o2),
|
||||||
@ -2040,8 +2042,6 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
|
|||||||
|
|
||||||
slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
|
slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
|
||||||
dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
|
dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
|
||||||
if (slots == 0)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
BUG_ON(slots > MAX_SLOTS);
|
BUG_ON(slots > MAX_SLOTS);
|
||||||
|
|
||||||
|
@ -395,11 +395,21 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
|
|||||||
{
|
{
|
||||||
struct sdhci_pci_chip *chip;
|
struct sdhci_pci_chip *chip;
|
||||||
struct sdhci_host *host;
|
struct sdhci_host *host;
|
||||||
u32 reg;
|
u32 reg, caps;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
chip = slot->chip;
|
chip = slot->chip;
|
||||||
host = slot->host;
|
host = slot->host;
|
||||||
|
|
||||||
|
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mmc_select_bus_width() will test the bus to determine the actual bus
|
||||||
|
* width.
|
||||||
|
*/
|
||||||
|
if (caps & SDHCI_CAN_DO_8BIT)
|
||||||
|
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
|
||||||
|
|
||||||
switch (chip->pdev->device) {
|
switch (chip->pdev->device) {
|
||||||
case PCI_DEVICE_ID_O2_SDS0:
|
case PCI_DEVICE_ID_O2_SDS0:
|
||||||
case PCI_DEVICE_ID_O2_SEABIRD0:
|
case PCI_DEVICE_ID_O2_SEABIRD0:
|
||||||
|
@ -50,6 +50,8 @@
|
|||||||
#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375
|
#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375
|
||||||
#define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4
|
#define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4
|
||||||
#define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8
|
#define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8
|
||||||
|
#define PCI_DEVICE_ID_INTEL_EHL_EMMC 0x4b47
|
||||||
|
#define PCI_DEVICE_ID_INTEL_EHL_SD 0x4b48
|
||||||
#define PCI_DEVICE_ID_INTEL_CML_EMMC 0x02c4
|
#define PCI_DEVICE_ID_INTEL_CML_EMMC 0x02c4
|
||||||
#define PCI_DEVICE_ID_INTEL_CML_SD 0x02f5
|
#define PCI_DEVICE_ID_INTEL_CML_SD 0x02f5
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
@ -22,6 +23,15 @@
|
|||||||
/* SDHCI_ARGUMENT2 register high 16bit */
|
/* SDHCI_ARGUMENT2 register high 16bit */
|
||||||
#define SDHCI_SPRD_ARG2_STUFF GENMASK(31, 16)
|
#define SDHCI_SPRD_ARG2_STUFF GENMASK(31, 16)
|
||||||
|
|
||||||
|
#define SDHCI_SPRD_REG_32_DLL_CFG 0x200
|
||||||
|
#define SDHCI_SPRD_DLL_ALL_CPST_EN (BIT(18) | BIT(24) | BIT(25) | BIT(26) | BIT(27))
|
||||||
|
#define SDHCI_SPRD_DLL_EN BIT(21)
|
||||||
|
#define SDHCI_SPRD_DLL_SEARCH_MODE BIT(16)
|
||||||
|
#define SDHCI_SPRD_DLL_INIT_COUNT 0xc00
|
||||||
|
#define SDHCI_SPRD_DLL_PHASE_INTERNAL 0x3
|
||||||
|
|
||||||
|
#define SDHCI_SPRD_REG_32_DLL_DLY 0x204
|
||||||
|
|
||||||
#define SDHCI_SPRD_REG_32_DLL_DLY_OFFSET 0x208
|
#define SDHCI_SPRD_REG_32_DLL_DLY_OFFSET 0x208
|
||||||
#define SDHCIBSPRD_IT_WR_DLY_INV BIT(5)
|
#define SDHCIBSPRD_IT_WR_DLY_INV BIT(5)
|
||||||
#define SDHCI_SPRD_BIT_CMD_DLY_INV BIT(13)
|
#define SDHCI_SPRD_BIT_CMD_DLY_INV BIT(13)
|
||||||
@ -41,6 +51,7 @@
|
|||||||
/* SDHCI_HOST_CONTROL2 */
|
/* SDHCI_HOST_CONTROL2 */
|
||||||
#define SDHCI_SPRD_CTRL_HS200 0x0005
|
#define SDHCI_SPRD_CTRL_HS200 0x0005
|
||||||
#define SDHCI_SPRD_CTRL_HS400 0x0006
|
#define SDHCI_SPRD_CTRL_HS400 0x0006
|
||||||
|
#define SDHCI_SPRD_CTRL_HS400ES 0x0007
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* According to the standard specification, BIT(3) of SDHCI_SOFTWARE_RESET is
|
* According to the standard specification, BIT(3) of SDHCI_SOFTWARE_RESET is
|
||||||
@ -55,13 +66,36 @@
|
|||||||
#define SDHCI_SPRD_CLK_MAX_DIV 1023
|
#define SDHCI_SPRD_CLK_MAX_DIV 1023
|
||||||
|
|
||||||
#define SDHCI_SPRD_CLK_DEF_RATE 26000000
|
#define SDHCI_SPRD_CLK_DEF_RATE 26000000
|
||||||
|
#define SDHCI_SPRD_PHY_DLL_CLK 52000000
|
||||||
|
|
||||||
struct sdhci_sprd_host {
|
struct sdhci_sprd_host {
|
||||||
u32 version;
|
u32 version;
|
||||||
struct clk *clk_sdio;
|
struct clk *clk_sdio;
|
||||||
struct clk *clk_enable;
|
struct clk *clk_enable;
|
||||||
|
struct clk *clk_2x_enable;
|
||||||
|
struct pinctrl *pinctrl;
|
||||||
|
struct pinctrl_state *pins_uhs;
|
||||||
|
struct pinctrl_state *pins_default;
|
||||||
u32 base_rate;
|
u32 base_rate;
|
||||||
int flags; /* backup of host attribute */
|
int flags; /* backup of host attribute */
|
||||||
|
u32 phy_delay[MMC_TIMING_MMC_HS400 + 2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdhci_sprd_phy_cfg {
|
||||||
|
const char *property;
|
||||||
|
u8 timing;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sdhci_sprd_phy_cfg sdhci_sprd_phy_cfgs[] = {
|
||||||
|
{ "sprd,phy-delay-legacy", MMC_TIMING_LEGACY, },
|
||||||
|
{ "sprd,phy-delay-sd-highspeed", MMC_TIMING_SD_HS, },
|
||||||
|
{ "sprd,phy-delay-sd-uhs-sdr50", MMC_TIMING_UHS_SDR50, },
|
||||||
|
{ "sprd,phy-delay-sd-uhs-sdr104", MMC_TIMING_UHS_SDR104, },
|
||||||
|
{ "sprd,phy-delay-mmc-highspeed", MMC_TIMING_MMC_HS, },
|
||||||
|
{ "sprd,phy-delay-mmc-ddr52", MMC_TIMING_MMC_DDR52, },
|
||||||
|
{ "sprd,phy-delay-mmc-hs200", MMC_TIMING_MMC_HS200, },
|
||||||
|
{ "sprd,phy-delay-mmc-hs400", MMC_TIMING_MMC_HS400, },
|
||||||
|
{ "sprd,phy-delay-mmc-hs400es", MMC_TIMING_MMC_HS400 + 1, },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TO_SPRD_HOST(host) sdhci_pltfm_priv(sdhci_priv(host))
|
#define TO_SPRD_HOST(host) sdhci_pltfm_priv(sdhci_priv(host))
|
||||||
@ -131,6 +165,15 @@ static inline void sdhci_sprd_sd_clk_off(struct sdhci_host *host)
|
|||||||
sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
|
sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void sdhci_sprd_sd_clk_on(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
u16 ctrl;
|
||||||
|
|
||||||
|
ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||||
|
ctrl |= SDHCI_CLOCK_CARD_EN;
|
||||||
|
sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
sdhci_sprd_set_dll_invert(struct sdhci_host *host, u32 mask, bool en)
|
sdhci_sprd_set_dll_invert(struct sdhci_host *host, u32 mask, bool en)
|
||||||
{
|
{
|
||||||
@ -189,9 +232,33 @@ static inline void _sdhci_sprd_set_clock(struct sdhci_host *host,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sdhci_sprd_enable_phy_dll(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
|
||||||
|
tmp &= ~(SDHCI_SPRD_DLL_EN | SDHCI_SPRD_DLL_ALL_CPST_EN);
|
||||||
|
sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
|
||||||
|
/* wait 1ms */
|
||||||
|
usleep_range(1000, 1250);
|
||||||
|
|
||||||
|
tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
|
||||||
|
tmp |= SDHCI_SPRD_DLL_ALL_CPST_EN | SDHCI_SPRD_DLL_SEARCH_MODE |
|
||||||
|
SDHCI_SPRD_DLL_INIT_COUNT | SDHCI_SPRD_DLL_PHASE_INTERNAL;
|
||||||
|
sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
|
||||||
|
/* wait 1ms */
|
||||||
|
usleep_range(1000, 1250);
|
||||||
|
|
||||||
|
tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
|
||||||
|
tmp |= SDHCI_SPRD_DLL_EN;
|
||||||
|
sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
|
||||||
|
/* wait 1ms */
|
||||||
|
usleep_range(1000, 1250);
|
||||||
|
}
|
||||||
|
|
||||||
static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
|
static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||||
{
|
{
|
||||||
bool en = false;
|
bool en = false, clk_changed = false;
|
||||||
|
|
||||||
if (clock == 0) {
|
if (clock == 0) {
|
||||||
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
|
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
|
||||||
@ -203,9 +270,19 @@ static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
|
|||||||
en = true;
|
en = true;
|
||||||
sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV |
|
sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV |
|
||||||
SDHCI_SPRD_BIT_POSRD_DLY_INV, en);
|
SDHCI_SPRD_BIT_POSRD_DLY_INV, en);
|
||||||
|
clk_changed = true;
|
||||||
} else {
|
} else {
|
||||||
_sdhci_sprd_set_clock(host, clock);
|
_sdhci_sprd_set_clock(host, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* According to the Spreadtrum SD host specification, when we changed
|
||||||
|
* the clock to be more than 52M, we should enable the PHY DLL which
|
||||||
|
* is used to track the clock frequency to make the clock work more
|
||||||
|
* stable. Otherwise deviation may occur of the higher clock.
|
||||||
|
*/
|
||||||
|
if (clk_changed && clock > SDHCI_SPRD_PHY_DLL_CLK)
|
||||||
|
sdhci_sprd_enable_phy_dll(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int sdhci_sprd_get_max_clock(struct sdhci_host *host)
|
static unsigned int sdhci_sprd_get_max_clock(struct sdhci_host *host)
|
||||||
@ -223,6 +300,9 @@ static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host)
|
|||||||
static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
|
static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
|
||||||
unsigned int timing)
|
unsigned int timing)
|
||||||
{
|
{
|
||||||
|
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
|
||||||
|
struct mmc_host *mmc = host->mmc;
|
||||||
|
u32 *p = sprd_host->phy_delay;
|
||||||
u16 ctrl_2;
|
u16 ctrl_2;
|
||||||
|
|
||||||
if (timing == host->timing)
|
if (timing == host->timing)
|
||||||
@ -261,6 +341,9 @@ static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
||||||
|
|
||||||
|
if (!mmc->ios.enhanced_strobe)
|
||||||
|
sdhci_writel(host, p[timing], SDHCI_SPRD_REG_32_DLL_DLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdhci_sprd_hw_reset(struct sdhci_host *host)
|
static void sdhci_sprd_hw_reset(struct sdhci_host *host)
|
||||||
@ -284,6 +367,12 @@ static void sdhci_sprd_hw_reset(struct sdhci_host *host)
|
|||||||
usleep_range(300, 500);
|
usleep_range(300, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int sdhci_sprd_get_max_timeout_count(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
/* The Spredtrum controller actual maximum timeout count is 1 << 31 */
|
||||||
|
return 1 << 31;
|
||||||
|
}
|
||||||
|
|
||||||
static struct sdhci_ops sdhci_sprd_ops = {
|
static struct sdhci_ops sdhci_sprd_ops = {
|
||||||
.read_l = sdhci_sprd_readl,
|
.read_l = sdhci_sprd_readl,
|
||||||
.write_l = sdhci_sprd_writel,
|
.write_l = sdhci_sprd_writel,
|
||||||
@ -295,6 +384,7 @@ static struct sdhci_ops sdhci_sprd_ops = {
|
|||||||
.reset = sdhci_reset,
|
.reset = sdhci_reset,
|
||||||
.set_uhs_signaling = sdhci_sprd_set_uhs_signaling,
|
.set_uhs_signaling = sdhci_sprd_set_uhs_signaling,
|
||||||
.hw_reset = sdhci_sprd_hw_reset,
|
.hw_reset = sdhci_sprd_hw_reset,
|
||||||
|
.get_max_timeout_count = sdhci_sprd_get_max_timeout_count,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||||
@ -317,6 +407,99 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||||||
sdhci_request(mmc, mrq);
|
sdhci_request(mmc, mrq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||||
|
{
|
||||||
|
struct sdhci_host *host = mmc_priv(mmc);
|
||||||
|
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!IS_ERR(mmc->supply.vqmmc)) {
|
||||||
|
ret = mmc_regulator_set_vqmmc(mmc, ios);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: Switching signalling voltage failed\n",
|
||||||
|
mmc_hostname(mmc));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ERR(sprd_host->pinctrl))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (ios->signal_voltage) {
|
||||||
|
case MMC_SIGNAL_VOLTAGE_180:
|
||||||
|
ret = pinctrl_select_state(sprd_host->pinctrl,
|
||||||
|
sprd_host->pins_uhs);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: failed to select uhs pin state\n",
|
||||||
|
mmc_hostname(mmc));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* fall-through */
|
||||||
|
case MMC_SIGNAL_VOLTAGE_330:
|
||||||
|
ret = pinctrl_select_state(sprd_host->pinctrl,
|
||||||
|
sprd_host->pins_default);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: failed to select default pin state\n",
|
||||||
|
mmc_hostname(mmc));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for 300 ~ 500 us for pin state stable */
|
||||||
|
usleep_range(300, 500);
|
||||||
|
sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdhci_sprd_hs400_enhanced_strobe(struct mmc_host *mmc,
|
||||||
|
struct mmc_ios *ios)
|
||||||
|
{
|
||||||
|
struct sdhci_host *host = mmc_priv(mmc);
|
||||||
|
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
|
||||||
|
u32 *p = sprd_host->phy_delay;
|
||||||
|
u16 ctrl_2;
|
||||||
|
|
||||||
|
if (!ios->enhanced_strobe)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sdhci_sprd_sd_clk_off(host);
|
||||||
|
|
||||||
|
/* Set HS400 enhanced strobe mode */
|
||||||
|
ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||||
|
ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
|
||||||
|
ctrl_2 |= SDHCI_SPRD_CTRL_HS400ES;
|
||||||
|
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
||||||
|
|
||||||
|
sdhci_sprd_sd_clk_on(host);
|
||||||
|
|
||||||
|
/* Set the PHY DLL delay value for HS400 enhanced strobe mode */
|
||||||
|
sdhci_writel(host, p[MMC_TIMING_MMC_HS400 + 1],
|
||||||
|
SDHCI_SPRD_REG_32_DLL_DLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdhci_sprd_phy_param_parse(struct sdhci_sprd_host *sprd_host,
|
||||||
|
struct device_node *np)
|
||||||
|
{
|
||||||
|
u32 *p = sprd_host->phy_delay;
|
||||||
|
int ret, i, index;
|
||||||
|
u32 val[4];
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(sdhci_sprd_phy_cfgs); i++) {
|
||||||
|
ret = of_property_read_u32_array(np,
|
||||||
|
sdhci_sprd_phy_cfgs[i].property, val, 4);
|
||||||
|
if (ret)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
index = sdhci_sprd_phy_cfgs[i].timing;
|
||||||
|
p[index] = val[0] | (val[1] << 8) | (val[2] << 16) | (val[3] << 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const struct sdhci_pltfm_data sdhci_sprd_pdata = {
|
static const struct sdhci_pltfm_data sdhci_sprd_pdata = {
|
||||||
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
|
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
|
||||||
.quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |
|
.quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |
|
||||||
@ -338,6 +521,16 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
|||||||
host->dma_mask = DMA_BIT_MASK(64);
|
host->dma_mask = DMA_BIT_MASK(64);
|
||||||
pdev->dev.dma_mask = &host->dma_mask;
|
pdev->dev.dma_mask = &host->dma_mask;
|
||||||
host->mmc_host_ops.request = sdhci_sprd_request;
|
host->mmc_host_ops.request = sdhci_sprd_request;
|
||||||
|
host->mmc_host_ops.hs400_enhanced_strobe =
|
||||||
|
sdhci_sprd_hs400_enhanced_strobe;
|
||||||
|
/*
|
||||||
|
* We can not use the standard ops to change and detect the voltage
|
||||||
|
* signal for Spreadtrum SD host controller, since our voltage regulator
|
||||||
|
* for I/O is fixed in hardware, that means we do not need control
|
||||||
|
* the standard SD host controller to change the I/O voltage.
|
||||||
|
*/
|
||||||
|
host->mmc_host_ops.start_signal_voltage_switch =
|
||||||
|
sdhci_sprd_voltage_switch;
|
||||||
|
|
||||||
host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
|
host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
|
||||||
MMC_CAP_ERASE | MMC_CAP_CMD23;
|
MMC_CAP_ERASE | MMC_CAP_CMD23;
|
||||||
@ -346,6 +539,24 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
|||||||
goto pltfm_free;
|
goto pltfm_free;
|
||||||
|
|
||||||
sprd_host = TO_SPRD_HOST(host);
|
sprd_host = TO_SPRD_HOST(host);
|
||||||
|
sdhci_sprd_phy_param_parse(sprd_host, pdev->dev.of_node);
|
||||||
|
|
||||||
|
sprd_host->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||||
|
if (!IS_ERR(sprd_host->pinctrl)) {
|
||||||
|
sprd_host->pins_uhs =
|
||||||
|
pinctrl_lookup_state(sprd_host->pinctrl, "state_uhs");
|
||||||
|
if (IS_ERR(sprd_host->pins_uhs)) {
|
||||||
|
ret = PTR_ERR(sprd_host->pins_uhs);
|
||||||
|
goto pltfm_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprd_host->pins_default =
|
||||||
|
pinctrl_lookup_state(sprd_host->pinctrl, "default");
|
||||||
|
if (IS_ERR(sprd_host->pins_default)) {
|
||||||
|
ret = PTR_ERR(sprd_host->pins_default);
|
||||||
|
goto pltfm_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clk = devm_clk_get(&pdev->dev, "sdio");
|
clk = devm_clk_get(&pdev->dev, "sdio");
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
@ -364,14 +575,22 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
sprd_host->clk_enable = clk;
|
sprd_host->clk_enable = clk;
|
||||||
|
|
||||||
|
clk = devm_clk_get(&pdev->dev, "2x_enable");
|
||||||
|
if (!IS_ERR(clk))
|
||||||
|
sprd_host->clk_2x_enable = clk;
|
||||||
|
|
||||||
ret = clk_prepare_enable(sprd_host->clk_sdio);
|
ret = clk_prepare_enable(sprd_host->clk_sdio);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto pltfm_free;
|
goto pltfm_free;
|
||||||
|
|
||||||
clk_prepare_enable(sprd_host->clk_enable);
|
ret = clk_prepare_enable(sprd_host->clk_enable);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto clk_disable;
|
goto clk_disable;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(sprd_host->clk_2x_enable);
|
||||||
|
if (ret)
|
||||||
|
goto clk_disable2;
|
||||||
|
|
||||||
sdhci_sprd_init_config(host);
|
sdhci_sprd_init_config(host);
|
||||||
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
|
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
|
||||||
sprd_host->version = ((host->version & SDHCI_VENDOR_VER_MASK) >>
|
sprd_host->version = ((host->version & SDHCI_VENDOR_VER_MASK) >>
|
||||||
@ -408,6 +627,9 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
|||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
pm_runtime_set_suspended(&pdev->dev);
|
pm_runtime_set_suspended(&pdev->dev);
|
||||||
|
|
||||||
|
clk_disable_unprepare(sprd_host->clk_2x_enable);
|
||||||
|
|
||||||
|
clk_disable2:
|
||||||
clk_disable_unprepare(sprd_host->clk_enable);
|
clk_disable_unprepare(sprd_host->clk_enable);
|
||||||
|
|
||||||
clk_disable:
|
clk_disable:
|
||||||
@ -427,6 +649,7 @@ static int sdhci_sprd_remove(struct platform_device *pdev)
|
|||||||
mmc_remove_host(mmc);
|
mmc_remove_host(mmc);
|
||||||
clk_disable_unprepare(sprd_host->clk_sdio);
|
clk_disable_unprepare(sprd_host->clk_sdio);
|
||||||
clk_disable_unprepare(sprd_host->clk_enable);
|
clk_disable_unprepare(sprd_host->clk_enable);
|
||||||
|
clk_disable_unprepare(sprd_host->clk_2x_enable);
|
||||||
|
|
||||||
mmc_free_host(mmc);
|
mmc_free_host(mmc);
|
||||||
|
|
||||||
@ -449,6 +672,7 @@ static int sdhci_sprd_runtime_suspend(struct device *dev)
|
|||||||
|
|
||||||
clk_disable_unprepare(sprd_host->clk_sdio);
|
clk_disable_unprepare(sprd_host->clk_sdio);
|
||||||
clk_disable_unprepare(sprd_host->clk_enable);
|
clk_disable_unprepare(sprd_host->clk_enable);
|
||||||
|
clk_disable_unprepare(sprd_host->clk_2x_enable);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -459,19 +683,28 @@ static int sdhci_sprd_runtime_resume(struct device *dev)
|
|||||||
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
|
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = clk_prepare_enable(sprd_host->clk_enable);
|
ret = clk_prepare_enable(sprd_host->clk_2x_enable);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(sprd_host->clk_enable);
|
||||||
|
if (ret)
|
||||||
|
goto clk_2x_disable;
|
||||||
|
|
||||||
ret = clk_prepare_enable(sprd_host->clk_sdio);
|
ret = clk_prepare_enable(sprd_host->clk_sdio);
|
||||||
if (ret) {
|
if (ret)
|
||||||
clk_disable_unprepare(sprd_host->clk_enable);
|
goto clk_disable;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
sdhci_runtime_resume_host(host);
|
sdhci_runtime_resume_host(host);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
clk_disable:
|
||||||
|
clk_disable_unprepare(sprd_host->clk_enable);
|
||||||
|
|
||||||
|
clk_2x_disable:
|
||||||
|
clk_disable_unprepare(sprd_host->clk_2x_enable);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1541,8 +1541,11 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
clk = devm_clk_get(mmc_dev(host->mmc), NULL);
|
clk = devm_clk_get(mmc_dev(host->mmc), NULL);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
dev_err(mmc_dev(host->mmc), "clk err\n");
|
|
||||||
rc = PTR_ERR(clk);
|
rc = PTR_ERR(clk);
|
||||||
|
|
||||||
|
if (rc != -EPROBE_DEFER)
|
||||||
|
dev_err(&pdev->dev, "failed to get clock: %d\n", rc);
|
||||||
|
|
||||||
goto err_clk_get;
|
goto err_clk_get;
|
||||||
}
|
}
|
||||||
clk_prepare_enable(clk);
|
clk_prepare_enable(clk);
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
#define SDHCI_CTRL_ADMA32 0x10
|
#define SDHCI_CTRL_ADMA32 0x10
|
||||||
#define SDHCI_CTRL_ADMA64 0x18
|
#define SDHCI_CTRL_ADMA64 0x18
|
||||||
#define SDHCI_CTRL_ADMA3 0x18
|
#define SDHCI_CTRL_ADMA3 0x18
|
||||||
#define SDHCI_CTRL_8BITBUS 0x20
|
#define SDHCI_CTRL_8BITBUS 0x20
|
||||||
#define SDHCI_CTRL_CDTEST_INS 0x40
|
#define SDHCI_CTRL_CDTEST_INS 0x40
|
||||||
#define SDHCI_CTRL_CDTEST_EN 0x80
|
#define SDHCI_CTRL_CDTEST_EN 0x80
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/of.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/property.h>
|
#include <linux/property.h>
|
||||||
@ -36,11 +37,14 @@
|
|||||||
#define OTAPDLYSEL_SHIFT 12
|
#define OTAPDLYSEL_SHIFT 12
|
||||||
#define OTAPDLYSEL_MASK GENMASK(15, 12)
|
#define OTAPDLYSEL_MASK GENMASK(15, 12)
|
||||||
#define STRBSEL_SHIFT 24
|
#define STRBSEL_SHIFT 24
|
||||||
#define STRBSEL_MASK GENMASK(27, 24)
|
#define STRBSEL_4BIT_MASK GENMASK(27, 24)
|
||||||
|
#define STRBSEL_8BIT_MASK GENMASK(31, 24)
|
||||||
#define SEL50_SHIFT 8
|
#define SEL50_SHIFT 8
|
||||||
#define SEL50_MASK BIT(SEL50_SHIFT)
|
#define SEL50_MASK BIT(SEL50_SHIFT)
|
||||||
#define SEL100_SHIFT 9
|
#define SEL100_SHIFT 9
|
||||||
#define SEL100_MASK BIT(SEL100_SHIFT)
|
#define SEL100_MASK BIT(SEL100_SHIFT)
|
||||||
|
#define FREQSEL_SHIFT 8
|
||||||
|
#define FREQSEL_MASK GENMASK(10, 8)
|
||||||
#define DLL_TRIM_ICP_SHIFT 4
|
#define DLL_TRIM_ICP_SHIFT 4
|
||||||
#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
|
#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
|
||||||
#define DR_TY_SHIFT 20
|
#define DR_TY_SHIFT 20
|
||||||
@ -77,19 +81,29 @@ struct sdhci_am654_data {
|
|||||||
int trm_icp;
|
int trm_icp;
|
||||||
int drv_strength;
|
int drv_strength;
|
||||||
bool dll_on;
|
bool dll_on;
|
||||||
|
int strb_sel;
|
||||||
|
u32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdhci_am654_driver_data {
|
||||||
|
const struct sdhci_pltfm_data *pdata;
|
||||||
|
u32 flags;
|
||||||
|
#define IOMUX_PRESENT (1 << 0)
|
||||||
|
#define FREQSEL_2_BIT (1 << 1)
|
||||||
|
#define STRBSEL_4_BIT (1 << 2)
|
||||||
|
#define DLL_PRESENT (1 << 3)
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
|
static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||||
{
|
{
|
||||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||||
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
||||||
int sel50, sel100;
|
int sel50, sel100, freqsel;
|
||||||
u32 mask, val;
|
u32 mask, val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (sdhci_am654->dll_on) {
|
if (sdhci_am654->dll_on) {
|
||||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
|
||||||
ENDLL_MASK, 0);
|
|
||||||
|
|
||||||
sdhci_am654->dll_on = false;
|
sdhci_am654->dll_on = false;
|
||||||
}
|
}
|
||||||
@ -101,27 +115,53 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
|
|||||||
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
|
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
|
||||||
val = (1 << OTAPDLYENA_SHIFT) |
|
val = (1 << OTAPDLYENA_SHIFT) |
|
||||||
(sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
|
(sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
|
||||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
|
||||||
mask, val);
|
/* Write to STRBSEL for HS400 speed mode */
|
||||||
switch (clock) {
|
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||||
case 200000000:
|
if (sdhci_am654->flags & STRBSEL_4_BIT)
|
||||||
sel50 = 0;
|
mask = STRBSEL_4BIT_MASK;
|
||||||
sel100 = 0;
|
else
|
||||||
break;
|
mask = STRBSEL_8BIT_MASK;
|
||||||
case 100000000:
|
|
||||||
sel50 = 0;
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask,
|
||||||
sel100 = 1;
|
sdhci_am654->strb_sel <<
|
||||||
break;
|
STRBSEL_SHIFT);
|
||||||
default:
|
}
|
||||||
sel50 = 1;
|
|
||||||
sel100 = 0;
|
if (sdhci_am654->flags & FREQSEL_2_BIT) {
|
||||||
|
switch (clock) {
|
||||||
|
case 200000000:
|
||||||
|
sel50 = 0;
|
||||||
|
sel100 = 0;
|
||||||
|
break;
|
||||||
|
case 100000000:
|
||||||
|
sel50 = 0;
|
||||||
|
sel100 = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sel50 = 1;
|
||||||
|
sel100 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure PHY DLL frequency */
|
||||||
|
mask = SEL50_MASK | SEL100_MASK;
|
||||||
|
val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
|
||||||
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask,
|
||||||
|
val);
|
||||||
|
} else {
|
||||||
|
switch (clock) {
|
||||||
|
case 200000000:
|
||||||
|
freqsel = 0x0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
freqsel = 0x4;
|
||||||
|
}
|
||||||
|
|
||||||
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
|
||||||
|
FREQSEL_MASK,
|
||||||
|
freqsel << FREQSEL_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure PHY DLL frequency */
|
|
||||||
mask = SEL50_MASK | SEL100_MASK;
|
|
||||||
val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
|
|
||||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
|
|
||||||
mask, val);
|
|
||||||
/* Configure DLL TRIM */
|
/* Configure DLL TRIM */
|
||||||
mask = DLL_TRIM_ICP_MASK;
|
mask = DLL_TRIM_ICP_MASK;
|
||||||
val = sdhci_am654->trm_icp << DLL_TRIM_ICP_SHIFT;
|
val = sdhci_am654->trm_icp << DLL_TRIM_ICP_SHIFT;
|
||||||
@ -129,24 +169,41 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
|
|||||||
/* Configure DLL driver strength */
|
/* Configure DLL driver strength */
|
||||||
mask |= DR_TY_MASK;
|
mask |= DR_TY_MASK;
|
||||||
val |= sdhci_am654->drv_strength << DR_TY_SHIFT;
|
val |= sdhci_am654->drv_strength << DR_TY_SHIFT;
|
||||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, mask, val);
|
||||||
mask, val);
|
|
||||||
/* Enable DLL */
|
/* Enable DLL */
|
||||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK,
|
||||||
ENDLL_MASK, 0x1 << ENDLL_SHIFT);
|
0x1 << ENDLL_SHIFT);
|
||||||
/*
|
/*
|
||||||
* Poll for DLL ready. Use a one second timeout.
|
* Poll for DLL ready. Use a one second timeout.
|
||||||
* Works in all experiments done so far
|
* Works in all experiments done so far
|
||||||
*/
|
*/
|
||||||
ret = regmap_read_poll_timeout(sdhci_am654->base,
|
ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
|
||||||
PHY_STAT1, val,
|
val, val & DLLRDY_MASK, 1000,
|
||||||
val & DLLRDY_MASK,
|
1000000);
|
||||||
1000, 1000000);
|
if (ret) {
|
||||||
|
dev_err(mmc_dev(host->mmc), "DLL failed to relock\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sdhci_am654->dll_on = true;
|
sdhci_am654->dll_on = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
|
||||||
|
unsigned int clock)
|
||||||
|
{
|
||||||
|
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||||
|
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
||||||
|
int val, mask;
|
||||||
|
|
||||||
|
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
|
||||||
|
val = (1 << OTAPDLYENA_SHIFT) |
|
||||||
|
(sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
|
||||||
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
|
||||||
|
|
||||||
|
sdhci_set_clock(host, clock);
|
||||||
|
}
|
||||||
|
|
||||||
static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode,
|
static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode,
|
||||||
unsigned short vdd)
|
unsigned short vdd)
|
||||||
{
|
{
|
||||||
@ -197,6 +254,56 @@ static const struct sdhci_pltfm_data sdhci_am654_pdata = {
|
|||||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
|
||||||
|
.pdata = &sdhci_am654_pdata,
|
||||||
|
.flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sdhci_ops sdhci_j721e_8bit_ops = {
|
||||||
|
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||||
|
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
|
||||||
|
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||||
|
.set_bus_width = sdhci_set_bus_width,
|
||||||
|
.set_power = sdhci_am654_set_power,
|
||||||
|
.set_clock = sdhci_am654_set_clock,
|
||||||
|
.write_b = sdhci_am654_write_b,
|
||||||
|
.reset = sdhci_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = {
|
||||||
|
.ops = &sdhci_j721e_8bit_ops,
|
||||||
|
.quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
|
||||||
|
SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
|
||||||
|
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
|
||||||
|
.pdata = &sdhci_j721e_8bit_pdata,
|
||||||
|
.flags = DLL_PRESENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sdhci_ops sdhci_j721e_4bit_ops = {
|
||||||
|
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||||
|
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
|
||||||
|
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||||
|
.set_bus_width = sdhci_set_bus_width,
|
||||||
|
.set_power = sdhci_am654_set_power,
|
||||||
|
.set_clock = sdhci_j721e_4bit_set_clock,
|
||||||
|
.write_b = sdhci_am654_write_b,
|
||||||
|
.reset = sdhci_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sdhci_pltfm_data sdhci_j721e_4bit_pdata = {
|
||||||
|
.ops = &sdhci_j721e_4bit_ops,
|
||||||
|
.quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
|
||||||
|
SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
|
||||||
|
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = {
|
||||||
|
.pdata = &sdhci_j721e_4bit_pdata,
|
||||||
|
.flags = IOMUX_PRESENT,
|
||||||
|
};
|
||||||
static int sdhci_am654_init(struct sdhci_host *host)
|
static int sdhci_am654_init(struct sdhci_host *host)
|
||||||
{
|
{
|
||||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||||
@ -208,30 +315,34 @@ static int sdhci_am654_init(struct sdhci_host *host)
|
|||||||
|
|
||||||
/* Reset OTAP to default value */
|
/* Reset OTAP to default value */
|
||||||
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
|
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
|
||||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, 0x0);
|
||||||
mask, 0x0);
|
|
||||||
|
|
||||||
regmap_read(sdhci_am654->base, PHY_STAT1, &val);
|
if (sdhci_am654->flags & DLL_PRESENT) {
|
||||||
if (~val & CALDONE_MASK) {
|
regmap_read(sdhci_am654->base, PHY_STAT1, &val);
|
||||||
/* Calibrate IO lines */
|
if (~val & CALDONE_MASK) {
|
||||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
/* Calibrate IO lines */
|
||||||
PDB_MASK, PDB_MASK);
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
||||||
ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
|
PDB_MASK, PDB_MASK);
|
||||||
val, val & CALDONE_MASK, 1, 20);
|
ret = regmap_read_poll_timeout(sdhci_am654->base,
|
||||||
if (ret)
|
PHY_STAT1, val,
|
||||||
return ret;
|
val & CALDONE_MASK,
|
||||||
|
1, 20);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable pins by setting IO mux to 0 */
|
/* Enable pins by setting IO mux to 0 */
|
||||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
if (sdhci_am654->flags & IOMUX_PRESENT)
|
||||||
IOMUX_ENABLE_MASK, 0);
|
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
||||||
|
IOMUX_ENABLE_MASK, 0);
|
||||||
|
|
||||||
/* Set slot type based on SD or eMMC */
|
/* Set slot type based on SD or eMMC */
|
||||||
if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
|
if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
|
||||||
ctl_cfg_2 = SLOTTYPE_EMBEDDED;
|
ctl_cfg_2 = SLOTTYPE_EMBEDDED;
|
||||||
|
|
||||||
regmap_update_bits(sdhci_am654->base, CTL_CFG_2,
|
regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK,
|
||||||
SLOTTYPE_MASK, ctl_cfg_2);
|
ctl_cfg_2);
|
||||||
|
|
||||||
return sdhci_add_host(host);
|
return sdhci_add_host(host);
|
||||||
}
|
}
|
||||||
@ -243,51 +354,73 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev,
|
|||||||
int drv_strength;
|
int drv_strength;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = device_property_read_u32(dev, "ti,trm-icp",
|
|
||||||
&sdhci_am654->trm_icp);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = device_property_read_u32(dev, "ti,otap-del-sel",
|
ret = device_property_read_u32(dev, "ti,otap-del-sel",
|
||||||
&sdhci_am654->otap_del_sel);
|
&sdhci_am654->otap_del_sel);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
|
if (sdhci_am654->flags & DLL_PRESENT) {
|
||||||
&drv_strength);
|
ret = device_property_read_u32(dev, "ti,trm-icp",
|
||||||
if (ret)
|
&sdhci_am654->trm_icp);
|
||||||
return ret;
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
switch (drv_strength) {
|
ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
|
||||||
case 50:
|
&drv_strength);
|
||||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
|
if (ret)
|
||||||
break;
|
return ret;
|
||||||
case 33:
|
|
||||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
|
switch (drv_strength) {
|
||||||
break;
|
case 50:
|
||||||
case 66:
|
sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
|
||||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
|
break;
|
||||||
break;
|
case 33:
|
||||||
case 100:
|
sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
|
||||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
|
break;
|
||||||
break;
|
case 66:
|
||||||
case 40:
|
sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
|
||||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
|
break;
|
||||||
break;
|
case 100:
|
||||||
default:
|
sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
|
||||||
dev_err(dev, "Invalid driver strength\n");
|
break;
|
||||||
return -EINVAL;
|
case 40:
|
||||||
|
sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(dev, "Invalid driver strength\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device_property_read_u32(dev, "ti,strobe-sel", &sdhci_am654->strb_sel);
|
||||||
|
|
||||||
sdhci_get_of_property(pdev);
|
sdhci_get_of_property(pdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id sdhci_am654_of_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "ti,am654-sdhci-5.1",
|
||||||
|
.data = &sdhci_am654_drvdata,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "ti,j721e-sdhci-8bit",
|
||||||
|
.data = &sdhci_j721e_8bit_drvdata,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "ti,j721e-sdhci-4bit",
|
||||||
|
.data = &sdhci_j721e_4bit_drvdata,
|
||||||
|
},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
static int sdhci_am654_probe(struct platform_device *pdev)
|
static int sdhci_am654_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
const struct sdhci_am654_driver_data *drvdata;
|
||||||
struct sdhci_pltfm_host *pltfm_host;
|
struct sdhci_pltfm_host *pltfm_host;
|
||||||
struct sdhci_am654_data *sdhci_am654;
|
struct sdhci_am654_data *sdhci_am654;
|
||||||
|
const struct of_device_id *match;
|
||||||
struct sdhci_host *host;
|
struct sdhci_host *host;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct clk *clk_xin;
|
struct clk *clk_xin;
|
||||||
@ -295,12 +428,15 @@ static int sdhci_am654_probe(struct platform_device *pdev)
|
|||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
host = sdhci_pltfm_init(pdev, &sdhci_am654_pdata, sizeof(*sdhci_am654));
|
match = of_match_node(sdhci_am654_of_match, pdev->dev.of_node);
|
||||||
|
drvdata = match->data;
|
||||||
|
host = sdhci_pltfm_init(pdev, drvdata->pdata, sizeof(*sdhci_am654));
|
||||||
if (IS_ERR(host))
|
if (IS_ERR(host))
|
||||||
return PTR_ERR(host);
|
return PTR_ERR(host);
|
||||||
|
|
||||||
pltfm_host = sdhci_priv(host);
|
pltfm_host = sdhci_priv(host);
|
||||||
sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
||||||
|
sdhci_am654->flags = drvdata->flags;
|
||||||
|
|
||||||
clk_xin = devm_clk_get(dev, "clk_xin");
|
clk_xin = devm_clk_get(dev, "clk_xin");
|
||||||
if (IS_ERR(clk_xin)) {
|
if (IS_ERR(clk_xin)) {
|
||||||
@ -375,11 +511,6 @@ static int sdhci_am654_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id sdhci_am654_of_match[] = {
|
|
||||||
{ .compatible = "ti,am654-sdhci-5.1" },
|
|
||||||
{ /* sentinel */ }
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct platform_driver sdhci_am654_driver = {
|
static struct platform_driver sdhci_am654_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "sdhci-am654",
|
.name = "sdhci-am654",
|
||||||
|
@ -172,6 +172,8 @@ static int tmio_mmc_probe(struct platform_device *pdev)
|
|||||||
host->mmc->f_max = pdata->hclk;
|
host->mmc->f_max = pdata->hclk;
|
||||||
host->mmc->f_min = pdata->hclk / 512;
|
host->mmc->f_min = pdata->hclk / 512;
|
||||||
|
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
ret = tmio_mmc_host_probe(host);
|
ret = tmio_mmc_host_probe(host);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto host_free;
|
goto host_free;
|
||||||
@ -191,6 +193,7 @@ static int tmio_mmc_probe(struct platform_device *pdev)
|
|||||||
tmio_mmc_host_remove(host);
|
tmio_mmc_host_remove(host);
|
||||||
host_free:
|
host_free:
|
||||||
tmio_mmc_host_free(host);
|
tmio_mmc_host_free(host);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
cell_disable:
|
cell_disable:
|
||||||
if (cell->disable)
|
if (cell->disable)
|
||||||
cell->disable(pdev);
|
cell->disable(pdev);
|
||||||
@ -207,6 +210,8 @@ static int tmio_mmc_remove(struct platform_device *pdev)
|
|||||||
if (cell->disable)
|
if (cell->disable)
|
||||||
cell->disable(pdev);
|
cell->disable(pdev);
|
||||||
|
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/highmem.h>
|
#include <linux/highmem.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
@ -45,7 +46,6 @@
|
|||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/sizes.h>
|
#include <linux/sizes.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/swiotlb.h>
|
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
#include "tmio_mmc.h"
|
#include "tmio_mmc.h"
|
||||||
@ -1153,6 +1153,15 @@ void tmio_mmc_host_free(struct tmio_mmc_host *host)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tmio_mmc_host_free);
|
EXPORT_SYMBOL_GPL(tmio_mmc_host_free);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tmio_mmc_host_probe() - Common probe for all implementations
|
||||||
|
* @_host: Host to probe
|
||||||
|
*
|
||||||
|
* Perform tasks common to all implementations probe functions.
|
||||||
|
*
|
||||||
|
* The caller should have called pm_runtime_enable() prior to calling
|
||||||
|
* the common probe function.
|
||||||
|
*/
|
||||||
int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
|
int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = _host->pdev;
|
struct platform_device *pdev = _host->pdev;
|
||||||
@ -1190,19 +1199,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
|
|||||||
mmc->max_blk_size = TMIO_MAX_BLK_SIZE;
|
mmc->max_blk_size = TMIO_MAX_BLK_SIZE;
|
||||||
mmc->max_blk_count = pdata->max_blk_count ? :
|
mmc->max_blk_count = pdata->max_blk_count ? :
|
||||||
(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
|
(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
|
||||||
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
|
mmc->max_req_size = min_t(size_t,
|
||||||
/*
|
mmc->max_blk_size * mmc->max_blk_count,
|
||||||
* Since swiotlb has memory size limitation, this will calculate
|
dma_max_mapping_size(&pdev->dev));
|
||||||
* the maximum size locally (because we don't have any APIs for it now)
|
|
||||||
* and check the current max_req_size. And then, this will update
|
|
||||||
* the max_req_size if needed as a workaround.
|
|
||||||
*/
|
|
||||||
if (swiotlb_max_segment()) {
|
|
||||||
unsigned int max_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE;
|
|
||||||
|
|
||||||
if (mmc->max_req_size > max_size)
|
|
||||||
mmc->max_req_size = max_size;
|
|
||||||
}
|
|
||||||
mmc->max_seg_size = mmc->max_req_size;
|
mmc->max_seg_size = mmc->max_req_size;
|
||||||
|
|
||||||
if (mmc_can_gpio_ro(mmc))
|
if (mmc_can_gpio_ro(mmc))
|
||||||
@ -1261,7 +1260,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
|
|||||||
pm_runtime_set_active(&pdev->dev);
|
pm_runtime_set_active(&pdev->dev);
|
||||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
|
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
|
||||||
pm_runtime_use_autosuspend(&pdev->dev);
|
pm_runtime_use_autosuspend(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
|
||||||
|
|
||||||
ret = mmc_add_host(mmc);
|
ret = mmc_add_host(mmc);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1297,7 +1295,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
|
|||||||
|
|
||||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||||
pm_runtime_put_sync(&pdev->dev);
|
pm_runtime_put_sync(&pdev->dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tmio_mmc_host_remove);
|
EXPORT_SYMBOL_GPL(tmio_mmc_host_remove);
|
||||||
|
|
||||||
|
@ -631,6 +631,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
|
|||||||
host->clk_disable = uniphier_sd_clk_disable;
|
host->clk_disable = uniphier_sd_clk_disable;
|
||||||
host->set_clock = uniphier_sd_set_clock;
|
host->set_clock = uniphier_sd_set_clock;
|
||||||
|
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
ret = uniphier_sd_clk_enable(host);
|
ret = uniphier_sd_clk_enable(host);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto free_host;
|
goto free_host;
|
||||||
@ -652,6 +653,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
free_host:
|
free_host:
|
||||||
tmio_mmc_host_free(host);
|
tmio_mmc_host_free(host);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -662,6 +664,7 @@ static int uniphier_sd_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
tmio_mmc_host_remove(host);
|
tmio_mmc_host_remove(host);
|
||||||
uniphier_sd_clk_disable(host);
|
uniphier_sd_clk_disable(host);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -729,13 +729,6 @@ static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef dma_max_pfn
|
|
||||||
static inline unsigned long dma_max_pfn(struct device *dev)
|
|
||||||
{
|
|
||||||
return (*dev->dma_mask >> PAGE_SHIFT) + dev->dma_pfn_offset;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline int dma_get_cache_alignment(void)
|
static inline int dma_get_cache_alignment(void)
|
||||||
{
|
{
|
||||||
#ifdef ARCH_DMA_MINALIGN
|
#ifdef ARCH_DMA_MINALIGN
|
||||||
|
@ -501,7 +501,6 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
|
|||||||
wake_up_process(host->sdio_irq_thread);
|
wake_up_process(host->sdio_irq_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdio_run_irqs(struct mmc_host *host);
|
|
||||||
void sdio_signal_irq(struct mmc_host *host);
|
void sdio_signal_irq(struct mmc_host *host);
|
||||||
|
|
||||||
#ifdef CONFIG_REGULATOR
|
#ifdef CONFIG_REGULATOR
|
||||||
|
Loading…
Reference in New Issue
Block a user