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.
|
||||
- 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:
|
||||
|
||||
sd_emmc_a: mmc@70000 {
|
||||
|
|
|
@ -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
|
||||
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";
|
||||
};
|
||||
};
|
||||
This file has moved to mmc-controller.yaml.
|
||||
|
|
|
@ -1,13 +1,4 @@
|
|||
* Toshiba Mobile IO 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.
|
||||
* Renesas SDHI SD/MMC controller
|
||||
|
||||
Required properties:
|
||||
- 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
|
||||
|
||||
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.
|
||||
- The first should be the sdhci 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"
|
||||
- interrupts: Interrupt specifiers
|
||||
- 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,driver-strength-ohm: driver strength in 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:
|
||||
|
||||
|
|
|
@ -14,10 +14,31 @@ Required properties:
|
|||
- clock-names: Should contain the following:
|
||||
"sdio" - SDIO source clock (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:
|
||||
- assigned-clocks: the same with "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:
|
||||
|
||||
|
@ -32,6 +53,11 @@ sdio0: sdio@20600000 {
|
|||
assigned-clocks = <&ap_clk CLK_EMMC_2X>;
|
||||
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>;
|
||||
non-removable;
|
||||
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
|
||||
|
||||
/* 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 */
|
||||
static inline bool is_device_dma_coherent(struct device *dev)
|
||||
{
|
||||
|
|
|
@ -625,13 +625,18 @@ static int __init memstick_init(void)
|
|||
return -ENOMEM;
|
||||
|
||||
rc = bus_register(&memstick_bus_type);
|
||||
if (!rc)
|
||||
rc = class_register(&memstick_host_class);
|
||||
if (rc)
|
||||
goto error_destroy_workqueue;
|
||||
|
||||
if (!rc)
|
||||
return 0;
|
||||
rc = class_register(&memstick_host_class);
|
||||
if (rc)
|
||||
goto error_bus_unregister;
|
||||
|
||||
return 0;
|
||||
|
||||
error_bus_unregister:
|
||||
bus_unregister(&memstick_bus_type);
|
||||
error_destroy_workqueue:
|
||||
destroy_workqueue(workqueue);
|
||||
|
||||
return rc;
|
||||
|
|
|
@ -227,45 +227,21 @@ void mmc_add_host_debugfs(struct mmc_host *host)
|
|||
struct dentry *root;
|
||||
|
||||
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;
|
||||
|
||||
if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
|
||||
goto err_node;
|
||||
|
||||
if (!debugfs_create_x32("caps", S_IRUSR, root, &host->caps))
|
||||
goto err_node;
|
||||
|
||||
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;
|
||||
debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops);
|
||||
debugfs_create_x32("caps", S_IRUSR, root, &host->caps);
|
||||
debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2);
|
||||
debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
|
||||
&mmc_clock_fops);
|
||||
|
||||
#ifdef CONFIG_FAIL_MMC_REQUEST
|
||||
if (fail_request)
|
||||
setup_fault_attr(&fail_default_attr, fail_request);
|
||||
host->fail_mmc_request = fail_default_attr;
|
||||
if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
|
||||
root,
|
||||
&host->fail_mmc_request)))
|
||||
goto err_node;
|
||||
fault_create_debugfs_attr("fail_mmc_request", root,
|
||||
&host->fail_mmc_request);
|
||||
#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)
|
||||
|
@ -282,25 +258,9 @@ void mmc_add_card_debugfs(struct mmc_card *card)
|
|||
return;
|
||||
|
||||
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;
|
||||
|
||||
if (!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");
|
||||
debugfs_create_x32("state", S_IRUSR, root, &card->state);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (card->debugfs_root)
|
||||
file = debugfs_create_file(name, mode, card->debugfs_root,
|
||||
card, fops);
|
||||
|
||||
if (IS_ERR_OR_NULL(file)) {
|
||||
dev_err(&card->dev,
|
||||
"Can't create %s. Perhaps debugfs is disabled.\n",
|
||||
name);
|
||||
return -ENODEV;
|
||||
}
|
||||
debugfs_create_file(name, mode, card->debugfs_root, card, fops);
|
||||
|
||||
df = kmalloc(sizeof(*df), GFP_KERNEL);
|
||||
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)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
u64 limit = BLK_BOUNCE_HIGH;
|
||||
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_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);
|
||||
if (mmc_can_erase(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,
|
||||
min(host->max_blk_count, host->max_req_size / 512));
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
int err;
|
||||
|
@ -582,11 +582,9 @@ try_again:
|
|||
/*
|
||||
* Inform the card of the voltage
|
||||
*/
|
||||
if (!powered_resume) {
|
||||
err = mmc_send_io_op_cond(host, ocr, &rocr);
|
||||
if (err)
|
||||
goto err;
|
||||
}
|
||||
err = mmc_send_io_op_cond(host, ocr, &rocr);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* For SPI, enable CRC as appropriate.
|
||||
|
@ -645,7 +643,7 @@ try_again:
|
|||
* try to init uhs card. sdio_read_cccr will take over this task
|
||||
* 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);
|
||||
if (err == -EAGAIN) {
|
||||
mmc_sdio_resend_if_cond(host, card);
|
||||
|
@ -659,7 +657,7 @@ try_again:
|
|||
/*
|
||||
* 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);
|
||||
if (err)
|
||||
goto remove;
|
||||
|
@ -687,7 +685,7 @@ try_again:
|
|||
/*
|
||||
* 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);
|
||||
if (err)
|
||||
goto remove;
|
||||
|
@ -816,10 +814,27 @@ 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;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
mmc_go_idle(host);
|
||||
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)
|
||||
return ret;
|
||||
|
||||
return mmc_sdio_init_card(host, host->card->ocr, host->card,
|
||||
powered_resume);
|
||||
return mmc_sdio_init_card(host, host->card->ocr, host->card);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -965,7 +979,11 @@ static int mmc_sdio_resume(struct mmc_host *host)
|
|||
/* Basic card reinitialization. */
|
||||
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)) {
|
||||
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_enable(&host->card->dev);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
err = mmc_sdio_reinit_card(host);
|
||||
} else if (mmc_card_wake_sdio_irq(host)) {
|
||||
/* We may have switched to 1-bit mode during suspend */
|
||||
err = sdio_enable_4bit_bus(host->card);
|
||||
}
|
||||
|
@ -1009,38 +1023,6 @@ out:
|
|||
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)
|
||||
{
|
||||
/* 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. */
|
||||
mmc_claim_host(host);
|
||||
mmc_power_up(host, host->card->ocr);
|
||||
ret = mmc_sdio_power_restore(host);
|
||||
ret = mmc_sdio_reinit_card(host);
|
||||
mmc_release_host(host);
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -1079,7 +1061,7 @@ static int mmc_sdio_sw_reset(struct mmc_host *host)
|
|||
mmc_set_initial_state(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 = {
|
||||
|
@ -1129,7 +1111,7 @@ int mmc_attach_sdio(struct mmc_host *host)
|
|||
/*
|
||||
* Detect and init the card.
|
||||
*/
|
||||
err = mmc_sdio_init_card(host, rocr, NULL, 0);
|
||||
err = mmc_sdio_init_card(host, rocr, NULL);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void sdio_run_irqs(struct mmc_host *host)
|
||||
static void sdio_run_irqs(struct mmc_host *host)
|
||||
{
|
||||
mmc_claim_host(host);
|
||||
if (host->sdio_irqs) {
|
||||
|
@ -103,7 +103,6 @@ void sdio_run_irqs(struct mmc_host *host)
|
|||
}
|
||||
mmc_release_host(host);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdio_run_irqs);
|
||||
|
||||
void sdio_irq_work(struct work_struct *work)
|
||||
{
|
||||
|
|
|
@ -996,7 +996,7 @@ config MMC_SDHCI_OMAP
|
|||
|
||||
config MMC_SDHCI_AM654
|
||||
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
|
||||
help
|
||||
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_diff = abs(clock - tmp_clock);
|
||||
|
||||
if (tmp_diff >= 0 && tmp_diff < diff) {
|
||||
if (tmp_diff < diff) {
|
||||
diff = tmp_diff;
|
||||
clk_src = cfg->clk_src_reg;
|
||||
clk_div = tmp_div;
|
||||
|
|
|
@ -110,7 +110,6 @@ struct goldfish_mmc_host {
|
|||
struct mmc_request *mrq;
|
||||
struct mmc_command *cmd;
|
||||
struct mmc_data *data;
|
||||
struct mmc_host *mmc;
|
||||
struct device *dev;
|
||||
unsigned char id; /* 16xx chips have 2 MMC blocks */
|
||||
void *virt_base;
|
||||
|
@ -172,7 +171,7 @@ goldfish_mmc_start_command(struct goldfish_mmc_host *host, struct mmc_command *c
|
|||
resptype = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
dev_err(mmc_dev(mmc_from_priv(host)),
|
||||
"Invalid response type: %04x\n", mmc_resp_type(cmd));
|
||||
break;
|
||||
}
|
||||
|
@ -218,8 +217,8 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
|
|||
data->sg->length);
|
||||
}
|
||||
host->data->bytes_xfered += data->sg->length;
|
||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
|
||||
dma_data_dir);
|
||||
dma_unmap_sg(mmc_dev(mmc_from_priv(host)), data->sg,
|
||||
host->sg_len, dma_data_dir);
|
||||
}
|
||||
|
||||
host->data = NULL;
|
||||
|
@ -233,7 +232,7 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
|
|||
|
||||
if (!data->stop) {
|
||||
host->mrq = NULL;
|
||||
mmc_request_done(host->mmc, data->mrq);
|
||||
mmc_request_done(mmc_from_priv(host), data->mrq);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -275,7 +274,7 @@ static void goldfish_mmc_cmd_done(struct goldfish_mmc_host *host,
|
|||
|
||||
if (host->data == NULL || cmd->error) {
|
||||
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;
|
||||
mrq->cmd->error = -ETIMEDOUT;
|
||||
host->mrq = NULL;
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
mmc_request_done(mmc_from_priv(host), mrq);
|
||||
}
|
||||
|
||||
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);
|
||||
pr_info("%s: Card detect now %d\n", __func__,
|
||||
(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) {
|
||||
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) {
|
||||
GOLDFISH_MMC_WRITE(host, MMC_INT_STATUS, status);
|
||||
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);
|
||||
|
||||
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);
|
||||
host->dma_done = 0;
|
||||
host->dma_in_use = 1;
|
||||
|
@ -458,7 +458,6 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
host->mmc = mmc;
|
||||
|
||||
pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end);
|
||||
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);
|
||||
if (ret)
|
||||
dev_warn(mmc_dev(host->mmc),
|
||||
"Unable to create sysfs attributes\n");
|
||||
dev_warn(mmc_dev(mmc), "Unable to create sysfs attributes\n");
|
||||
|
||||
GOLDFISH_MMC_WRITE(host, MMC_SET_BUFFER, host->phys_base);
|
||||
GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE,
|
||||
|
@ -522,7 +520,7 @@ err_request_irq_failed:
|
|||
dma_alloc_failed:
|
||||
iounmap(host->reg_base);
|
||||
ioremap_failed:
|
||||
mmc_free_host(host->mmc);
|
||||
mmc_free_host(mmc);
|
||||
err_alloc_host_failed:
|
||||
return ret;
|
||||
}
|
||||
|
@ -530,14 +528,15 @@ err_alloc_host_failed:
|
|||
static int goldfish_mmc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
|
||||
struct mmc_host *mmc = mmc_from_priv(host);
|
||||
|
||||
BUG_ON(host == NULL);
|
||||
|
||||
mmc_remove_host(host->mmc);
|
||||
mmc_remove_host(mmc);
|
||||
free_irq(host->irq, host);
|
||||
dma_free_coherent(&pdev->dev, BUFFER_SIZE, host->virt_base, host->phys_base);
|
||||
iounmap(host->reg_base);
|
||||
mmc_free_host(host->mmc);
|
||||
mmc_free_host(mmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -576,42 +576,18 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
|
|||
struct mmc_host *mmc = slot->mmc;
|
||||
struct atmel_mci *host = slot->host;
|
||||
struct dentry *root;
|
||||
struct dentry *node;
|
||||
|
||||
root = mmc->debugfs_root;
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
node = debugfs_create_file("regs", S_IRUSR, root, host,
|
||||
&atmci_regs_fops);
|
||||
if (IS_ERR(node))
|
||||
return;
|
||||
if (!node)
|
||||
goto err;
|
||||
|
||||
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");
|
||||
debugfs_create_file("regs", S_IRUSR, root, host, &atmci_regs_fops);
|
||||
debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
|
||||
debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
|
||||
debugfs_create_x32("pending_events", S_IRUSR, root,
|
||||
(u32 *)&host->pending_events);
|
||||
debugfs_create_x32("completed_events", S_IRUSR, root,
|
||||
(u32 *)&host->completed_events);
|
||||
}
|
||||
|
||||
#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 dw_mci *host = slot->host;
|
||||
struct dentry *root;
|
||||
struct dentry *node;
|
||||
|
||||
root = mmc->debugfs_root;
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
node = debugfs_create_file("regs", S_IRUSR, root, host,
|
||||
&dw_mci_regs_fops);
|
||||
if (!node)
|
||||
goto err;
|
||||
|
||||
node = debugfs_create_file("req", S_IRUSR, root, slot,
|
||||
&dw_mci_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");
|
||||
debugfs_create_file("regs", S_IRUSR, root, host, &dw_mci_regs_fops);
|
||||
debugfs_create_file("req", S_IRUSR, root, slot, &dw_mci_req_fops);
|
||||
debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
|
||||
debugfs_create_x32("pending_events", S_IRUSR, root,
|
||||
(u32 *)&host->pending_events);
|
||||
debugfs_create_x32("completed_events", S_IRUSR, root,
|
||||
(u32 *)&host->completed_events);
|
||||
}
|
||||
#endif /* defined(CONFIG_DEBUG_FS) */
|
||||
|
||||
|
|
|
@ -116,6 +116,9 @@
|
|||
#define SD_EMMC_TXD 0x94
|
||||
#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_RESP_TIMEOUT 256 /* in clock cycles */
|
||||
#define SD_EMMC_CMD_TIMEOUT 1024 /* in ms */
|
||||
|
@ -155,6 +158,8 @@ struct meson_host {
|
|||
unsigned long req_rate;
|
||||
bool ddr;
|
||||
|
||||
bool dram_access_quirk;
|
||||
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default;
|
||||
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,
|
||||
struct mmc_request *mrq)
|
||||
{
|
||||
struct meson_host *host = mmc_priv(mmc);
|
||||
struct mmc_data *data = mrq->data;
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
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
|
||||
* 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;
|
||||
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 */
|
||||
host->vqmmc_enabled = false;
|
||||
ret = mmc_regulator_get_supply(mmc);
|
||||
|
@ -1133,9 +1151,16 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
|||
goto err_init_clk;
|
||||
|
||||
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_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc);
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
if (host->dram_access_quirk) {
|
||||
/*
|
||||
* The MMC Controller embeds 1,5KiB of internal SRAM
|
||||
* that can be used to be used as bounce buffer.
|
||||
* In the case of the G12A SDIO controller, use these
|
||||
* instead of the DDR memory
|
||||
*/
|
||||
host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN;
|
||||
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,
|
||||
|
@ -1170,8 +1207,9 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_bounce_buf:
|
||||
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);
|
||||
err_free_irq:
|
||||
free_irq(host->irq, host);
|
||||
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,
|
||||
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->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);
|
||||
}
|
||||
|
||||
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_4taps = true,
|
||||
};
|
||||
|
||||
static const struct renesas_sdhi_quirks sdhi_quirks_h3_es2 = {
|
||||
.hs400_disabled = false,
|
||||
static const struct renesas_sdhi_quirks sdhi_quirks_4tap = {
|
||||
.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[] = {
|
||||
{ .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_h3_m3w_es1 },
|
||||
{ .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_h3_es2 },
|
||||
{ .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_h3_m3w_es1 },
|
||||
{ .soc_id = "r8a774a1", .revision = "ES1.[012]", .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_4tap },
|
||||
{ .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
|
||||
{ .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
|
||||
{ .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 },
|
||||
{ /* Sentinel. */ },
|
||||
};
|
||||
|
@ -775,6 +774,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|||
/* All SDHI have SDIO status bits which must be 1 */
|
||||
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = renesas_sdhi_clk_enable(host);
|
||||
if (ret)
|
||||
goto efree;
|
||||
|
@ -855,6 +856,8 @@ edisclk:
|
|||
efree:
|
||||
tmio_mmc_host_free(host);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
|
||||
|
@ -866,6 +869,8 @@ int renesas_sdhi_remove(struct platform_device *pdev)
|
|||
tmio_mmc_host_remove(host);
|
||||
renesas_sdhi_clk_disable(host);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
|
||||
|
|
|
@ -1449,33 +1449,18 @@ DEFINE_SHOW_ATTRIBUTE(s3cmci_regs);
|
|||
static void s3cmci_debugfs_attach(struct s3cmci_host *host)
|
||||
{
|
||||
struct device *dev = &host->pdev->dev;
|
||||
struct dentry *root;
|
||||
|
||||
host->debug_root = debugfs_create_dir(dev_name(dev), NULL);
|
||||
if (IS_ERR(host->debug_root)) {
|
||||
dev_err(dev, "failed to create debugfs root\n");
|
||||
return;
|
||||
}
|
||||
root = debugfs_create_dir(dev_name(dev), NULL);
|
||||
host->debug_root = root;
|
||||
|
||||
host->debug_state = debugfs_create_file("state", 0444,
|
||||
host->debug_root, host,
|
||||
&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");
|
||||
debugfs_create_file("state", 0444, root, host, &s3cmci_state_fops);
|
||||
debugfs_create_file("regs", 0444, root, host, &s3cmci_regs_fops);
|
||||
}
|
||||
|
||||
static void s3cmci_debugfs_remove(struct s3cmci_host *host)
|
||||
{
|
||||
debugfs_remove(host->debug_regs);
|
||||
debugfs_remove(host->debug_state);
|
||||
debugfs_remove(host->debug_root);
|
||||
debugfs_remove_recursive(host->debug_root);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -67,8 +67,6 @@ struct s3cmci_host {
|
|||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debug_root;
|
||||
struct dentry *debug_state;
|
||||
struct dentry *debug_regs;
|
||||
#endif
|
||||
|
||||
#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_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||
int wait_cnt = 50;
|
||||
unsigned long flags;
|
||||
unsigned long flags, xo_clk = 0;
|
||||
u32 config;
|
||||
const struct sdhci_msm_offset *msm_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);
|
||||
|
||||
/*
|
||||
|
@ -627,10 +630,10 @@ static int msm_init_cm_dll(struct sdhci_host *host)
|
|||
config &= CORE_FLL_CYCLE_CNT;
|
||||
if (config)
|
||||
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
|
||||
clk_get_rate(msm_host->xo_clk));
|
||||
xo_clk);
|
||||
else
|
||||
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
|
||||
clk_get_rate(msm_host->xo_clk));
|
||||
xo_clk);
|
||||
|
||||
config = readl_relaxed(host->ioaddr +
|
||||
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_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
|
||||
bool hs400_tuning;
|
||||
unsigned int clk;
|
||||
u32 val;
|
||||
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 &&
|
||||
host->flags & SDHCI_HS400_TUNING)
|
||||
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
|
||||
* which is eSDHC base clock when use periperal clock.
|
||||
* For ls1046a, the clock value got by common clk API is
|
||||
* peripheral clock while the eSDHC base clock is 1/2
|
||||
* peripheral clock.
|
||||
* For some platforms, the clock value got by common clk
|
||||
* API is peripheral clock while the eSDHC base clock is
|
||||
* 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;
|
||||
else
|
||||
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, ICP_EMMC, intel_glk_emmc),
|
||||
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_SD, intel_byt_sd),
|
||||
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;
|
||||
dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
|
||||
if (slots == 0)
|
||||
return -ENODEV;
|
||||
|
||||
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_host *host;
|
||||
u32 reg;
|
||||
u32 reg, caps;
|
||||
int ret;
|
||||
|
||||
chip = slot->chip;
|
||||
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) {
|
||||
case PCI_DEVICE_ID_O2_SDS0:
|
||||
case PCI_DEVICE_ID_O2_SEABIRD0:
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375
|
||||
#define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4
|
||||
#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_SD 0x02f5
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
@ -22,6 +23,15 @@
|
|||
/* SDHCI_ARGUMENT2 register high 16bit */
|
||||
#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 SDHCIBSPRD_IT_WR_DLY_INV BIT(5)
|
||||
#define SDHCI_SPRD_BIT_CMD_DLY_INV BIT(13)
|
||||
|
@ -41,6 +51,7 @@
|
|||
/* SDHCI_HOST_CONTROL2 */
|
||||
#define SDHCI_SPRD_CTRL_HS200 0x0005
|
||||
#define SDHCI_SPRD_CTRL_HS400 0x0006
|
||||
#define SDHCI_SPRD_CTRL_HS400ES 0x0007
|
||||
|
||||
/*
|
||||
* 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_DEF_RATE 26000000
|
||||
#define SDHCI_SPRD_PHY_DLL_CLK 52000000
|
||||
|
||||
struct sdhci_sprd_host {
|
||||
u32 version;
|
||||
struct clk *clk_sdio;
|
||||
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;
|
||||
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))
|
||||
|
@ -131,6 +165,15 @@ static inline void sdhci_sprd_sd_clk_off(struct sdhci_host *host)
|
|||
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
|
||||
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)
|
||||
{
|
||||
bool en = false;
|
||||
bool en = false, clk_changed = false;
|
||||
|
||||
if (clock == 0) {
|
||||
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;
|
||||
sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV |
|
||||
SDHCI_SPRD_BIT_POSRD_DLY_INV, en);
|
||||
clk_changed = true;
|
||||
} else {
|
||||
_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)
|
||||
|
@ -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,
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
|
@ -284,6 +367,12 @@ static void sdhci_sprd_hw_reset(struct sdhci_host *host)
|
|||
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 = {
|
||||
.read_l = sdhci_sprd_readl,
|
||||
.write_l = sdhci_sprd_writel,
|
||||
|
@ -295,6 +384,7 @@ static struct sdhci_ops sdhci_sprd_ops = {
|
|||
.reset = sdhci_reset,
|
||||
.set_uhs_signaling = sdhci_sprd_set_uhs_signaling,
|
||||
.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)
|
||||
|
@ -317,6 +407,99 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *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 = {
|
||||
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
|
||||
.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);
|
||||
pdev->dev.dma_mask = &host->dma_mask;
|
||||
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 |
|
||||
MMC_CAP_ERASE | MMC_CAP_CMD23;
|
||||
|
@ -346,6 +539,24 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
|||
goto pltfm_free;
|
||||
|
||||
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");
|
||||
if (IS_ERR(clk)) {
|
||||
|
@ -364,14 +575,22 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
|||
}
|
||||
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);
|
||||
if (ret)
|
||||
goto pltfm_free;
|
||||
|
||||
clk_prepare_enable(sprd_host->clk_enable);
|
||||
ret = clk_prepare_enable(sprd_host->clk_enable);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
ret = clk_prepare_enable(sprd_host->clk_2x_enable);
|
||||
if (ret)
|
||||
goto clk_disable2;
|
||||
|
||||
sdhci_sprd_init_config(host);
|
||||
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
|
||||
sprd_host->version = ((host->version & SDHCI_VENDOR_VER_MASK) >>
|
||||
|
@ -408,6 +627,9 @@ pm_runtime_disable:
|
|||
pm_runtime_disable(&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:
|
||||
|
@ -427,6 +649,7 @@ static int sdhci_sprd_remove(struct platform_device *pdev)
|
|||
mmc_remove_host(mmc);
|
||||
clk_disable_unprepare(sprd_host->clk_sdio);
|
||||
clk_disable_unprepare(sprd_host->clk_enable);
|
||||
clk_disable_unprepare(sprd_host->clk_2x_enable);
|
||||
|
||||
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_enable);
|
||||
clk_disable_unprepare(sprd_host->clk_2x_enable);
|
||||
|
||||
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);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(sprd_host->clk_enable);
|
||||
ret = clk_prepare_enable(sprd_host->clk_2x_enable);
|
||||
if (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);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(sprd_host->clk_enable);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
sdhci_runtime_resume_host(host);
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -1541,8 +1541,11 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
|
|||
|
||||
clk = devm_clk_get(mmc_dev(host->mmc), NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(mmc_dev(host->mmc), "clk err\n");
|
||||
rc = PTR_ERR(clk);
|
||||
|
||||
if (rc != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "failed to get clock: %d\n", rc);
|
||||
|
||||
goto err_clk_get;
|
||||
}
|
||||
clk_prepare_enable(clk);
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
#define SDHCI_CTRL_ADMA32 0x10
|
||||
#define SDHCI_CTRL_ADMA64 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_EN 0x80
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
|
@ -36,11 +37,14 @@
|
|||
#define OTAPDLYSEL_SHIFT 12
|
||||
#define OTAPDLYSEL_MASK GENMASK(15, 12)
|
||||
#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_MASK BIT(SEL50_SHIFT)
|
||||
#define SEL100_SHIFT 9
|
||||
#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_MASK GENMASK(7, 4)
|
||||
#define DR_TY_SHIFT 20
|
||||
|
@ -77,19 +81,29 @@ struct sdhci_am654_data {
|
|||
int trm_icp;
|
||||
int drv_strength;
|
||||
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)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
||||
int sel50, sel100;
|
||||
int sel50, sel100, freqsel;
|
||||
u32 mask, val;
|
||||
int ret;
|
||||
|
||||
if (sdhci_am654->dll_on) {
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
||||
ENDLL_MASK, 0);
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
|
||||
|
||||
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;
|
||||
val = (1 << OTAPDLYENA_SHIFT) |
|
||||
(sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
|
||||
mask, val);
|
||||
switch (clock) {
|
||||
case 200000000:
|
||||
sel50 = 0;
|
||||
sel100 = 0;
|
||||
break;
|
||||
case 100000000:
|
||||
sel50 = 0;
|
||||
sel100 = 1;
|
||||
break;
|
||||
default:
|
||||
sel50 = 1;
|
||||
sel100 = 0;
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
|
||||
/* Write to STRBSEL for HS400 speed mode */
|
||||
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||
if (sdhci_am654->flags & STRBSEL_4_BIT)
|
||||
mask = STRBSEL_4BIT_MASK;
|
||||
else
|
||||
mask = STRBSEL_8BIT_MASK;
|
||||
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask,
|
||||
sdhci_am654->strb_sel <<
|
||||
STRBSEL_SHIFT);
|
||||
}
|
||||
|
||||
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 */
|
||||
mask = DLL_TRIM_ICP_MASK;
|
||||
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 */
|
||||
mask |= DR_TY_MASK;
|
||||
val |= sdhci_am654->drv_strength << DR_TY_SHIFT;
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
||||
mask, val);
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, mask, val);
|
||||
/* Enable DLL */
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
||||
ENDLL_MASK, 0x1 << ENDLL_SHIFT);
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK,
|
||||
0x1 << ENDLL_SHIFT);
|
||||
/*
|
||||
* Poll for DLL ready. Use a one second timeout.
|
||||
* Works in all experiments done so far
|
||||
*/
|
||||
ret = regmap_read_poll_timeout(sdhci_am654->base,
|
||||
PHY_STAT1, val,
|
||||
val & DLLRDY_MASK,
|
||||
1000, 1000000);
|
||||
ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
|
||||
val, val & DLLRDY_MASK, 1000,
|
||||
1000000);
|
||||
if (ret) {
|
||||
dev_err(mmc_dev(host->mmc), "DLL failed to relock\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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,
|
||||
unsigned short vdd)
|
||||
{
|
||||
|
@ -197,6 +254,56 @@ static const struct sdhci_pltfm_data sdhci_am654_pdata = {
|
|||
.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)
|
||||
{
|
||||
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 */
|
||||
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
|
||||
mask, 0x0);
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, 0x0);
|
||||
|
||||
regmap_read(sdhci_am654->base, PHY_STAT1, &val);
|
||||
if (~val & CALDONE_MASK) {
|
||||
/* Calibrate IO lines */
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
||||
PDB_MASK, PDB_MASK);
|
||||
ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
|
||||
val, val & CALDONE_MASK, 1, 20);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (sdhci_am654->flags & DLL_PRESENT) {
|
||||
regmap_read(sdhci_am654->base, PHY_STAT1, &val);
|
||||
if (~val & CALDONE_MASK) {
|
||||
/* Calibrate IO lines */
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
||||
PDB_MASK, PDB_MASK);
|
||||
ret = regmap_read_poll_timeout(sdhci_am654->base,
|
||||
PHY_STAT1, val,
|
||||
val & CALDONE_MASK,
|
||||
1, 20);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable pins by setting IO mux to 0 */
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
||||
IOMUX_ENABLE_MASK, 0);
|
||||
if (sdhci_am654->flags & IOMUX_PRESENT)
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
|
||||
IOMUX_ENABLE_MASK, 0);
|
||||
|
||||
/* Set slot type based on SD or eMMC */
|
||||
if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
|
||||
ctl_cfg_2 = SLOTTYPE_EMBEDDED;
|
||||
|
||||
regmap_update_bits(sdhci_am654->base, CTL_CFG_2,
|
||||
SLOTTYPE_MASK, ctl_cfg_2);
|
||||
regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK,
|
||||
ctl_cfg_2);
|
||||
|
||||
return sdhci_add_host(host);
|
||||
}
|
||||
|
@ -243,51 +354,73 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev,
|
|||
int drv_strength;
|
||||
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",
|
||||
&sdhci_am654->otap_del_sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
|
||||
&drv_strength);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (sdhci_am654->flags & DLL_PRESENT) {
|
||||
ret = device_property_read_u32(dev, "ti,trm-icp",
|
||||
&sdhci_am654->trm_icp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (drv_strength) {
|
||||
case 50:
|
||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
|
||||
break;
|
||||
case 33:
|
||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
|
||||
break;
|
||||
case 66:
|
||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
|
||||
break;
|
||||
case 100:
|
||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
|
||||
break;
|
||||
case 40:
|
||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid driver strength\n");
|
||||
return -EINVAL;
|
||||
ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
|
||||
&drv_strength);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (drv_strength) {
|
||||
case 50:
|
||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
|
||||
break;
|
||||
case 33:
|
||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
|
||||
break;
|
||||
case 66:
|
||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
|
||||
break;
|
||||
case 100:
|
||||
sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
|
||||
break;
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
const struct sdhci_am654_driver_data *drvdata;
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct sdhci_am654_data *sdhci_am654;
|
||||
const struct of_device_id *match;
|
||||
struct sdhci_host *host;
|
||||
struct resource *res;
|
||||
struct clk *clk_xin;
|
||||
|
@ -295,12 +428,15 @@ static int sdhci_am654_probe(struct platform_device *pdev)
|
|||
void __iomem *base;
|
||||
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))
|
||||
return PTR_ERR(host);
|
||||
|
||||
pltfm_host = sdhci_priv(host);
|
||||
sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
||||
sdhci_am654->flags = drvdata->flags;
|
||||
|
||||
clk_xin = devm_clk_get(dev, "clk_xin");
|
||||
if (IS_ERR(clk_xin)) {
|
||||
|
@ -375,11 +511,6 @@ static int sdhci_am654_remove(struct platform_device *pdev)
|
|||
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 = {
|
||||
.driver = {
|
||||
.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_min = pdata->hclk / 512;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = tmio_mmc_host_probe(host);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
|
@ -191,6 +193,7 @@ host_remove:
|
|||
tmio_mmc_host_remove(host);
|
||||
host_free:
|
||||
tmio_mmc_host_free(host);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
cell_disable:
|
||||
if (cell->disable)
|
||||
cell->disable(pdev);
|
||||
|
@ -207,6 +210,8 @@ static int tmio_mmc_remove(struct platform_device *pdev)
|
|||
if (cell->disable)
|
||||
cell->disable(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -45,7 +46,6 @@
|
|||
#include <linux/scatterlist.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/swiotlb.h>
|
||||
#include <linux/workqueue.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);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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_count = pdata->max_blk_count ? :
|
||||
(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
|
||||
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
|
||||
/*
|
||||
* Since swiotlb has memory size limitation, this will calculate
|
||||
* 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_req_size = min_t(size_t,
|
||||
mmc->max_blk_size * mmc->max_blk_count,
|
||||
dma_max_mapping_size(&pdev->dev));
|
||||
mmc->max_seg_size = mmc->max_req_size;
|
||||
|
||||
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_autosuspend_delay(&pdev->dev, 50);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = mmc_add_host(mmc);
|
||||
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_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
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->set_clock = uniphier_sd_set_clock;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
ret = uniphier_sd_clk_enable(host);
|
||||
if (ret)
|
||||
goto free_host;
|
||||
|
@ -652,6 +653,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
|
|||
|
||||
free_host:
|
||||
tmio_mmc_host_free(host);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -662,6 +664,7 @@ static int uniphier_sd_remove(struct platform_device *pdev)
|
|||
|
||||
tmio_mmc_host_remove(host);
|
||||
uniphier_sd_clk_disable(host);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -729,13 +729,6 @@ static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask)
|
|||
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)
|
||||
{
|
||||
#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);
|
||||
}
|
||||
|
||||
void sdio_run_irqs(struct mmc_host *host);
|
||||
void sdio_signal_irq(struct mmc_host *host);
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
|
|
Loading…
Reference in New Issue