- Export SDIO revision and info strings to userspace
  - Add support for specifying mmc/mmcblk index via mmc aliases in DT
 
 MMC host:
  - Enable support for async probe for all mmc host drivers
  - Enable compile testing of multiple host drivers
  - dw_mmc: Enable the Synopsys DesignWare driver for RISCV and CSKY
  - mtk-sd: Fixup support for CQHCI
  - owl-mmc: Add support for the actions,s700-mmc variant
  - renesas_sdhi: Fix regression (temporary) for re-insertion of SD cards
  - renesas_sdhi: Add support for the r8a774e1 variant
  - renesas_sdhi/tmio: Improvements for tunings
  - renesas_sdhi/tmio: Rework support for reset of controller
  - sdhci-acpi: Fix HS400 tuning for devices with invalid presets on AMDI0040
  - sdhci_am654: Improve support for tunings
  - sdhci_am654: Add support for input tap delays
  - sdhci_am654: Add workaround for card detect debounce timer
  - sdhci-am654: Add support for the TI's J7200 variants
  - sdhci-esdhc-imx: Fix support for manual tuning
  - sdhci-iproc: Enable support for eMMC DDR 3.3V for bcm2711
  - sdhci-msm: Fix stability issues with HS400 for sc7180
  - sdhci-of-sparx5: Add Sparx5 SoC eMMC driver
  - sdhci-of-esdhc: Fixup reference clock source selection
  - sdhci-pci: Add LTR support for some Intel BYT controllers
  - sdhci-pci-gli: Add CQHCI Support for GL9763E
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAl+EKAsXHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjClKMw/+L8auxMmo8r5bEXb6b7/anJIq
 HhnsQIG+bd/OT2zVIXcDF6estBAd4g748MImGKhMLLvPls5Mt9FP04rkdQPFEDPJ
 0L6f1GduN2agTbqofphgBhjZnYN916vNZWFjr0yLF/TTosKQJCv7Vv/pfjYlVE4g
 k4sIOcFytj03FVs9D/QbEf2wKomX1e5AsLCWeoJvV/6ncTJrEGqqr+4Ty45Q6jiz
 apm9t5KezlkQTUZ0w1sWuKuhsCHcRROM5iHJUAsbVMpix3TpFe3//kMY0l+uGcvo
 JZwJux06gwMNT3dkRgAfWnzTpdEvaVvuYnKkYOWtNbUAkX6f6ua1iGQmB1a1gqsw
 Af02FKQJG1V9vKCodvkULdB3C2dhE+S7nsfE7PgnvQS6Lo3PBFSToHD5npSblK1b
 flec6B8AeWjUtniuNzMHf8/ucNqVQ2fKUW1kFgMeoSwFWJlbXpjkMANzPYUTMjWI
 WhiYaxmGFn8kpDcksDCIVND6ARZ6pILpQF+Ykl5GKlmWiSA9iCDyYHY6mcEY/20s
 8OUaIrL5VoA/fNO0fRyToeJtMOQVeZo7qxAd76IDmupeYDK6Tv5P3VJ+drvNXR0h
 K9DvPn5sGJLm6TX1b6LNC+79m41CvgyreOcT6BBssbAkyQkhSqmzcdXssCgHYII7
 SbAn/AOWG2ujef3jOB8=
 =mg10
 -----END PGP SIGNATURE-----

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

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Export SDIO revision and info strings to userspace
   - Add support for specifying mmc/mmcblk index via mmc aliases in DT

 MMC host:
   - Enable support for async probe for all mmc host drivers
   - Enable compile testing of multiple host drivers
   - dw_mmc: Enable the Synopsys DesignWare driver for RISCV and CSKY
   - mtk-sd: Fixup support for CQHCI
   - owl-mmc: Add support for the actions,s700-mmc variant
   - renesas_sdhi: Fix regression (temporary) for re-insertion of SD cards
   - renesas_sdhi: Add support for the r8a774e1 variant
   - renesas_sdhi/tmio: Improvements for tunings
   - renesas_sdhi/tmio: Rework support for reset of controller
   - sdhci-acpi: Fix HS400 tuning for devices with invalid presets on AMDI0040
   - sdhci_am654: Improve support for tunings
   - sdhci_am654: Add support for input tap delays
   - sdhci_am654: Add workaround for card detect debounce timer
   - sdhci-am654: Add support for the TI's J7200 variants
   - sdhci-esdhc-imx: Fix support for manual tuning
   - sdhci-iproc: Enable support for eMMC DDR 3.3V for bcm2711
   - sdhci-msm: Fix stability issues with HS400 for sc7180
   - sdhci-of-sparx5: Add Sparx5 SoC eMMC driver
   - sdhci-of-esdhc: Fixup reference clock source selection
   - sdhci-pci: Add LTR support for some Intel BYT controllers
   - sdhci-pci-gli: Add CQHCI Support for GL9763E"

* tag 'mmc-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (91 commits)
  mmc: sdhci_am654: Fix module autoload
  mmc: renesas_sdhi: workaround a regression when reinserting SD cards
  mmc: sdhci-pci-gli: Add CQHCI Support for GL9763E
  mmc: sdhci-acpi: AMDI0040: Set SDHCI_QUIRK2_PRESET_VALUE_BROKEN
  mmc: sdhci_am654: Enable tuning for SDR50
  mmc: sdhci_am654: Add support for software tuning
  mmc: sdhci_am654: Add support for input tap delay
  mmc: sdhci_am654: Fix hard coded otap delay array size
  dt-bindings: mmc: sdhci-am654: Add documentation for input tap delay
  dt-bindings: mmc: sdhci-am654: Convert sdhci-am654 controller documentation to json schema
  mmc: sdhci-of-esdhc: fix reference clock source selection
  mmc: host: fix depends for MMC_MESON_GX w/ COMPILE_TEST
  mmc: sdhci-s3c: hide forward declaration of of_device_id behind CONFIG_OF
  mmc: sdhci: fix indentation mistakes
  mmc: moxart: remove unneeded check for drvdata
  mmc: renesas_sdhi: drop local flag for tuning
  mmc: rtsx_usb_sdmmc: simplify the return expression of sd_change_phase()
  mmc: core: document mmc_hw_reset()
  mmc: mediatek: Drop pointer to mmc_host from msdc_host
  dt-bindings: mmc: owl: add compatible string actions,s700-mmc
  ...
This commit is contained in:
Linus Torvalds 2020-10-13 09:25:24 -07:00
Родитель dfef313e99 1e23400f1a
Коммит 647412daeb
105 изменённых файлов: 1741 добавлений и 402 удалений

Просмотреть файл

@ -62,7 +62,7 @@ examples:
}; };
mmc@5b010000 { mmc@5b010000 {
compatible = "fsl,imx8qxp-usdhc"; compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc";
interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x5b010000 0x10000>; reg = <0x5b010000 0x10000>;
clocks = <&conn_lpcg IMX_CONN_LPCG_SDHC0_IPG_CLK>, clocks = <&conn_lpcg IMX_CONN_LPCG_SDHC0_IPG_CLK>,

Просмотреть файл

@ -21,23 +21,26 @@ description: |
properties: properties:
compatible: compatible:
enum: oneOf:
- fsl,imx25-esdhc - enum:
- fsl,imx35-esdhc - fsl,imx25-esdhc
- fsl,imx51-esdhc - fsl,imx35-esdhc
- fsl,imx53-esdhc - fsl,imx51-esdhc
- fsl,imx6q-usdhc - fsl,imx53-esdhc
- fsl,imx6sl-usdhc - fsl,imx6q-usdhc
- fsl,imx6sx-usdhc - fsl,imx6sl-usdhc
- fsl,imx6ull-usdhc - fsl,imx6sx-usdhc
- fsl,imx7d-usdhc - fsl,imx6ull-usdhc
- fsl,imx7ulp-usdhc - fsl,imx7d-usdhc
- fsl,imx8mq-usdhc - fsl,imx7ulp-usdhc
- fsl,imx8mm-usdhc - items:
- fsl,imx8mn-usdhc - enum:
- fsl,imx8mp-usdhc - fsl,imx8mm-usdhc
- fsl,imx8qm-usdhc - fsl,imx8mn-usdhc
- fsl,imx8qxp-usdhc - fsl,imx8mp-usdhc
- fsl,imx8mq-usdhc
- fsl,imx8qxp-usdhc
- const: fsl,imx7d-usdhc
reg: reg:
maxItems: 1 maxItems: 1

Просмотреть файл

@ -0,0 +1,65 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/microchip,dw-sparx5-sdhci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip Sparx5 Mobile Storage Host Controller Binding
allOf:
- $ref: "mmc-controller.yaml"
maintainers:
- Lars Povlsen <lars.povlsen@microchip.com>
# Everything else is described in the common file
properties:
compatible:
const: microchip,dw-sparx5-sdhci
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
description:
Handle to "core" clock for the sdhci controller.
clock-names:
items:
- const: core
microchip,clock-delay:
description: Delay clock to card to meet setup time requirements.
Each step increase by 1.25ns.
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 1
maximum: 15
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/microchip,sparx5.h>
sdhci0: mmc@600800000 {
compatible = "microchip,dw-sparx5-sdhci";
reg = <0x00800000 0x1000>;
pinctrl-0 = <&emmc_pins>;
pinctrl-names = "default";
clocks = <&clks CLK_ID_AUX1>;
clock-names = "core";
assigned-clocks = <&clks CLK_ID_AUX1>;
assigned-clock-rates = <800000000>;
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
bus-width = <8>;
microchip,clock-delay = <10>;
};

Просмотреть файл

@ -14,6 +14,10 @@ description: |
that requires the respective functionality should implement them using that requires the respective functionality should implement them using
these definitions. these definitions.
It is possible to assign a fixed index mmcN to an MMC host controller
(and the corresponding mmcblkN devices) by defining an alias in the
/aliases device tree node.
properties: properties:
$nodename: $nodename:
pattern: "^mmc(@.*)?$" pattern: "^mmc(@.*)?$"

Просмотреть файл

@ -20,6 +20,8 @@ properties:
reset-gpios: reset-gpios:
minItems: 1 minItems: 1
# Put some limit to avoid false warnings
maxItems: 32
description: description:
contains a list of GPIO specifiers. The reset GPIOs are asserted contains a list of GPIO specifiers. The reset GPIOs are asserted
at initialization and prior we start the power up procedure of the card. at initialization and prior we start the power up procedure of the card.

Просмотреть файл

@ -14,7 +14,11 @@ maintainers:
properties: properties:
compatible: compatible:
const: actions,owl-mmc oneOf:
- const: actions,owl-mmc
- items:
- const: actions,s700-mmc
- const: actions,owl-mmc
reg: reg:
maxItems: 1 maxItems: 1

Просмотреть файл

@ -50,6 +50,7 @@ properties:
- renesas,sdhi-r8a774a1 # RZ/G2M - renesas,sdhi-r8a774a1 # RZ/G2M
- renesas,sdhi-r8a774b1 # RZ/G2N - renesas,sdhi-r8a774b1 # RZ/G2N
- renesas,sdhi-r8a774c0 # RZ/G2E - renesas,sdhi-r8a774c0 # RZ/G2E
- renesas,sdhi-r8a774e1 # RZ/G2H
- renesas,sdhi-r8a7795 # R-Car H3 - renesas,sdhi-r8a7795 # R-Car H3
- renesas,sdhi-r8a7796 # R-Car M3-W - renesas,sdhi-r8a7796 # R-Car M3-W
- renesas,sdhi-r8a77961 # R-Car M3-W+ - renesas,sdhi-r8a77961 # R-Car M3-W+

Просмотреть файл

@ -1,61 +0,0 @@
Device Tree Bindings for the SDHCI Controllers present on TI's AM654 SOCs
The bindings follow the mmc[1], clock[2] and interrupt[3] bindings.
Only deviations are documented here.
[1] Documentation/devicetree/bindings/mmc/mmc.txt
[2] Documentation/devicetree/bindings/clock/clock-bindings.txt
[3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Required Properties:
- 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
- clocks: Handles to the clock inputs.
- clock-names: Tuple including "clk_xin" and "clk_ahb"
- interrupts: Interrupt specifiers
Output tap delay for each speed mode:
- ti,otap-del-sel-legacy
- ti,otap-del-sel-mmc-hs
- ti,otap-del-sel-sd-hs
- ti,otap-del-sel-sdr12
- ti,otap-del-sel-sdr25
- ti,otap-del-sel-sdr50
- ti,otap-del-sel-sdr104
- ti,otap-del-sel-ddr50
- ti,otap-del-sel-ddr52
- ti,otap-del-sel-hs200
- ti,otap-del-sel-hs400
These bindings must be provided otherwise the driver will disable the
corresponding speed mode (i.e. all nodes must provide at least -legacy)
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.
- ti,clkbuf-sel: Clock Delay Buffer Select
Example:
sdhci0: sdhci@4f80000 {
compatible = "ti,am654-sdhci-5.1";
reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>;
power-domains = <&k3_pds 47>;
clocks = <&k3_clks 47 0>, <&k3_clks 47 1>;
clock-names = "clk_ahb", "clk_xin";
interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
sdhci-caps-mask = <0x80000007 0x0>;
mmc-ddr-1_8v;
ti,otap-del-sel-legacy = <0x0>;
ti,otap-del-sel-mmc-hs = <0x0>;
ti,otap-del-sel-ddr52 = <0x5>;
ti,otap-del-sel-hs200 = <0x5>;
ti,otap-del-sel-hs400 = <0x0>;
ti,trm-icp = <0x8>;
};

Просмотреть файл

@ -0,0 +1,218 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
%YAML 1.2
---
$id: "http://devicetree.org/schemas/mmc/sdhci-am654.yaml#"
$schema : "http://devicetree.org/meta-schemas/core.yaml#"
title: TI AM654 MMC Controller
maintainers:
- Ulf Hansson <ulf.hansson@linaro.org>
allOf:
- $ref: mmc-controller.yaml#
properties:
compatible:
enum:
- ti,am654-sdhci-5.1
- ti,j721e-sdhci-8bit
- ti,j721e-sdhci-4bit
- ti,j7200-sdhci-8bit
- ti,j721e-sdhci-4bit
reg:
maxItems: 2
interrupts:
maxItems: 1
power-domains:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
description: Handles to input clocks
clock-names:
minItems: 1
maxItems: 2
items:
- const: clk_ahb
- const: clk_xin
# PHY output tap delays:
# Used to delay the data valid window and align it to the sampling clock.
# Binding needs to be provided for each supported speed mode otherwise the
# corresponding mode will be disabled.
ti,otap-del-sel-legacy:
description: Output tap delay for SD/MMC legacy timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-mmc-hs:
description: Output tap delay for MMC high speed timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-sd-hs:
description: Output tap delay for SD high speed timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-sdr12:
description: Output tap delay for SD UHS SDR12 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-sdr25:
description: Output tap delay for SD UHS SDR25 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-sdr50:
description: Output tap delay for SD UHS SDR50 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-sdr104:
description: Output tap delay for SD UHS SDR104 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-ddr50:
description: Output tap delay for SD UHS DDR50 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-ddr52:
description: Output tap delay for eMMC DDR52 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-hs200:
description: Output tap delay for eMMC HS200 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,otap-del-sel-hs400:
description: Output tap delay for eMMC HS400 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
# PHY input tap delays:
# Used to delay the data valid window and align it to the sampling clock for
# modes that don't support tuning
ti,itap-del-sel-legacy:
description: Input tap delay for SD/MMC legacy timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0x1f
ti,itap-del-sel-mmc-hs:
description: Input tap delay for MMC high speed timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0x1f
ti,itap-del-sel-sd-hs:
description: Input tap delay for SD high speed timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0x1f
ti,itap-del-sel-sdr12:
description: Input tap delay for SD UHS SDR12 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0x1f
ti,itap-del-sel-sdr25:
description: Input tap delay for SD UHS SDR25 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0x1f
ti,itap-del-sel-ddr52:
description: Input tap delay for MMC DDR52 timing
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0x1f
ti,trm-icp:
description: DLL trim select
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 0xf
ti,driver-strength-ohm:
description: DLL drive strength in ohms
$ref: "/schemas/types.yaml#/definitions/uint32"
oneOf:
- enum:
- 33
- 40
- 50
- 66
- 100
ti,strobe-sel:
description: strobe select delay for HS400 speed mode.
$ref: "/schemas/types.yaml#/definitions/uint32"
ti,clkbuf-sel:
description: Clock Delay Buffer Select
$ref: "/schemas/types.yaml#/definitions/uint32"
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- ti,otap-del-sel-legacy
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
bus {
#address-cells = <2>;
#size-cells = <2>;
mmc0: mmc@4f80000 {
compatible = "ti,am654-sdhci-5.1";
reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>;
power-domains = <&k3_pds 47>;
clocks = <&k3_clks 47 0>, <&k3_clks 47 1>;
clock-names = "clk_ahb", "clk_xin";
interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
sdhci-caps-mask = <0x80000007 0x0>;
mmc-ddr-1_8v;
ti,otap-del-sel-legacy = <0x0>;
ti,otap-del-sel-mmc-hs = <0x0>;
ti,otap-del-sel-ddr52 = <0x5>;
ti,otap-del-sel-hs200 = <0x5>;
ti,otap-del-sel-hs400 = <0x0>;
ti,itap-del-sel-legacy = <0x10>;
ti,itap-del-sel-mmc-hs = <0xa>;
ti,itap-del-sel-ddr52 = <0x3>;
ti,trm-icp = <0x8>;
};
};

Просмотреть файл

@ -1223,7 +1223,7 @@ static int msb_read_boot_blocks(struct msb_data *msb)
} }
if (be16_to_cpu(page->header.block_id) != MS_BLOCK_BOOT_ID) { if (be16_to_cpu(page->header.block_id) != MS_BLOCK_BOOT_ID) {
dbg("the pba at %d doesn' contain boot block ID", pba); dbg("the pba at %d doesn't contain boot block ID", pba);
continue; continue;
} }

Просмотреть файл

@ -68,6 +68,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{ {
struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_card *card = mmc_dev_to_card(dev);
const char *type; const char *type;
unsigned int i;
int retval = 0; int retval = 0;
switch (card->type) { switch (card->type) {
@ -98,6 +99,17 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
card->cis.vendor, card->cis.device); card->cis.vendor, card->cis.device);
if (retval) if (retval)
return retval; return retval;
retval = add_uevent_var(env, "SDIO_REVISION=%u.%u",
card->major_rev, card->minor_rev);
if (retval)
return retval;
for (i = 0; i < card->num_info; i++) {
retval = add_uevent_var(env, "SDIO_INFO%u=%s", i+1, card->info[i]);
if (retval)
return retval;
}
} }
/* /*

Просмотреть файл

@ -2063,6 +2063,16 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)
host->ops->hw_reset(host); host->ops->hw_reset(host);
} }
/**
* mmc_hw_reset - reset the card in hardware
* @host: MMC host to which the card is attached
*
* Hard reset the card. This function is only for upper layers, like the
* block layer or card drivers. You cannot use it in host drivers (struct
* mmc_card might be gone then).
*
* Return: 0 on success, -errno on failure
*/
int mmc_hw_reset(struct mmc_host *host) int mmc_hw_reset(struct mmc_host *host)
{ {
int ret; int ret;

Просмотреть файл

@ -376,6 +376,20 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
} }
EXPORT_SYMBOL(mmc_of_parse_voltage); EXPORT_SYMBOL(mmc_of_parse_voltage);
/**
* mmc_first_nonreserved_index() - get the first index that is not reserved
*/
static int mmc_first_nonreserved_index(void)
{
int max;
max = of_alias_get_highest_id("mmc");
if (max < 0)
return 0;
return max + 1;
}
/** /**
* mmc_alloc_host - initialise the per-host structure. * mmc_alloc_host - initialise the per-host structure.
* @extra: sizeof private data structure * @extra: sizeof private data structure
@ -387,6 +401,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{ {
int err; int err;
struct mmc_host *host; struct mmc_host *host;
int alias_id, min_idx, max_idx;
host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
if (!host) if (!host)
@ -395,7 +410,16 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
/* scanning will be enabled when we're ready */ /* scanning will be enabled when we're ready */
host->rescan_disable = 1; host->rescan_disable = 1;
err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL); alias_id = of_alias_get_id(dev->of_node, "mmc");
if (alias_id >= 0) {
min_idx = alias_id;
max_idx = alias_id + 1;
} else {
min_idx = mmc_first_nonreserved_index();
max_idx = 0;
}
err = ida_simple_get(&mmc_host_ida, min_idx, max_idx, GFP_KERNEL);
if (err < 0) { if (err < 0) {
kfree(host); kfree(host);
return NULL; return NULL;

Просмотреть файл

@ -1168,13 +1168,13 @@ static int mmc_select_hs400(struct mmc_card *card)
return err; return err;
} }
/* Set host controller to HS timing */
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
/* Prepare host to downgrade to HS timing */ /* Prepare host to downgrade to HS timing */
if (host->ops->hs400_downgrade) if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host); host->ops->hs400_downgrade(host);
/* Set host controller to HS timing */
mmc_set_timing(host, MMC_TIMING_MMC_HS);
/* Reduce frequency to HS frequency */ /* Reduce frequency to HS frequency */
max_dtr = card->ext_csd.hs_max_dtr; max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr); mmc_set_clock(host, max_dtr);
@ -1253,6 +1253,9 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
if (err) if (err)
goto out_err; goto out_err;
if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host);
mmc_set_timing(host, MMC_TIMING_MMC_DDR52); mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
err = mmc_switch_status(card, true); err = mmc_switch_status(card, true);
@ -1268,9 +1271,6 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
mmc_set_timing(host, MMC_TIMING_MMC_HS); mmc_set_timing(host, MMC_TIMING_MMC_HS);
if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host);
err = mmc_switch_status(card, true); err = mmc_switch_status(card, true);
if (err) if (err)
goto out_err; goto out_err;
@ -1763,13 +1763,17 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
goto free_card; goto free_card;
if (mmc_card_hs200(card)) { if (mmc_card_hs200(card)) {
host->doing_init_tune = 1;
err = mmc_hs200_tuning(card); err = mmc_hs200_tuning(card);
if (!err)
err = mmc_select_hs400(card);
host->doing_init_tune = 0;
if (err) if (err)
goto free_card; goto free_card;
err = mmc_select_hs400(card);
if (err)
goto free_card;
} else if (!mmc_card_hs400es(card)) { } else if (!mmc_card_hs400es(card)) {
/* Select the desired bus width optionally */ /* Select the desired bus width optionally */
err = mmc_select_bus_width(card); err = mmc_select_bus_width(card);

Просмотреть файл

@ -2669,22 +2669,22 @@ static const struct mmc_test_case mmc_test_cases[] = {
}, },
{ {
.name = "Correct xfer_size at write (start failure)", .name = "Proper xfer_size at write (start failure)",
.run = mmc_test_xfersize_write, .run = mmc_test_xfersize_write,
}, },
{ {
.name = "Correct xfer_size at read (start failure)", .name = "Proper xfer_size at read (start failure)",
.run = mmc_test_xfersize_read, .run = mmc_test_xfersize_read,
}, },
{ {
.name = "Correct xfer_size at write (midway failure)", .name = "Proper xfer_size at write (midway failure)",
.run = mmc_test_multi_xfersize_write, .run = mmc_test_multi_xfersize_write,
}, },
{ {
.name = "Correct xfer_size at read (midway failure)", .name = "Proper xfer_size at read (midway failure)",
.run = mmc_test_multi_xfersize_read, .run = mmc_test_multi_xfersize_read,
}, },

Просмотреть файл

@ -709,10 +709,34 @@ static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor); MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor);
MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device); MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device);
MMC_DEV_ATTR(revision, "%u.%u\n", card->major_rev, card->minor_rev);
#define sdio_info_attr(num) \
static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct mmc_card *card = mmc_dev_to_card(dev); \
\
if (num > card->num_info) \
return -ENODATA; \
if (!card->info[num-1][0]) \
return 0; \
return sprintf(buf, "%s\n", card->info[num-1]); \
} \
static DEVICE_ATTR_RO(info##num)
sdio_info_attr(1);
sdio_info_attr(2);
sdio_info_attr(3);
sdio_info_attr(4);
static struct attribute *sd_std_attrs[] = { static struct attribute *sd_std_attrs[] = {
&dev_attr_vendor.attr, &dev_attr_vendor.attr,
&dev_attr_device.attr, &dev_attr_device.attr,
&dev_attr_revision.attr,
&dev_attr_info1.attr,
&dev_attr_info2.attr,
&dev_attr_info3.attr,
&dev_attr_info4.attr,
&dev_attr_cid.attr, &dev_attr_cid.attr,
&dev_attr_csd.attr, &dev_attr_csd.attr,
&dev_attr_scr.attr, &dev_attr_scr.attr,
@ -735,12 +759,18 @@ static struct attribute *sd_std_attrs[] = {
static umode_t sd_std_is_visible(struct kobject *kobj, struct attribute *attr, static umode_t sd_std_is_visible(struct kobject *kobj, struct attribute *attr,
int index) int index)
{ {
struct device *dev = container_of(kobj, struct device, kobj); struct device *dev = kobj_to_dev(kobj);
struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_card *card = mmc_dev_to_card(dev);
/* CIS vendor and device ids are available only for Combo cards */ /* CIS vendor and device ids, revision and info string are available only for Combo cards */
if ((attr == &dev_attr_vendor.attr || attr == &dev_attr_device.attr) && if ((attr == &dev_attr_vendor.attr ||
card->type != MMC_TYPE_SD_COMBO) attr == &dev_attr_device.attr ||
attr == &dev_attr_revision.attr ||
attr == &dev_attr_info1.attr ||
attr == &dev_attr_info2.attr ||
attr == &dev_attr_info3.attr ||
attr == &dev_attr_info4.attr
) && card->type != MMC_TYPE_SD_COMBO)
return 0; return 0;
return attr->mode; return attr->mode;

Просмотреть файл

@ -29,12 +29,36 @@
MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor); MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor);
MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device); MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device);
MMC_DEV_ATTR(revision, "%u.%u\n", card->major_rev, card->minor_rev);
MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
#define sdio_info_attr(num) \
static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct mmc_card *card = mmc_dev_to_card(dev); \
\
if (num > card->num_info) \
return -ENODATA; \
if (!card->info[num-1][0]) \
return 0; \
return sprintf(buf, "%s\n", card->info[num-1]); \
} \
static DEVICE_ATTR_RO(info##num)
sdio_info_attr(1);
sdio_info_attr(2);
sdio_info_attr(3);
sdio_info_attr(4);
static struct attribute *sdio_std_attrs[] = { static struct attribute *sdio_std_attrs[] = {
&dev_attr_vendor.attr, &dev_attr_vendor.attr,
&dev_attr_device.attr, &dev_attr_device.attr,
&dev_attr_revision.attr,
&dev_attr_info1.attr,
&dev_attr_info2.attr,
&dev_attr_info3.attr,
&dev_attr_info4.attr,
&dev_attr_ocr.attr, &dev_attr_ocr.attr,
&dev_attr_rca.attr, &dev_attr_rca.attr,
NULL, NULL,

Просмотреть файл

@ -28,34 +28,50 @@
#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) #define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
/* show configuration fields */ /* show configuration fields */
#define sdio_config_attr(field, format_string) \ #define sdio_config_attr(field, format_string, args...) \
static ssize_t \ static ssize_t \
field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \ { \
struct sdio_func *func; \ struct sdio_func *func; \
\ \
func = dev_to_sdio_func (dev); \ func = dev_to_sdio_func (dev); \
return sprintf (buf, format_string, func->field); \ return sprintf(buf, format_string, args); \
} \ } \
static DEVICE_ATTR_RO(field) static DEVICE_ATTR_RO(field)
sdio_config_attr(class, "0x%02x\n"); sdio_config_attr(class, "0x%02x\n", func->class);
sdio_config_attr(vendor, "0x%04x\n"); sdio_config_attr(vendor, "0x%04x\n", func->vendor);
sdio_config_attr(device, "0x%04x\n"); sdio_config_attr(device, "0x%04x\n", func->device);
sdio_config_attr(revision, "%u.%u\n", func->major_rev, func->minor_rev);
sdio_config_attr(modalias, "sdio:c%02Xv%04Xd%04X\n", func->class, func->vendor, func->device);
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) #define sdio_info_attr(num) \
{ static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf) \
struct sdio_func *func = dev_to_sdio_func (dev); { \
struct sdio_func *func = dev_to_sdio_func(dev); \
\
if (num > func->num_info) \
return -ENODATA; \
if (!func->info[num-1][0]) \
return 0; \
return sprintf(buf, "%s\n", func->info[num-1]); \
} \
static DEVICE_ATTR_RO(info##num)
return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n", sdio_info_attr(1);
func->class, func->vendor, func->device); sdio_info_attr(2);
} sdio_info_attr(3);
static DEVICE_ATTR_RO(modalias); sdio_info_attr(4);
static struct attribute *sdio_dev_attrs[] = { static struct attribute *sdio_dev_attrs[] = {
&dev_attr_class.attr, &dev_attr_class.attr,
&dev_attr_vendor.attr, &dev_attr_vendor.attr,
&dev_attr_device.attr, &dev_attr_device.attr,
&dev_attr_revision.attr,
&dev_attr_info1.attr,
&dev_attr_info2.attr,
&dev_attr_info3.attr,
&dev_attr_info4.attr,
&dev_attr_modalias.attr, &dev_attr_modalias.attr,
NULL, NULL,
}; };
@ -106,6 +122,7 @@ static int
sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env) sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{ {
struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_func *func = dev_to_sdio_func(dev);
unsigned int i;
if (add_uevent_var(env, if (add_uevent_var(env,
"SDIO_CLASS=%02X", func->class)) "SDIO_CLASS=%02X", func->class))
@ -115,6 +132,15 @@ sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
"SDIO_ID=%04X:%04X", func->vendor, func->device)) "SDIO_ID=%04X:%04X", func->vendor, func->device))
return -ENOMEM; return -ENOMEM;
if (add_uevent_var(env,
"SDIO_REVISION=%u.%u", func->major_rev, func->minor_rev))
return -ENOMEM;
for (i = 0; i < func->num_info; i++) {
if (add_uevent_var(env, "SDIO_INFO%u=%s", i+1, func->info[i]))
return -ENOMEM;
}
if (add_uevent_var(env, if (add_uevent_var(env,
"MODALIAS=sdio:c%02Xv%04Xd%04X", "MODALIAS=sdio:c%02Xv%04Xd%04X",
func->class, func->vendor, func->device)) func->class, func->vendor, func->device))

Просмотреть файл

@ -23,9 +23,16 @@
static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func, static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
const unsigned char *buf, unsigned size) const unsigned char *buf, unsigned size)
{ {
u8 major_rev, minor_rev;
unsigned i, nr_strings; unsigned i, nr_strings;
char **buffer, *string; char **buffer, *string;
if (size < 2)
return 0;
major_rev = buf[0];
minor_rev = buf[1];
/* Find all null-terminated (including zero length) strings in /* Find all null-terminated (including zero length) strings in
the TPLLV1_INFO field. Trailing garbage is ignored. */ the TPLLV1_INFO field. Trailing garbage is ignored. */
buf += 2; buf += 2;
@ -57,9 +64,13 @@ static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
} }
if (func) { if (func) {
func->major_rev = major_rev;
func->minor_rev = minor_rev;
func->num_info = nr_strings; func->num_info = nr_strings;
func->info = (const char**)buffer; func->info = (const char**)buffer;
} else { } else {
card->major_rev = major_rev;
card->minor_rev = minor_rev;
card->num_info = nr_strings; card->num_info = nr_strings;
card->info = (const char**)buffer; card->info = (const char**)buffer;
} }

Просмотреть файл

@ -178,7 +178,7 @@ config MMC_SDHCI_OF_AT91
config MMC_SDHCI_OF_ESDHC config MMC_SDHCI_OF_ESDHC
tristate "SDHCI OF support for the Freescale eSDHC controller" tristate "SDHCI OF support for the Freescale eSDHC controller"
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
select FSL_GUTS select FSL_GUTS
help help
@ -213,6 +213,18 @@ config MMC_SDHCI_OF_DWCMSHC
If you have a controller with this interface, say Y or M here. If you have a controller with this interface, say Y or M here.
If unsure, say N. If unsure, say N.
config MMC_SDHCI_OF_SPARX5
tristate "SDHCI OF support for the MCHP Sparx5 SoC"
depends on MMC_SDHCI_PLTFM
depends on ARCH_SPARX5 || COMPILE_TEST
help
This selects the Secure Digital Host Controller Interface (SDHCI)
found in the MCHP Sparx5 SoC.
If you have a Sparx5 SoC with this interface, say Y or M here.
If unsure, say N.
config MMC_SDHCI_CADENCE config MMC_SDHCI_CADENCE
tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller" tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
@ -226,7 +238,7 @@ config MMC_SDHCI_CADENCE
config MMC_SDHCI_CNS3XXX config MMC_SDHCI_CNS3XXX
tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
depends on ARCH_CNS3XXX depends on ARCH_CNS3XXX || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
help help
This selects the SDHCI support for CNS3xxx System-on-Chip devices. This selects the SDHCI support for CNS3xxx System-on-Chip devices.
@ -250,7 +262,7 @@ config MMC_SDHCI_ESDHC_MCF
config MMC_SDHCI_ESDHC_IMX config MMC_SDHCI_ESDHC_IMX
tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
depends on ARCH_MXC depends on ARCH_MXC || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
select MMC_CQHCI select MMC_CQHCI
@ -264,7 +276,7 @@ config MMC_SDHCI_ESDHC_IMX
config MMC_SDHCI_DOVE config MMC_SDHCI_DOVE
tristate "SDHCI support on Marvell's Dove SoC" tristate "SDHCI support on Marvell's Dove SoC"
depends on ARCH_DOVE || MACH_DOVE depends on ARCH_DOVE || MACH_DOVE || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
help help
@ -277,7 +289,7 @@ config MMC_SDHCI_DOVE
config MMC_SDHCI_TEGRA config MMC_SDHCI_TEGRA
tristate "SDHCI platform support for the Tegra SD/MMC Controller" tristate "SDHCI platform support for the Tegra SD/MMC Controller"
depends on ARCH_TEGRA depends on ARCH_TEGRA || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
select MMC_CQHCI select MMC_CQHCI
@ -289,7 +301,8 @@ config MMC_SDHCI_TEGRA
config MMC_SDHCI_S3C config MMC_SDHCI_S3C
tristate "SDHCI support on Samsung S3C SoC" tristate "SDHCI support on Samsung S3C SoC"
depends on MMC_SDHCI && PLAT_SAMSUNG depends on MMC_SDHCI
depends on PLAT_SAMSUNG || COMPILE_TEST
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
often referrered to as the HSMMC block in some of the Samsung S3C often referrered to as the HSMMC block in some of the Samsung S3C
@ -301,7 +314,7 @@ config MMC_SDHCI_S3C
config MMC_SDHCI_SIRF config MMC_SDHCI_SIRF
tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs" tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs"
depends on ARCH_SIRF depends on ARCH_SIRF || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
help help
@ -339,7 +352,8 @@ config MMC_SDHCI_PXAV2
config MMC_SDHCI_SPEAR config MMC_SDHCI_SPEAR
tristate "SDHCI support on ST SPEAr platform" tristate "SDHCI support on ST SPEAr platform"
depends on MMC_SDHCI && PLAT_SPEAR depends on MMC_SDHCI
depends on PLAT_SPEAR || COMPILE_TEST
depends on OF depends on OF
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
@ -362,7 +376,7 @@ config MMC_SDHCI_S3C_DMA
config MMC_SDHCI_BCM_KONA config MMC_SDHCI_BCM_KONA
tristate "SDHCI support on Broadcom KONA platform" tristate "SDHCI support on Broadcom KONA platform"
depends on ARCH_BCM_MOBILE depends on ARCH_BCM_MOBILE || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
help help
This selects the Broadcom Kona Secure Digital Host Controller This selects the Broadcom Kona Secure Digital Host Controller
@ -410,7 +424,8 @@ config MMC_SDHCI_IPROC
config MMC_MESON_GX config MMC_MESON_GX
tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support" tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support"
depends on ARCH_MESON && MMC depends on ARCH_MESON|| COMPILE_TEST
depends on COMMON_CLK
help help
This selects support for the Amlogic SD/MMC Host Controller This selects support for the Amlogic SD/MMC Host Controller
found on the S905/GX*/AXG family of SoCs. This controller is found on the S905/GX*/AXG family of SoCs. This controller is
@ -446,7 +461,7 @@ config MMC_MESON_MX_SDIO
config MMC_MOXART config MMC_MOXART
tristate "MOXART SD/MMC Host Controller support" tristate "MOXART SD/MMC Host Controller support"
depends on ARCH_MOXART && MMC depends on ARCH_MOXART || COMPILE_TEST
help help
This selects support for the MOXART SD/MMC Host Controller. This selects support for the MOXART SD/MMC Host Controller.
MOXA provides one multi-functional card reader which can MOXA provides one multi-functional card reader which can
@ -455,7 +470,7 @@ config MMC_MOXART
config MMC_SDHCI_ST config MMC_SDHCI_ST
tristate "SDHCI support on STMicroelectronics SoC" tristate "SDHCI support on STMicroelectronics SoC"
depends on ARCH_STI || FSP2 depends on ARCH_STI || FSP2 || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
help help
@ -525,7 +540,7 @@ config MMC_ATMELMCI
config MMC_SDHCI_MSM config MMC_SDHCI_MSM
tristate "Qualcomm SDHCI Controller Support" tristate "Qualcomm SDHCI Controller Support"
depends on ARCH_QCOM || (ARM && COMPILE_TEST) depends on ARCH_QCOM || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
select MMC_CQHCI select MMC_CQHCI
@ -575,7 +590,7 @@ config MMC_TIFM_SD
config MMC_MVSDIO config MMC_MVSDIO
tristate "Marvell MMC/SD/SDIO host driver" tristate "Marvell MMC/SD/SDIO host driver"
depends on PLAT_ORION depends on PLAT_ORION || (COMPILE_TEST && ARM)
depends on OF depends on OF
help help
This selects the Marvell SDIO host driver. This selects the Marvell SDIO host driver.
@ -587,7 +602,7 @@ config MMC_MVSDIO
config MMC_DAVINCI config MMC_DAVINCI
tristate "TI DAVINCI Multimedia Card Interface support" tristate "TI DAVINCI Multimedia Card Interface support"
depends on ARCH_DAVINCI depends on ARCH_DAVINCI || COMPILE_TEST
help help
This selects the TI DAVINCI Multimedia card Interface. This selects the TI DAVINCI Multimedia card Interface.
If you have an DAVINCI board with a Multimedia Card slot, If you have an DAVINCI board with a Multimedia Card slot,
@ -669,7 +684,7 @@ config MMC_SDRICOH_CS
config MMC_SDHCI_SPRD config MMC_SDHCI_SPRD
tristate "Spreadtrum SDIO host Controller" tristate "Spreadtrum SDIO host Controller"
depends on ARCH_SPRD depends on ARCH_SPRD || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
select MMC_HSQ select MMC_HSQ
@ -686,7 +701,7 @@ config MMC_TMIO_CORE
config MMC_TMIO config MMC_TMIO
tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
depends on MFD_TMIO || MFD_ASIC3 depends on MFD_TMIO || MFD_ASIC3 || COMPILE_TEST
select MMC_TMIO_CORE select MMC_TMIO_CORE
help help
This provides support for the SD/MMC cell found in TC6393XB, This provides support for the SD/MMC cell found in TC6393XB,
@ -777,7 +792,7 @@ config MMC_CAVIUM_THUNDERX
config MMC_DW config MMC_DW
tristate "Synopsys DesignWare Memory Card Interface" tristate "Synopsys DesignWare Memory Card Interface"
depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST depends on ARC || ARM || ARM64 || MIPS || RISCV || CSKY || COMPILE_TEST
help help
This selects support for the Synopsys DesignWare Mobile Storage IP This selects support for the Synopsys DesignWare Mobile Storage IP
block, this provides host support for SD and MMC interfaces, in both block, this provides host support for SD and MMC interfaces, in both
@ -959,7 +974,7 @@ config MMC_REALTEK_USB
config MMC_SUNXI config MMC_SUNXI
tristate "Allwinner sunxi SD/MMC Host Controller support" tristate "Allwinner sunxi SD/MMC Host Controller support"
depends on ARCH_SUNXI depends on ARCH_SUNXI || COMPILE_TEST
help help
This selects support for the SD/MMC Host Controller on This selects support for the SD/MMC Host Controller on
Allwinner sunxi SoCs. Allwinner sunxi SoCs.

Просмотреть файл

@ -94,6 +94,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o
obj-$(CONFIG_MMC_SDHCI_OF_SPARX5) += sdhci-of-sparx5.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o

Просмотреть файл

@ -1178,6 +1178,7 @@ static struct platform_driver alcor_pci_sdmmc_driver = {
.id_table = alcor_pci_sdmmc_ids, .id_table = alcor_pci_sdmmc_ids,
.driver = { .driver = {
.name = DRV_NAME_ALCOR_PCI_SDMMC, .name = DRV_NAME_ALCOR_PCI_SDMMC,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &alcor_mmc_pm_ops .pm = &alcor_mmc_pm_ops
}, },
}; };

Просмотреть файл

@ -537,6 +537,7 @@ static struct platform_driver goldfish_mmc_driver = {
.remove = goldfish_mmc_remove, .remove = goldfish_mmc_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
}, },
}; };

Просмотреть файл

@ -2668,6 +2668,7 @@ static struct platform_driver atmci_driver = {
.remove = atmci_remove, .remove = atmci_remove,
.driver = { .driver = {
.name = "atmel_mci", .name = "atmel_mci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(atmci_dt_ids), .of_match_table = of_match_ptr(atmci_dt_ids),
.pm = &atmci_dev_pm_ops, .pm = &atmci_dev_pm_ops,
}, },

Просмотреть файл

@ -1189,6 +1189,7 @@ static struct platform_driver au1xmmc_driver = {
.resume = au1xmmc_resume, .resume = au1xmmc_resume,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
}, },
}; };

Просмотреть файл

@ -1406,9 +1406,7 @@ static int bcm2835_probe(struct platform_device *pdev)
clk = devm_clk_get(dev, NULL); clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
ret = PTR_ERR(clk); ret = dev_err_probe(dev, PTR_ERR(clk), "could not get clk\n");
if (ret != -EPROBE_DEFER)
dev_err(dev, "could not get clk: %d\n", ret);
goto err; goto err;
} }
@ -1476,6 +1474,7 @@ static struct platform_driver bcm2835_driver = {
.remove = bcm2835_remove, .remove = bcm2835_remove,
.driver = { .driver = {
.name = "sdhost-bcm2835", .name = "sdhost-bcm2835",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = bcm2835_match, .of_match_table = bcm2835_match,
}, },
}; };

Просмотреть файл

@ -327,6 +327,7 @@ static struct platform_driver octeon_mmc_driver = {
.remove = octeon_mmc_remove, .remove = octeon_mmc_remove,
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = octeon_mmc_match, .of_match_table = octeon_mmc_match,
}, },
}; };

Просмотреть файл

@ -376,6 +376,9 @@ static void cqhci_off(struct mmc_host *mmc)
else else
pr_debug("%s: cqhci: CQE off\n", mmc_hostname(mmc)); pr_debug("%s: cqhci: CQE off\n", mmc_hostname(mmc));
if (cq_host->ops->post_disable)
cq_host->ops->post_disable(mmc);
mmc->cqe_on = false; mmc->cqe_on = false;
} }
@ -580,6 +583,9 @@ static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
__cqhci_enable(cq_host); __cqhci_enable(cq_host);
if (!mmc->cqe_on) { if (!mmc->cqe_on) {
if (cq_host->ops->pre_enable)
cq_host->ops->pre_enable(mmc);
cqhci_writel(cq_host, 0, CQHCI_CTL); cqhci_writel(cq_host, 0, CQHCI_CTL);
mmc->cqe_on = true; mmc->cqe_on = true;
pr_debug("%s: cqhci: CQE on\n", mmc_hostname(mmc)); pr_debug("%s: cqhci: CQE on\n", mmc_hostname(mmc));

Просмотреть файл

@ -206,6 +206,8 @@ struct cqhci_host_ops {
void (*disable)(struct mmc_host *mmc, bool recovery); void (*disable)(struct mmc_host *mmc, bool recovery);
void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq, void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq,
u64 *data); u64 *data);
void (*pre_enable)(struct mmc_host *mmc);
void (*post_disable)(struct mmc_host *mmc);
}; };
static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg)

Просмотреть файл

@ -996,7 +996,7 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
if (qstatus & MMCST0_RSPDNE) { if (qstatus & MMCST0_RSPDNE) {
/* End of command phase */ /* End of command phase */
end_command = (int) host->cmd; end_command = host->cmd ? 1 : 0;
} }
if (end_command) if (end_command)
@ -1240,9 +1240,8 @@ static int davinci_mmcsd_probe(struct platform_device *pdev)
pdev->id_entry = match->data; pdev->id_entry = match->data;
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret) { if (ret) {
if (ret != -EPROBE_DEFER) dev_err_probe(&pdev->dev, ret,
dev_err(&pdev->dev, "could not parse of data\n");
"could not parse of data: %d\n", ret);
goto parse_fail; goto parse_fail;
} }
} else { } else {
@ -1396,6 +1395,7 @@ static const struct dev_pm_ops davinci_mmcsd_pm = {
static struct platform_driver davinci_mmcsd_driver = { static struct platform_driver davinci_mmcsd_driver = {
.driver = { .driver = {
.name = "davinci_mmc", .name = "davinci_mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = davinci_mmcsd_pm_ops, .pm = davinci_mmcsd_pm_ops,
.of_match_table = davinci_mmc_dt_ids, .of_match_table = davinci_mmc_dt_ids,
}, },

Просмотреть файл

@ -55,6 +55,7 @@ static struct platform_driver dw_mci_bluefield_pltfm_driver = {
.remove = dw_mci_pltfm_remove, .remove = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dwmmc_bluefield", .name = "dwmmc_bluefield",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_bluefield_match, .of_match_table = dw_mci_bluefield_match,
.pm = &dw_mci_pltfm_pmops, .pm = &dw_mci_pltfm_pmops,
}, },

Просмотреть файл

@ -592,6 +592,7 @@ static struct platform_driver dw_mci_exynos_pltfm_driver = {
.remove = dw_mci_exynos_remove, .remove = dw_mci_exynos_remove,
.driver = { .driver = {
.name = "dwmmc_exynos", .name = "dwmmc_exynos",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_exynos_match, .of_match_table = dw_mci_exynos_match,
.pm = &dw_mci_exynos_pmops, .pm = &dw_mci_exynos_pmops,
}, },

Просмотреть файл

@ -200,6 +200,7 @@ static struct platform_driver dw_mci_hi3798cv200_driver = {
.remove = dw_mci_hi3798cv200_remove, .remove = dw_mci_hi3798cv200_remove,
.driver = { .driver = {
.name = "dwmmc_hi3798cv200", .name = "dwmmc_hi3798cv200",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_hi3798cv200_match, .of_match_table = dw_mci_hi3798cv200_match,
}, },
}; };

Просмотреть файл

@ -473,6 +473,7 @@ static struct platform_driver dw_mci_k3_pltfm_driver = {
.remove = dw_mci_pltfm_remove, .remove = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dwmmc_k3", .name = "dwmmc_k3",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_k3_match, .of_match_table = dw_mci_k3_match,
.pm = &dw_mci_k3_dev_pm_ops, .pm = &dw_mci_k3_dev_pm_ops,
}, },

Просмотреть файл

@ -98,6 +98,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
.remove = dw_mci_pltfm_remove, .remove = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dw_mmc", .name = "dw_mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_pltfm_match, .of_match_table = dw_mci_pltfm_match,
.pm = &dw_mci_pltfm_pmops, .pm = &dw_mci_pltfm_pmops,
}, },

Просмотреть файл

@ -383,6 +383,7 @@ static struct platform_driver dw_mci_rockchip_pltfm_driver = {
.remove = dw_mci_rockchip_remove, .remove = dw_mci_rockchip_remove,
.driver = { .driver = {
.name = "dwmmc_rockchip", .name = "dwmmc_rockchip",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_rockchip_match, .of_match_table = dw_mci_rockchip_match,
.pm = &dw_mci_rockchip_dev_pm_ops, .pm = &dw_mci_rockchip_dev_pm_ops,
}, },

Просмотреть файл

@ -155,7 +155,6 @@ static int dw_mci_zx_parse_dt(struct dw_mci *host)
struct device_node *node; struct device_node *node;
struct dw_mci_zx_priv_data *priv; struct dw_mci_zx_priv_data *priv;
struct regmap *sysc_base; struct regmap *sysc_base;
int ret;
/* syscon is needed only by emmc */ /* syscon is needed only by emmc */
node = of_parse_phandle(np, "zte,aon-syscon", 0); node = of_parse_phandle(np, "zte,aon-syscon", 0);
@ -163,13 +162,9 @@ static int dw_mci_zx_parse_dt(struct dw_mci *host)
sysc_base = syscon_node_to_regmap(node); sysc_base = syscon_node_to_regmap(node);
of_node_put(node); of_node_put(node);
if (IS_ERR(sysc_base)) { if (IS_ERR(sysc_base))
ret = PTR_ERR(sysc_base); return dev_err_probe(host->dev, PTR_ERR(sysc_base),
if (ret != -EPROBE_DEFER) "Can't get syscon\n");
dev_err(host->dev, "Can't get syscon: %d\n",
ret);
return ret;
}
} else { } else {
return 0; return 0;
} }
@ -227,6 +222,7 @@ static struct platform_driver dw_mci_zx_pltfm_driver = {
.remove = dw_mci_pltfm_remove, .remove = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dwmmc_zx", .name = "dwmmc_zx",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_zx_match, .of_match_table = dw_mci_zx_match,
.pm = &dw_mci_zx_dev_pm_ops, .pm = &dw_mci_zx_dev_pm_ops,
}, },

Просмотреть файл

@ -3161,12 +3161,9 @@ int dw_mci_probe(struct dw_mci *host)
if (!host->pdata) { if (!host->pdata) {
host->pdata = dw_mci_parse_dt(host); host->pdata = dw_mci_parse_dt(host);
if (PTR_ERR(host->pdata) == -EPROBE_DEFER) { if (IS_ERR(host->pdata))
return -EPROBE_DEFER; return dev_err_probe(host->dev, PTR_ERR(host->pdata),
} else if (IS_ERR(host->pdata)) { "platform data not available\n");
dev_err(host->dev, "platform data not available\n");
return -EINVAL;
}
} }
host->biu_clk = devm_clk_get(host->dev, "biu"); host->biu_clk = devm_clk_get(host->dev, "biu");

Просмотреть файл

@ -991,9 +991,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret) { if (ret) {
if (ret != -EPROBE_DEFER) dev_err_probe(&pdev->dev, ret, "could not parse device properties\n");
dev_err(&pdev->dev,
"could not parse device properties: %d\n", ret);
goto err_free_host; goto err_free_host;
} }
@ -1126,6 +1124,7 @@ static struct platform_driver jz4740_mmc_driver = {
.remove = jz4740_mmc_remove, .remove = jz4740_mmc_remove,
.driver = { .driver = {
.name = "jz4740-mmc", .name = "jz4740-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(jz4740_mmc_of_match), .of_match_table = of_match_ptr(jz4740_mmc_of_match),
.pm = pm_ptr(&jz4740_mmc_pm_ops), .pm = pm_ptr(&jz4740_mmc_pm_ops),
}, },

Просмотреть файл

@ -426,11 +426,9 @@ static int meson_mmc_clk_init(struct meson_host *host)
snprintf(name, sizeof(name), "clkin%d", i); snprintf(name, sizeof(name), "clkin%d", i);
clk = devm_clk_get(host->dev, name); clk = devm_clk_get(host->dev, name);
if (IS_ERR(clk)) { if (IS_ERR(clk))
if (clk != ERR_PTR(-EPROBE_DEFER)) return dev_err_probe(host->dev, PTR_ERR(clk),
dev_err(host->dev, "Missing clock %s\n", name); "Missing clock %s\n", name);
return PTR_ERR(clk);
}
mux_parent_names[i] = __clk_get_name(clk); mux_parent_names[i] = __clk_get_name(clk);
} }
@ -521,7 +519,7 @@ static int meson_mmc_resampling_tuning(struct mmc_host *mmc, u32 opcode)
val |= ADJUST_ADJ_EN; val |= ADJUST_ADJ_EN;
writel(val, host->regs + host->data->adjust); writel(val, host->regs + host->data->adjust);
if (mmc->doing_retune) if (mmc_doing_retune(mmc))
dly = FIELD_GET(ADJUST_ADJ_DELAY_MASK, val) + 1; dly = FIELD_GET(ADJUST_ADJ_DELAY_MASK, val) + 1;
else else
dly = 0; dly = 0;
@ -1077,12 +1075,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
} }
ret = device_reset_optional(&pdev->dev); ret = device_reset_optional(&pdev->dev);
if (ret) { if (ret)
if (ret != -EPROBE_DEFER) return dev_err_probe(&pdev->dev, ret, "device reset failed\n");
dev_err(&pdev->dev, "device reset failed: %d\n", ret);
return ret;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->regs = devm_ioremap_resource(&pdev->dev, res); host->regs = devm_ioremap_resource(&pdev->dev, res);
@ -1270,6 +1264,7 @@ static struct platform_driver meson_mmc_driver = {
.remove = meson_mmc_remove, .remove = meson_mmc_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(meson_mmc_of_match), .of_match_table = of_match_ptr(meson_mmc_of_match),
}, },
}; };

Просмотреть файл

@ -903,6 +903,7 @@ static struct platform_driver meson_mx_sdhc_driver = {
.remove = meson_mx_sdhc_remove, .remove = meson_mx_sdhc_remove,
.driver = { .driver = {
.name = "meson-mx-sdhc", .name = "meson-mx-sdhc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(meson_mx_sdhc_of_match), .of_match_table = of_match_ptr(meson_mx_sdhc_of_match),
}, },
}; };

Просмотреть файл

@ -755,6 +755,7 @@ static struct platform_driver meson_mx_mmc_driver = {
.remove = meson_mx_mmc_remove, .remove = meson_mx_mmc_remove,
.driver = { .driver = {
.name = "meson-mx-sdio", .name = "meson-mx-sdio",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(meson_mx_mmc_of_match), .of_match_table = of_match_ptr(meson_mx_mmc_of_match),
}, },
}; };

Просмотреть файл

@ -882,9 +882,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
else else
clock_rate = spi->max_speed_hz; clock_rate = spi->max_speed_hz;
timeout = data->timeout_ns + timeout = data->timeout_ns / 1000 +
data->timeout_clks * 1000000 / clock_rate; data->timeout_clks * 1000000 / clock_rate;
timeout = usecs_to_jiffies((unsigned int)(timeout / 1000)) + 1; timeout = usecs_to_jiffies((unsigned int)timeout) + 1;
/* Handle scatterlist segments one at a time, with synch for /* Handle scatterlist segments one at a time, with synch for
* each 512-byte block * each 512-byte block

Просмотреть файл

@ -689,19 +689,18 @@ static int moxart_remove(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, NULL); dev_set_drvdata(&pdev->dev, NULL);
if (mmc) { if (!IS_ERR(host->dma_chan_tx))
if (!IS_ERR(host->dma_chan_tx)) dma_release_channel(host->dma_chan_tx);
dma_release_channel(host->dma_chan_tx); if (!IS_ERR(host->dma_chan_rx))
if (!IS_ERR(host->dma_chan_rx)) dma_release_channel(host->dma_chan_rx);
dma_release_channel(host->dma_chan_rx); mmc_remove_host(mmc);
mmc_remove_host(mmc); mmc_free_host(mmc);
mmc_free_host(mmc);
writel(0, host->base + REG_INTERRUPT_MASK);
writel(0, host->base + REG_POWER_CONTROL);
writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
host->base + REG_CLOCK_CONTROL);
writel(0, host->base + REG_INTERRUPT_MASK);
writel(0, host->base + REG_POWER_CONTROL);
writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
host->base + REG_CLOCK_CONTROL);
}
return 0; return 0;
} }
@ -717,6 +716,7 @@ static struct platform_driver moxart_mmc_driver = {
.remove = moxart_remove, .remove = moxart_remove,
.driver = { .driver = {
.name = "mmc-moxart", .name = "mmc-moxart",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = moxart_mmc_match, .of_match_table = moxart_mmc_match,
}, },
}; };

Просмотреть файл

@ -397,7 +397,6 @@ struct msdc_delay_phase {
struct msdc_host { struct msdc_host {
struct device *dev; struct device *dev;
const struct mtk_mmc_compatible *dev_comp; const struct mtk_mmc_compatible *dev_comp;
struct mmc_host *mmc; /* mmc structure */
int cmd_rsp; int cmd_rsp;
spinlock_t lock; spinlock_t lock;
@ -734,14 +733,15 @@ static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq)
static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks) static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks)
{ {
struct mmc_host *mmc = mmc_from_priv(host);
u64 timeout, clk_ns; u64 timeout, clk_ns;
u32 mode = 0; u32 mode = 0;
if (host->mmc->actual_clock == 0) { if (mmc->actual_clock == 0) {
timeout = 0; timeout = 0;
} else { } else {
clk_ns = 1000000000ULL; clk_ns = 1000000000ULL;
do_div(clk_ns, host->mmc->actual_clock); do_div(clk_ns, mmc->actual_clock);
timeout = ns + clk_ns - 1; timeout = ns + clk_ns - 1;
do_div(timeout, clk_ns); do_div(timeout, clk_ns);
timeout += clks; timeout += clks;
@ -802,6 +802,7 @@ static void msdc_ungate_clock(struct msdc_host *host)
static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
{ {
struct mmc_host *mmc = mmc_from_priv(host);
u32 mode; u32 mode;
u32 flags; u32 flags;
u32 div; u32 div;
@ -811,7 +812,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
if (!hz) { if (!hz) {
dev_dbg(host->dev, "set mclk to 0\n"); dev_dbg(host->dev, "set mclk to 0\n");
host->mclk = 0; host->mclk = 0;
host->mmc->actual_clock = 0; mmc->actual_clock = 0;
sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
return; return;
} }
@ -890,7 +891,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
cpu_relax(); cpu_relax();
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
host->mmc->actual_clock = sclk; mmc->actual_clock = sclk;
host->mclk = hz; host->mclk = hz;
host->timing = timing; host->timing = timing;
/* need because clk changed. */ /* need because clk changed. */
@ -901,7 +902,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
* mmc_select_hs400() will drop to 50Mhz and High speed mode, * mmc_select_hs400() will drop to 50Mhz and High speed mode,
* tune result of hs200/200Mhz is not suitable for 50Mhz * tune result of hs200/200Mhz is not suitable for 50Mhz
*/ */
if (host->mmc->actual_clock <= 52000000) { if (mmc->actual_clock <= 52000000) {
writel(host->def_tune_para.iocon, host->base + MSDC_IOCON); writel(host->def_tune_para.iocon, host->base + MSDC_IOCON);
if (host->top_base) { if (host->top_base) {
writel(host->def_tune_para.emmc_top_control, writel(host->def_tune_para.emmc_top_control,
@ -932,7 +933,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
sdr_set_field(host->base + tune_reg, sdr_set_field(host->base + tune_reg,
MSDC_PAD_TUNE_CMDRRDLY, MSDC_PAD_TUNE_CMDRRDLY,
host->hs400_cmd_int_delay); host->hs400_cmd_int_delay);
dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->mmc->actual_clock, dev_dbg(host->dev, "sclk: %d, timing: %d\n", mmc->actual_clock,
timing); timing);
} }
@ -967,6 +968,7 @@ static inline u32 msdc_cmd_find_resp(struct msdc_host *host,
static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd) struct mmc_request *mrq, struct mmc_command *cmd)
{ {
struct mmc_host *mmc = mmc_from_priv(host);
/* rawcmd : /* rawcmd :
* vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 | * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 |
* stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode
@ -993,7 +995,7 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
struct mmc_data *data = cmd->data; struct mmc_data *data = cmd->data;
if (mmc_op_multi(opcode)) { if (mmc_op_multi(opcode)) {
if (mmc_card_mmc(host->mmc->card) && mrq->sbc && if (mmc_card_mmc(mmc->card) && mrq->sbc &&
!(mrq->sbc->arg & 0xFFFF0000)) !(mrq->sbc->arg & 0xFFFF0000))
rawcmd |= 0x2 << 28; /* AutoCMD23 */ rawcmd |= 0x2 << 28; /* AutoCMD23 */
} }
@ -1070,9 +1072,10 @@ static int msdc_auto_cmd_done(struct msdc_host *host, int events,
*/ */
static void msdc_recheck_sdio_irq(struct msdc_host *host) static void msdc_recheck_sdio_irq(struct msdc_host *host)
{ {
struct mmc_host *mmc = mmc_from_priv(host);
u32 reg_int, reg_inten, reg_ps; u32 reg_int, reg_inten, reg_ps;
if (host->mmc->caps & MMC_CAP_SDIO_IRQ) { if (mmc->caps & MMC_CAP_SDIO_IRQ) {
reg_inten = readl(host->base + MSDC_INTEN); reg_inten = readl(host->base + MSDC_INTEN);
if (reg_inten & MSDC_INTEN_SDIOIRQ) { if (reg_inten & MSDC_INTEN_SDIOIRQ) {
reg_int = readl(host->base + MSDC_INT); reg_int = readl(host->base + MSDC_INT);
@ -1080,7 +1083,7 @@ static void msdc_recheck_sdio_irq(struct msdc_host *host)
if (!(reg_int & MSDC_INT_SDIOIRQ || if (!(reg_int & MSDC_INT_SDIOIRQ ||
reg_ps & MSDC_PS_DATA1)) { reg_ps & MSDC_PS_DATA1)) {
__msdc_enable_sdio_irq(host, 0); __msdc_enable_sdio_irq(host, 0);
sdio_signal_irq(host->mmc); sdio_signal_irq(mmc);
} }
} }
} }
@ -1113,7 +1116,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
msdc_unprepare_data(host, mrq); msdc_unprepare_data(host, mrq);
if (host->error) if (host->error)
msdc_reset_hw(host); msdc_reset_hw(host);
mmc_request_done(host->mmc, mrq); mmc_request_done(mmc_from_priv(host), mrq);
if (host->dev_comp->recheck_sdio_irq) if (host->dev_comp->recheck_sdio_irq)
msdc_recheck_sdio_irq(host); msdc_recheck_sdio_irq(host);
} }
@ -1500,6 +1503,7 @@ static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts) static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts)
{ {
struct mmc_host *mmc = mmc_from_priv(host);
int cmd_err = 0, dat_err = 0; int cmd_err = 0, dat_err = 0;
if (intsts & MSDC_INT_RSPCRCERR) { if (intsts & MSDC_INT_RSPCRCERR) {
@ -1523,12 +1527,13 @@ static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts)
cmd_err, dat_err, intsts); cmd_err, dat_err, intsts);
} }
return cqhci_irq(host->mmc, 0, cmd_err, dat_err); return cqhci_irq(mmc, 0, cmd_err, dat_err);
} }
static irqreturn_t msdc_irq(int irq, void *dev_id) static irqreturn_t msdc_irq(int irq, void *dev_id)
{ {
struct msdc_host *host = (struct msdc_host *) dev_id; struct msdc_host *host = (struct msdc_host *) dev_id;
struct mmc_host *mmc = mmc_from_priv(host);
while (true) { while (true) {
unsigned long flags; unsigned long flags;
@ -1551,18 +1556,18 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
if ((events & event_mask) & MSDC_INT_SDIOIRQ) if ((events & event_mask) & MSDC_INT_SDIOIRQ)
sdio_signal_irq(host->mmc); sdio_signal_irq(mmc);
if ((events & event_mask) & MSDC_INT_CDSC) { if ((events & event_mask) & MSDC_INT_CDSC) {
if (host->internal_cd) if (host->internal_cd)
mmc_detect_change(host->mmc, msecs_to_jiffies(20)); mmc_detect_change(mmc, msecs_to_jiffies(20));
events &= ~MSDC_INT_CDSC; events &= ~MSDC_INT_CDSC;
} }
if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ))) if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
break; break;
if ((host->mmc->caps2 & MMC_CAP2_CQE) && if ((mmc->caps2 & MMC_CAP2_CQE) &&
(events & MSDC_INT_CMDQ)) { (events & MSDC_INT_CMDQ)) {
msdc_cmdq_irq(host, events); msdc_cmdq_irq(host, events);
/* clear interrupts */ /* clear interrupts */
@ -2290,6 +2295,26 @@ static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
} }
} }
static void msdc_cqe_pre_enable(struct mmc_host *mmc)
{
struct cqhci_host *cq_host = mmc->cqe_private;
u32 reg;
reg = cqhci_readl(cq_host, CQHCI_CFG);
reg |= CQHCI_ENABLE;
cqhci_writel(cq_host, reg, CQHCI_CFG);
}
static void msdc_cqe_post_disable(struct mmc_host *mmc)
{
struct cqhci_host *cq_host = mmc->cqe_private;
u32 reg;
reg = cqhci_readl(cq_host, CQHCI_CFG);
reg &= ~CQHCI_ENABLE;
cqhci_writel(cq_host, reg, CQHCI_CFG);
}
static const struct mmc_host_ops mt_msdc_ops = { static const struct mmc_host_ops mt_msdc_ops = {
.post_req = msdc_post_req, .post_req = msdc_post_req,
.pre_req = msdc_pre_req, .pre_req = msdc_pre_req,
@ -2309,6 +2334,8 @@ static const struct mmc_host_ops mt_msdc_ops = {
static const struct cqhci_host_ops msdc_cmdq_ops = { static const struct cqhci_host_ops msdc_cmdq_ops = {
.enable = msdc_cqe_enable, .enable = msdc_cqe_enable,
.disable = msdc_cqe_disable, .disable = msdc_cqe_disable,
.pre_enable = msdc_cqe_pre_enable,
.post_disable = msdc_cqe_post_disable,
}; };
static void msdc_of_property_parse(struct platform_device *pdev, static void msdc_of_property_parse(struct platform_device *pdev,
@ -2434,7 +2461,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
host->dev = &pdev->dev; host->dev = &pdev->dev;
host->dev_comp = of_device_get_match_data(&pdev->dev); host->dev_comp = of_device_get_match_data(&pdev->dev);
host->mmc = mmc;
host->src_clk_freq = clk_get_rate(host->src_clk); host->src_clk_freq = clk_get_rate(host->src_clk);
/* Set host parameters to mmc */ /* Set host parameters to mmc */
mmc->ops = &mt_msdc_ops; mmc->ops = &mt_msdc_ops;
@ -2475,7 +2501,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
mmc_dev(mmc)->dma_mask = &host->dma_mask; mmc_dev(mmc)->dma_mask = &host->dma_mask;
if (mmc->caps2 & MMC_CAP2_CQE) { if (mmc->caps2 & MMC_CAP2_CQE) {
host->cq_host = devm_kzalloc(host->mmc->parent, host->cq_host = devm_kzalloc(mmc->parent,
sizeof(*host->cq_host), sizeof(*host->cq_host),
GFP_KERNEL); GFP_KERNEL);
if (!host->cq_host) { if (!host->cq_host) {
@ -2560,7 +2586,7 @@ static int msdc_drv_remove(struct platform_device *pdev)
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
mmc_remove_host(host->mmc); mmc_remove_host(mmc);
msdc_deinit_hw(host); msdc_deinit_hw(host);
msdc_gate_clock(host); msdc_gate_clock(host);
@ -2572,7 +2598,7 @@ static int msdc_drv_remove(struct platform_device *pdev)
dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc), dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc),
host->dma.bd, host->dma.bd_addr); host->dma.bd, host->dma.bd_addr);
mmc_free_host(host->mmc); mmc_free_host(mmc);
return 0; return 0;
} }
@ -2607,6 +2633,7 @@ static void msdc_save_reg(struct msdc_host *host)
static void msdc_restore_reg(struct msdc_host *host) static void msdc_restore_reg(struct msdc_host *host)
{ {
struct mmc_host *mmc = mmc_from_priv(host);
u32 tune_reg = host->dev_comp->pad_tune_reg; u32 tune_reg = host->dev_comp->pad_tune_reg;
writel(host->save_para.msdc_cfg, host->base + MSDC_CFG); writel(host->save_para.msdc_cfg, host->base + MSDC_CFG);
@ -2631,7 +2658,7 @@ static void msdc_restore_reg(struct msdc_host *host)
writel(host->save_para.pad_tune, host->base + tune_reg); writel(host->save_para.pad_tune, host->base + tune_reg);
} }
if (sdio_irq_claimed(host->mmc)) if (sdio_irq_claimed(mmc))
__msdc_enable_sdio_irq(host, 1); __msdc_enable_sdio_irq(host, 1);
} }
@ -2667,6 +2694,7 @@ static struct platform_driver mt_msdc_driver = {
.remove = msdc_drv_remove, .remove = msdc_drv_remove,
.driver = { .driver = {
.name = "mtk-msdc", .name = "mtk-msdc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = msdc_of_ids, .of_match_table = msdc_of_ids,
.pm = &msdc_dev_pm_ops, .pm = &msdc_dev_pm_ops,
}, },

Просмотреть файл

@ -824,6 +824,7 @@ static struct platform_driver mvsd_driver = {
.remove = mvsd_remove, .remove = mvsd_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = mvsdio_dt_ids, .of_match_table = mvsdio_dt_ids,
}, },
}; };

Просмотреть файл

@ -1244,6 +1244,7 @@ static struct platform_driver mxcmci_driver = {
.id_table = mxcmci_devtype, .id_table = mxcmci_devtype,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &mxcmci_pm_ops, .pm = &mxcmci_pm_ops,
.of_match_table = mxcmci_of_match, .of_match_table = mxcmci_of_match,
} }

Просмотреть файл

@ -726,6 +726,7 @@ static struct platform_driver mxs_mmc_driver = {
.id_table = mxs_ssp_ids, .id_table = mxs_ssp_ids,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &mxs_mmc_pm_ops, .pm = &mxs_mmc_pm_ops,
.of_match_table = mxs_mmc_dt_ids, .of_match_table = mxs_mmc_dt_ids,
}, },

Просмотреть файл

@ -1504,6 +1504,7 @@ static struct platform_driver mmc_omap_driver = {
.remove = mmc_omap_remove, .remove = mmc_omap_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(mmc_omap_match), .of_match_table = of_match_ptr(mmc_omap_match),
}, },
}; };

Просмотреть файл

@ -1114,8 +1114,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
int ret; int ret;
/* Disable the clocks */ /* Disable the clocks */
if (host->dbclk) clk_disable_unprepare(host->dbclk);
clk_disable_unprepare(host->dbclk);
/* Turn the power off */ /* Turn the power off */
ret = omap_hsmmc_set_power(host, 0); ret = omap_hsmmc_set_power(host, 0);
@ -1123,8 +1122,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
/* Turn the power ON with given VDD 1.8 or 3.0v */ /* Turn the power ON with given VDD 1.8 or 3.0v */
if (!ret) if (!ret)
ret = omap_hsmmc_set_power(host, 1); ret = omap_hsmmc_set_power(host, 1);
if (host->dbclk) clk_prepare_enable(host->dbclk);
clk_prepare_enable(host->dbclk);
if (ret != 0) if (ret != 0)
goto err; goto err;
@ -2014,8 +2012,7 @@ err_irq:
pm_runtime_dont_use_autosuspend(host->dev); pm_runtime_dont_use_autosuspend(host->dev);
pm_runtime_put_sync(host->dev); pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev); pm_runtime_disable(host->dev);
if (host->dbclk) clk_disable_unprepare(host->dbclk);
clk_disable_unprepare(host->dbclk);
err1: err1:
mmc_free_host(mmc); mmc_free_host(mmc);
err: err:
@ -2037,8 +2034,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
pm_runtime_put_sync(host->dev); pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev); pm_runtime_disable(host->dev);
device_init_wakeup(&pdev->dev, false); device_init_wakeup(&pdev->dev, false);
if (host->dbclk) clk_disable_unprepare(host->dbclk);
clk_disable_unprepare(host->dbclk);
mmc_free_host(host->mmc); mmc_free_host(host->mmc);
@ -2063,8 +2059,7 @@ static int omap_hsmmc_suspend(struct device *dev)
OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
} }
if (host->dbclk) clk_disable_unprepare(host->dbclk);
clk_disable_unprepare(host->dbclk);
pm_runtime_put_sync(host->dev); pm_runtime_put_sync(host->dev);
return 0; return 0;
@ -2080,8 +2075,7 @@ static int omap_hsmmc_resume(struct device *dev)
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
if (host->dbclk) clk_prepare_enable(host->dbclk);
clk_prepare_enable(host->dbclk);
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
omap_hsmmc_conf_bus_power(host); omap_hsmmc_conf_bus_power(host);
@ -2171,6 +2165,7 @@ static struct platform_driver omap_hsmmc_driver = {
.remove = omap_hsmmc_remove, .remove = omap_hsmmc_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &omap_hsmmc_dev_pm_ops, .pm = &omap_hsmmc_dev_pm_ops,
.of_match_table = of_match_ptr(omap_mmc_of_match), .of_match_table = of_match_ptr(omap_mmc_of_match),
}, },

Просмотреть файл

@ -689,6 +689,7 @@ MODULE_DEVICE_TABLE(of, owl_mmc_of_match);
static struct platform_driver owl_mmc_driver = { static struct platform_driver owl_mmc_driver = {
.driver = { .driver = {
.name = "owl_mmc", .name = "owl_mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = owl_mmc_of_match, .of_match_table = owl_mmc_of_match,
}, },
.probe = owl_mmc_probe, .probe = owl_mmc_probe,

Просмотреть файл

@ -811,6 +811,7 @@ static struct platform_driver pxamci_driver = {
.remove = pxamci_remove, .remove = pxamci_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(pxa_mmc_dt_ids), .of_match_table = of_match_ptr(pxa_mmc_dt_ids),
}, },
}; };

Просмотреть файл

@ -33,10 +33,13 @@ struct renesas_sdhi_of_data {
unsigned short max_segs; unsigned short max_segs;
}; };
#define SDHI_CALIB_TABLE_MAX 32
struct renesas_sdhi_quirks { struct renesas_sdhi_quirks {
bool hs400_disabled; bool hs400_disabled;
bool hs400_4taps; bool hs400_4taps;
u32 hs400_bad_taps; u32 hs400_bad_taps;
const u8 (*hs400_calib_table)[SDHI_CALIB_TABLE_MAX];
}; };
struct tmio_mmc_dma { struct tmio_mmc_dma {
@ -58,7 +61,8 @@ struct renesas_sdhi {
void __iomem *scc_ctl; void __iomem *scc_ctl;
u32 scc_tappos; u32 scc_tappos;
u32 scc_tappos_hs400; u32 scc_tappos_hs400;
bool doing_tune; const u8 *adjust_hs400_calib_table;
bool needs_adjust_hs400;
/* Tuning values: 1 for success, 0 for failure */ /* Tuning values: 1 for success, 0 for failure */
DECLARE_BITMAP(taps, BITS_PER_LONG); DECLARE_BITMAP(taps, BITS_PER_LONG);

Просмотреть файл

@ -26,6 +26,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
#include <linux/mfd/tmio.h> #include <linux/mfd/tmio.h>
#include <linux/sh_dma.h> #include <linux/sh_dma.h>
@ -47,6 +48,8 @@
#define SDHI_VER_GEN3_SD 0xcc10 #define SDHI_VER_GEN3_SD 0xcc10
#define SDHI_VER_GEN3_SDMMC 0xcd10 #define SDHI_VER_GEN3_SDMMC 0xcd10
#define SDHI_GEN3_MMC0_ADDR 0xee140000
static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
{ {
u32 val; u32 val;
@ -117,8 +120,12 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
unsigned int freq, diff, best_freq = 0, diff_min = ~0; unsigned int freq, diff, best_freq = 0, diff_min = ~0;
int i; int i;
/* tested only on R-Car Gen2+ currently; may work for others */ /*
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) * We simply return the current rate if a) we are not on a R-Car Gen2+
* SoC (may work for others, but untested) or b) if the SCC needs its
* clock during tuning, so we don't change the external clock setup.
*/
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2) || mmc_doing_tune(host->mmc))
return clk_get_rate(priv->clk); return clk_get_rate(priv->clk);
/* /*
@ -247,6 +254,11 @@ static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
#define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A #define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A
#define SH_MOBILE_SDHI_SCC_SMPCMP 0x00C #define SH_MOBILE_SDHI_SCC_SMPCMP 0x00C
#define SH_MOBILE_SDHI_SCC_TMPPORT2 0x00E #define SH_MOBILE_SDHI_SCC_TMPPORT2 0x00E
#define SH_MOBILE_SDHI_SCC_TMPPORT3 0x014
#define SH_MOBILE_SDHI_SCC_TMPPORT4 0x016
#define SH_MOBILE_SDHI_SCC_TMPPORT5 0x018
#define SH_MOBILE_SDHI_SCC_TMPPORT6 0x01A
#define SH_MOBILE_SDHI_SCC_TMPPORT7 0x01C
#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0) #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0)
#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16
@ -267,6 +279,40 @@ static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4) #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4)
#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN BIT(31) #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN BIT(31)
/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT4 register */
#define SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START BIT(0)
/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT5 register */
#define SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R BIT(8)
#define SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W (0 << 8)
#define SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_ADR_MASK 0x3F
/* Definitions for values the SH_MOBILE_SDHI_SCC register */
#define SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE 0xa5000000
#define SH_MOBILE_SDHI_SCC_TMPPORT_CALIB_CODE_MASK 0x1f
#define SH_MOBILE_SDHI_SCC_TMPPORT_MANUAL_MODE BIT(7)
static const u8 r8a7796_es13_calib_table[2][SDHI_CALIB_TABLE_MAX] = {
{ 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15,
16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 },
{ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 11,
12, 17, 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, 22, 23, 25, 25 }
};
static const u8 r8a77965_calib_table[2][SDHI_CALIB_TABLE_MAX] = {
{ 1, 2, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 30, 31 },
{ 2, 3, 4, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17,
17, 17, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 31, 31, 31 }
};
static const u8 r8a77990_calib_table[2][SDHI_CALIB_TABLE_MAX] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 8, 9, 10,
11, 12, 13, 15, 16, 17, 17, 18, 18, 19, 20, 22, 24, 25, 26, 26 }
};
static inline u32 sd_scc_read32(struct tmio_mmc_host *host, static inline u32 sd_scc_read32(struct tmio_mmc_host *host,
struct renesas_sdhi *priv, int addr) struct renesas_sdhi *priv, int addr)
{ {
@ -373,6 +419,9 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
if (priv->adjust_hs400_calib_table)
priv->needs_adjust_hs400 = true;
} }
static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host, static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host,
@ -403,6 +452,74 @@ static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
} }
static u32 sd_scc_tmpport_read32(struct tmio_mmc_host *host,
struct renesas_sdhi *priv, u32 addr)
{
/* read mode */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT5,
SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R |
(SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr));
/* access start and stop */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4,
SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START);
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, 0);
return sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT7);
}
static void sd_scc_tmpport_write32(struct tmio_mmc_host *host,
struct renesas_sdhi *priv, u32 addr, u32 val)
{
/* write mode */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT5,
SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W |
(SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr));
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT6, val);
/* access start and stop */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4,
SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START);
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, 0);
}
static void renesas_sdhi_adjust_hs400_mode_enable(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
u32 calib_code;
/* disable write protect */
sd_scc_tmpport_write32(host, priv, 0x00,
SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE);
/* read calibration code and adjust */
calib_code = sd_scc_tmpport_read32(host, priv, 0x26);
calib_code &= SH_MOBILE_SDHI_SCC_TMPPORT_CALIB_CODE_MASK;
sd_scc_tmpport_write32(host, priv, 0x22,
SH_MOBILE_SDHI_SCC_TMPPORT_MANUAL_MODE |
priv->adjust_hs400_calib_table[calib_code]);
/* set offset value to TMPPORT3, hardcoded to OFFSET0 (= 0x3) for now */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT3, 0x3);
/* adjustment done, clear flag */
priv->needs_adjust_hs400 = false;
}
static void renesas_sdhi_adjust_hs400_mode_disable(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
/* disable write protect */
sd_scc_tmpport_write32(host, priv, 0x00,
SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE);
/* disable manual calibration */
sd_scc_tmpport_write32(host, priv, 0x22, 0);
/* clear offset value of TMPPORT3 */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT3, 0);
}
static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host, static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
struct renesas_sdhi *priv) struct renesas_sdhi *priv)
{ {
@ -420,6 +537,9 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) & SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) &
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2)); sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));
if (priv->adjust_hs400_calib_table)
renesas_sdhi_adjust_hs400_mode_disable(host);
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
} }
@ -432,6 +552,37 @@ static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_io
return 0; return 0;
} }
static void renesas_sdhi_reset(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
renesas_sdhi_reset_scc(host, priv);
renesas_sdhi_reset_hs400_mode(host, priv);
priv->needs_adjust_hs400 = false;
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK,
TMIO_MASK_INIT_RCAR2);
}
/*
* This is a temporary workaround! This driver used 'hw_reset' wrongly and the
* fix for that showed a regression. So, we mimic the old behaviour until the
* proper solution is found.
*/
static void renesas_sdhi_hw_reset(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
renesas_sdhi_reset(host);
}
#define SH_MOBILE_SDHI_MIN_TAP_ROW 3 #define SH_MOBILE_SDHI_MIN_TAP_ROW 3
static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
@ -441,7 +592,6 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
unsigned int taps_size = priv->tap_num * 2, min_tap_row; unsigned int taps_size = priv->tap_num * 2, min_tap_row;
unsigned long *bitmap; unsigned long *bitmap;
priv->doing_tune = false;
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
/* /*
@ -500,10 +650,11 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
return 0; return 0;
} }
static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode) static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode)
{ {
struct tmio_mmc_host *host = mmc_priv(mmc);
struct renesas_sdhi *priv = host_to_priv(host); struct renesas_sdhi *priv = host_to_priv(host);
int i; int i, ret;
priv->tap_num = renesas_sdhi_init_tuning(host); priv->tap_num = renesas_sdhi_init_tuning(host);
if (!priv->tap_num) if (!priv->tap_num)
@ -515,7 +666,6 @@ static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode)
return -EINVAL; return -EINVAL;
} }
priv->doing_tune = true;
bitmap_zero(priv->taps, priv->tap_num * 2); bitmap_zero(priv->taps, priv->tap_num * 2);
bitmap_zero(priv->smpcmp, priv->tap_num * 2); bitmap_zero(priv->smpcmp, priv->tap_num * 2);
@ -524,14 +674,17 @@ static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode)
/* Set sampling clock position */ /* Set sampling clock position */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, i % priv->tap_num); sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, i % priv->tap_num);
if (mmc_send_tuning(host->mmc, opcode, NULL) == 0) if (mmc_send_tuning(mmc, opcode, NULL) == 0)
set_bit(i, priv->taps); set_bit(i, priv->taps);
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) == 0) if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) == 0)
set_bit(i, priv->smpcmp); set_bit(i, priv->smpcmp);
} }
return renesas_sdhi_select_tuning(host); ret = renesas_sdhi_select_tuning(host);
if (ret < 0)
renesas_sdhi_reset(host);
return ret;
} }
static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap) static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap)
@ -621,7 +774,7 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap)) !(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap))
return false; return false;
if (mmc_doing_retune(host->mmc) || priv->doing_tune) if (mmc_doing_tune(host->mmc))
return false; return false;
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
@ -631,27 +784,6 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
return renesas_sdhi_manual_correction(host, use_4tap); return renesas_sdhi_manual_correction(host, use_4tap);
} }
static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv;
priv = host_to_priv(host);
renesas_sdhi_reset_scc(host, priv);
renesas_sdhi_reset_hs400_mode(host, priv);
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK,
TMIO_MASK_INIT_RCAR2);
}
static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit) static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit)
{ {
int timeout = 1000; int timeout = 1000;
@ -711,6 +843,13 @@ static int renesas_sdhi_multi_io_quirk(struct mmc_card *card,
return blk_size; return blk_size;
} }
static void renesas_sdhi_fixup_request(struct tmio_mmc_host *host, struct mmc_request *mrq)
{
struct renesas_sdhi *priv = host_to_priv(host);
if (priv->needs_adjust_hs400 && mrq->cmd->opcode == MMC_SEND_STATUS)
renesas_sdhi_adjust_hs400_mode_enable(host);
}
static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
{ {
/* Iff regs are 8 byte apart, sdbuf is 64 bit. Otherwise always 32. */ /* Iff regs are 8 byte apart, sdbuf is 64 bit. Otherwise always 32. */
@ -742,6 +881,21 @@ static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps2367 = {
.hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7),
}; };
static const struct renesas_sdhi_quirks sdhi_quirks_r8a7796_es13 = {
.hs400_4taps = true,
.hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7),
.hs400_calib_table = r8a7796_es13_calib_table,
};
static const struct renesas_sdhi_quirks sdhi_quirks_r8a77965 = {
.hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7),
.hs400_calib_table = r8a77965_calib_table,
};
static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = {
.hs400_calib_table = r8a77990_calib_table,
};
/* /*
* Note for r8a7796 / r8a774a1: we can't distinguish ES1.1 and 1.2 as of now. * Note for r8a7796 / r8a774a1: we can't distinguish ES1.1 and 1.2 as of now.
* So, we want to treat them equally and only have a match for ES1.2 to enforce * So, we want to treat them equally and only have a match for ES1.2 to enforce
@ -753,10 +907,11 @@ static const struct soc_device_attribute sdhi_quirks_match[] = {
{ .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap },
{ .soc_id = "r8a7795", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps2367 }, { .soc_id = "r8a7795", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps2367 },
{ .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
{ .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_4tap }, { .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_r8a7796_es13 },
{ .soc_id = "r8a7796", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps1357 }, { .soc_id = "r8a7796", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps1357 },
{ .soc_id = "r8a77965", .data = &sdhi_quirks_bad_taps2367 }, { .soc_id = "r8a77965", .data = &sdhi_quirks_r8a77965 },
{ .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 }, { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 },
{ .soc_id = "r8a77990", .data = &sdhi_quirks_r8a77990 },
{ /* Sentinel. */ }, { /* Sentinel. */ },
}; };
@ -862,11 +1017,11 @@ int renesas_sdhi_probe(struct platform_device *pdev,
renesas_sdhi_start_signal_voltage_switch; renesas_sdhi_start_signal_voltage_switch;
host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27; host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27;
/* SDR and HS200/400 registers requires HW reset */
if (of_data && of_data->scc_offset) { if (of_data && of_data->scc_offset) {
priv->scc_ctl = host->ctl + of_data->scc_offset; priv->scc_ctl = host->ctl + of_data->scc_offset;
host->reset = renesas_sdhi_reset;
host->ops.hw_reset = renesas_sdhi_hw_reset;
host->mmc->caps |= MMC_CAP_HW_RESET; host->mmc->caps |= MMC_CAP_HW_RESET;
host->hw_reset = renesas_sdhi_hw_reset;
} }
} }
@ -915,6 +1070,14 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (ver == SDHI_VER_GEN2_SDR50) if (ver == SDHI_VER_GEN2_SDR50)
mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY; mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY;
if (ver == SDHI_VER_GEN3_SDMMC && quirks && quirks->hs400_calib_table) {
host->fixup_request = renesas_sdhi_fixup_request;
priv->adjust_hs400_calib_table = *(
res->start == SDHI_GEN3_MMC0_ADDR ?
quirks->hs400_calib_table :
quirks->hs400_calib_table + 1);
}
ret = tmio_mmc_host_probe(host); ret = tmio_mmc_host_probe(host);
if (ret < 0) if (ret < 0)
goto edisclk; goto edisclk;
@ -943,8 +1106,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (!hit) if (!hit)
dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n"); dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n");
host->execute_tuning = renesas_sdhi_execute_tuning;
host->check_retune = renesas_sdhi_check_scc_error; host->check_retune = renesas_sdhi_check_scc_error;
host->ops.execute_tuning = renesas_sdhi_execute_tuning;
host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning; host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning;
host->ops.hs400_downgrade = renesas_sdhi_disable_scc; host->ops.hs400_downgrade = renesas_sdhi_disable_scc;
host->ops.hs400_complete = renesas_sdhi_hs400_complete; host->ops.hs400_complete = renesas_sdhi_hs400_complete;

Просмотреть файл

@ -336,10 +336,6 @@ static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
if (soc) if (soc)
global_flags |= (unsigned long)soc->data; global_flags |= (unsigned long)soc->data;
dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
if (!dev->dma_parms)
return -ENOMEM;
/* value is max of SD_SECCNT. Confirmed by HW engineers */ /* value is max of SD_SECCNT. Confirmed by HW engineers */
dma_set_max_seg_size(dev, 0xffffffff); dma_set_max_seg_size(dev, 0xffffffff);
@ -357,6 +353,7 @@ static const struct dev_pm_ops renesas_sdhi_internal_dmac_dev_pm_ops = {
static struct platform_driver renesas_internal_dmac_sdhi_driver = { static struct platform_driver renesas_internal_dmac_sdhi_driver = {
.driver = { .driver = {
.name = "renesas_sdhi_internal_dmac", .name = "renesas_sdhi_internal_dmac",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &renesas_sdhi_internal_dmac_dev_pm_ops, .pm = &renesas_sdhi_internal_dmac_dev_pm_ops,
.of_match_table = renesas_sdhi_internal_dmac_of_match, .of_match_table = renesas_sdhi_internal_dmac_of_match,
}, },

Просмотреть файл

@ -463,6 +463,7 @@ static const struct dev_pm_ops renesas_sdhi_sys_dmac_dev_pm_ops = {
static struct platform_driver renesas_sys_dmac_sdhi_driver = { static struct platform_driver renesas_sys_dmac_sdhi_driver = {
.driver = { .driver = {
.name = "sh_mobile_sdhi", .name = "sh_mobile_sdhi",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &renesas_sdhi_sys_dmac_dev_pm_ops, .pm = &renesas_sdhi_sys_dmac_dev_pm_ops,
.of_match_table = renesas_sdhi_sys_dmac_of_match, .of_match_table = renesas_sdhi_sys_dmac_of_match,
}, },

Просмотреть файл

@ -1471,6 +1471,7 @@ static struct platform_driver rtsx_pci_sdmmc_driver = {
.id_table = rtsx_pci_sdmmc_ids, .id_table = rtsx_pci_sdmmc_ids,
.driver = { .driver = {
.name = DRV_NAME_RTSX_PCI_SDMMC, .name = DRV_NAME_RTSX_PCI_SDMMC,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
}, },
}; };
module_platform_driver(rtsx_pci_sdmmc_driver); module_platform_driver(rtsx_pci_sdmmc_driver);

Просмотреть файл

@ -579,7 +579,6 @@ static void sd_normal_rw(struct rtsx_usb_sdmmc *host,
static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx) static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx)
{ {
struct rtsx_ucr *ucr = host->ucr; struct rtsx_ucr *ucr = host->ucr;
int err;
dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n", dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n",
__func__, tx ? "TX" : "RX", sample_point); __func__, tx ? "TX" : "RX", sample_point);
@ -601,11 +600,7 @@ static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx)
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0); rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_RST, 0); rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_RST, 0);
err = rtsx_usb_send_cmd(ucr, MODE_C, 100); return rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (err)
return err;
return 0;
} }
static inline u32 get_phase_point(u32 phase_map, unsigned int idx) static inline u32 get_phase_point(u32 phase_map, unsigned int idx)
@ -1458,6 +1453,7 @@ static struct platform_driver rtsx_usb_sdmmc_driver = {
.id_table = rtsx_usb_sdmmc_ids, .id_table = rtsx_usb_sdmmc_ids,
.driver = { .driver = {
.name = "rtsx_usb_sdmmc", .name = "rtsx_usb_sdmmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &rtsx_usb_sdmmc_dev_pm_ops, .pm = &rtsx_usb_sdmmc_dev_pm_ops,
}, },
}; };

Просмотреть файл

@ -150,8 +150,8 @@ static void s3cmci_reset(struct s3cmci_host *host);
static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) static void dbg_dumpregs(struct s3cmci_host *host, char *prefix)
{ {
u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize; u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer;
u32 datcon, datcnt, datsta, fsta, imask; u32 datcon, datcnt, datsta, fsta;
con = readl(host->base + S3C2410_SDICON); con = readl(host->base + S3C2410_SDICON);
pre = readl(host->base + S3C2410_SDIPRE); pre = readl(host->base + S3C2410_SDIPRE);
@ -163,12 +163,10 @@ static void dbg_dumpregs(struct s3cmci_host *host, char *prefix)
r2 = readl(host->base + S3C2410_SDIRSP2); r2 = readl(host->base + S3C2410_SDIRSP2);
r3 = readl(host->base + S3C2410_SDIRSP3); r3 = readl(host->base + S3C2410_SDIRSP3);
timer = readl(host->base + S3C2410_SDITIMER); timer = readl(host->base + S3C2410_SDITIMER);
bsize = readl(host->base + S3C2410_SDIBSIZE);
datcon = readl(host->base + S3C2410_SDIDCON); datcon = readl(host->base + S3C2410_SDIDCON);
datcnt = readl(host->base + S3C2410_SDIDCNT); datcnt = readl(host->base + S3C2410_SDIDCNT);
datsta = readl(host->base + S3C2410_SDIDSTA); datsta = readl(host->base + S3C2410_SDIDSTA);
fsta = readl(host->base + S3C2410_SDIFSTA); fsta = readl(host->base + S3C2410_SDIFSTA);
imask = readl(host->base + host->sdiimsk);
dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n", dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n",
prefix, con, pre, timer); prefix, con, pre, timer);
@ -396,9 +394,6 @@ static void s3cmci_enable_irq(struct s3cmci_host *host, bool more)
local_irq_restore(flags); local_irq_restore(flags);
} }
/**
*
*/
static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer)
{ {
unsigned long flags; unsigned long flags;
@ -1379,7 +1374,7 @@ static int s3cmci_state_show(struct seq_file *seq, void *v)
{ {
struct s3cmci_host *host = seq->private; struct s3cmci_host *host = seq->private;
seq_printf(seq, "Register base = 0x%08x\n", (u32)host->base); seq_printf(seq, "Register base = 0x%p\n", host->base);
seq_printf(seq, "Clock rate = %ld\n", host->clk_rate); seq_printf(seq, "Clock rate = %ld\n", host->clk_rate);
seq_printf(seq, "Prescale = %d\n", host->prescaler); seq_printf(seq, "Prescale = %d\n", host->prescaler);
seq_printf(seq, "is2440 = %d\n", host->is2440); seq_printf(seq, "is2440 = %d\n", host->is2440);
@ -1522,7 +1517,7 @@ static int s3cmci_probe_dt(struct s3cmci_host *host)
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
int ret; int ret;
host->is2440 = (int) of_device_get_match_data(&pdev->dev); host->is2440 = (long) of_device_get_match_data(&pdev->dev);
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret) if (ret)
@ -1809,6 +1804,7 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids);
static struct platform_driver s3cmci_driver = { static struct platform_driver s3cmci_driver = {
.driver = { .driver = {
.name = "s3c-sdi", .name = "s3c-sdi",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = s3cmci_dt_match, .of_match_table = s3cmci_dt_match,
}, },
.id_table = s3cmci_driver_ids, .id_table = s3cmci_driver_ids,

Просмотреть файл

@ -662,6 +662,43 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev,
(host->mmc->caps & MMC_CAP_1_8V_DDR)) (host->mmc->caps & MMC_CAP_1_8V_DDR))
host->mmc->caps2 = MMC_CAP2_HS400_1_8V; host->mmc->caps2 = MMC_CAP2_HS400_1_8V;
/*
* There are two types of presets out in the wild:
* 1) Default/broken presets.
* These presets have two sets of problems:
* a) The clock divisor for SDR12, SDR25, and SDR50 is too small.
* This results in clock frequencies that are 2x higher than
* acceptable. i.e., SDR12 = 25 MHz, SDR25 = 50 MHz, SDR50 =
* 100 MHz.x
* b) The HS200 and HS400 driver strengths don't match.
* By default, the SDR104 preset register has a driver strength of
* A, but the (internal) HS400 preset register has a driver
* strength of B. As part of initializing HS400, HS200 tuning
* needs to be performed. Having different driver strengths
* between tuning and operation is wrong. It results in different
* rise/fall times that lead to incorrect sampling.
* 2) Firmware with properly initialized presets.
* These presets have proper clock divisors. i.e., SDR12 => 12MHz,
* SDR25 => 25 MHz, SDR50 => 50 MHz. Additionally the HS200 and
* HS400 preset driver strengths match.
*
* Enabling presets for HS400 doesn't work for the following reasons:
* 1) sdhci_set_ios has a hard coded list of timings that are used
* to determine if presets should be enabled.
* 2) sdhci_get_preset_value is using a non-standard register to
* read out HS400 presets. The AMD controller doesn't support this
* non-standard register. In fact, it doesn't expose the HS400
* preset register anywhere in the SDHCI memory map. This results
* in reading a garbage value and using the wrong presets.
*
* Since HS400 and HS200 presets must be identical, we could
* instead use the the SDR104 preset register.
*
* If the above issues are resolved we could remove this quirk for
* firmware that that has valid presets (i.e., SDR12 <= 12 MHz).
*/
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
host->mmc_host_ops.select_drive_strength = amd_select_drive_strength; host->mmc_host_ops.select_drive_strength = amd_select_drive_strength;
host->mmc_host_ops.set_ios = amd_set_ios; host->mmc_host_ops.set_ios = amd_set_ios;
host->mmc_host_ops.execute_tuning = amd_sdhci_execute_tuning; host->mmc_host_ops.execute_tuning = amd_sdhci_execute_tuning;
@ -1027,6 +1064,7 @@ static const struct dev_pm_ops sdhci_acpi_pm_ops = {
static struct platform_driver sdhci_acpi_driver = { static struct platform_driver sdhci_acpi_driver = {
.driver = { .driver = {
.name = "sdhci-acpi", .name = "sdhci-acpi",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.acpi_match_table = sdhci_acpi_ids, .acpi_match_table = sdhci_acpi_ids,
.pm = &sdhci_acpi_pm_ops, .pm = &sdhci_acpi_pm_ops,
}, },

Просмотреть файл

@ -324,6 +324,7 @@ err_pltfm_free:
static struct platform_driver sdhci_bcm_kona_driver = { static struct platform_driver sdhci_bcm_kona_driver = {
.driver = { .driver = {
.name = "sdhci-kona", .name = "sdhci-kona",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
.of_match_table = sdhci_bcm_kona_of_match, .of_match_table = sdhci_bcm_kona_of_match,
}, },

Просмотреть файл

@ -235,13 +235,11 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probe found match for %s\n", match->compatible); dev_dbg(&pdev->dev, "Probe found match for %s\n", match->compatible);
clk = devm_clk_get(&pdev->dev, NULL); clk = devm_clk_get_optional(&pdev->dev, NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk))
if (PTR_ERR(clk) == -EPROBE_DEFER) return dev_err_probe(&pdev->dev, PTR_ERR(clk),
return -EPROBE_DEFER; "Failed to get clock from Device Tree\n");
dev_err(&pdev->dev, "Clock not found in Device Tree\n");
clk = NULL;
}
res = clk_prepare_enable(clk); res = clk_prepare_enable(clk);
if (res) if (res)
return res; return res;
@ -328,6 +326,7 @@ MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
static struct platform_driver sdhci_brcmstb_driver = { static struct platform_driver sdhci_brcmstb_driver = {
.driver = { .driver = {
.name = "sdhci-brcmstb", .name = "sdhci-brcmstb",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
.of_match_table = of_match_ptr(sdhci_brcm_of_match), .of_match_table = of_match_ptr(sdhci_brcm_of_match),
}, },

Просмотреть файл

@ -463,6 +463,7 @@ MODULE_DEVICE_TABLE(of, sdhci_cdns_match);
static struct platform_driver sdhci_cdns_driver = { static struct platform_driver sdhci_cdns_driver = {
.driver = { .driver = {
.name = "sdhci-cdns", .name = "sdhci-cdns",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_cdns_pm_ops, .pm = &sdhci_cdns_pm_ops,
.of_match_table = sdhci_cdns_match, .of_match_table = sdhci_cdns_match,
}, },

Просмотреть файл

@ -98,6 +98,7 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev)
static struct platform_driver sdhci_cns3xxx_driver = { static struct platform_driver sdhci_cns3xxx_driver = {
.driver = { .driver = {
.name = "sdhci-cns3xxx", .name = "sdhci-cns3xxx",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
}, },
.probe = sdhci_cns3xxx_probe, .probe = sdhci_cns3xxx_probe,

Просмотреть файл

@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table);
static struct platform_driver sdhci_dove_driver = { static struct platform_driver sdhci_dove_driver = {
.driver = { .driver = {
.name = "sdhci-dove", .name = "sdhci-dove",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
.of_match_table = sdhci_dove_of_match_table, .of_match_table = sdhci_dove_of_match_table,
}, },

Просмотреть файл

@ -987,10 +987,20 @@ static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
{ {
u32 reg; u32 reg;
u8 sw_rst;
int ret;
/* FIXME: delay a bit for card to be ready for next tuning due to errors */ /* FIXME: delay a bit for card to be ready for next tuning due to errors */
mdelay(1); mdelay(1);
/* IC suggest to reset USDHC before every tuning command */
esdhc_clrset_le(host, 0xff, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET);
ret = readb_poll_timeout(host->ioaddr + SDHCI_SOFTWARE_RESET, sw_rst,
!(sw_rst & SDHCI_RESET_ALL), 10, 100);
if (ret == -ETIMEDOUT)
dev_warn(mmc_dev(host->mmc),
"warning! RESET_ALL never complete before sending tuning command\n");
reg = readl(host->ioaddr + ESDHC_MIX_CTRL); reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
ESDHC_MIX_CTRL_FBCLK_SEL; ESDHC_MIX_CTRL_FBCLK_SEL;
@ -1367,7 +1377,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
* response, block the tuning procedure or the first command * response, block the tuning procedure or the first command
* after the whole tuning procedure always can't get any response. * after the whole tuning procedure always can't get any response.
*/ */
tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE;
writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
} else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
/* /*
@ -1643,10 +1653,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
goto disable_ipg_clk; goto disable_ipg_clk;
imx_data->pinctrl = devm_pinctrl_get(&pdev->dev); imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(imx_data->pinctrl)) { if (IS_ERR(imx_data->pinctrl))
err = PTR_ERR(imx_data->pinctrl);
dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n"); dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n");
}
if (esdhc_is_usdhc(imx_data)) { if (esdhc_is_usdhc(imx_data)) {
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
@ -1917,6 +1925,7 @@ static const struct dev_pm_ops sdhci_esdhc_pmops = {
static struct platform_driver sdhci_esdhc_imx_driver = { static struct platform_driver sdhci_esdhc_imx_driver = {
.driver = { .driver = {
.name = "sdhci-esdhc-imx", .name = "sdhci-esdhc-imx",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = imx_esdhc_dt_ids, .of_match_table = imx_esdhc_dt_ids,
.pm = &sdhci_esdhc_pmops, .pm = &sdhci_esdhc_pmops,
}, },

Просмотреть файл

@ -509,6 +509,7 @@ static int sdhci_esdhc_mcf_remove(struct platform_device *pdev)
static struct platform_driver sdhci_esdhc_mcf_driver = { static struct platform_driver sdhci_esdhc_mcf_driver = {
.driver = { .driver = {
.name = "sdhci-esdhc-mcf", .name = "sdhci-esdhc-mcf",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
}, },
.probe = sdhci_esdhc_mcf_probe, .probe = sdhci_esdhc_mcf_probe,
.remove = sdhci_esdhc_mcf_remove, .remove = sdhci_esdhc_mcf_remove,

Просмотреть файл

@ -283,6 +283,7 @@ static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = {
static const struct sdhci_iproc_data bcm2711_data = { static const struct sdhci_iproc_data bcm2711_data = {
.pdata = &sdhci_bcm2711_pltfm_data, .pdata = &sdhci_bcm2711_pltfm_data,
.mmc_caps = MMC_CAP_3_3V_DDR,
}; };
static const struct of_device_id sdhci_iproc_of_match[] = { static const struct of_device_id sdhci_iproc_of_match[] = {
@ -368,6 +369,7 @@ err:
static struct platform_driver sdhci_iproc_driver = { static struct platform_driver sdhci_iproc_driver = {
.driver = { .driver = {
.name = "sdhci-iproc", .name = "sdhci-iproc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_iproc_of_match, .of_match_table = sdhci_iproc_of_match,
.acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids), .acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids),
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,

Просмотреть файл

@ -333,6 +333,7 @@ static int sdhci_milbeaut_remove(struct platform_device *pdev)
static struct platform_driver sdhci_milbeaut_driver = { static struct platform_driver sdhci_milbeaut_driver = {
.driver = { .driver = {
.name = "sdhci-milbeaut", .name = "sdhci-milbeaut",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(mlb_dt_ids), .of_match_table = of_match_ptr(mlb_dt_ids),
}, },
.probe = sdhci_milbeaut_probe, .probe = sdhci_milbeaut_probe,

Просмотреть файл

@ -263,7 +263,6 @@ struct sdhci_msm_host {
unsigned long clk_rate; unsigned long clk_rate;
struct mmc_host *mmc; struct mmc_host *mmc;
struct opp_table *opp_table; struct opp_table *opp_table;
bool has_opp_table;
bool use_14lpp_dll_reset; bool use_14lpp_dll_reset;
bool tuning_done; bool tuning_done;
bool calibration_done; bool calibration_done;
@ -2167,6 +2166,7 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var}, {.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var}, {.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
{.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var}, {.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var},
{.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var},
{}, {},
}; };
@ -2301,11 +2301,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
/* OPP table is optional */ /* OPP table is optional */
ret = dev_pm_opp_of_add_table(&pdev->dev); ret = dev_pm_opp_of_add_table(&pdev->dev);
if (!ret) { if (ret && ret != -ENODEV) {
msm_host->has_opp_table = true;
} else if (ret != -ENODEV) {
dev_err(&pdev->dev, "Invalid OPP table in Device tree\n"); dev_err(&pdev->dev, "Invalid OPP table in Device tree\n");
goto opp_cleanup; goto opp_put_clkname;
} }
/* Vote for maximum clock rate for maximum performance */ /* Vote for maximum clock rate for maximum performance */
@ -2469,8 +2467,8 @@ clk_disable:
clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
msm_host->bulk_clks); msm_host->bulk_clks);
opp_cleanup: opp_cleanup:
if (msm_host->has_opp_table) dev_pm_opp_of_remove_table(&pdev->dev);
dev_pm_opp_of_remove_table(&pdev->dev); opp_put_clkname:
dev_pm_opp_put_clkname(msm_host->opp_table); dev_pm_opp_put_clkname(msm_host->opp_table);
bus_clk_disable: bus_clk_disable:
if (!IS_ERR(msm_host->bus_clk)) if (!IS_ERR(msm_host->bus_clk))
@ -2490,8 +2488,7 @@ static int sdhci_msm_remove(struct platform_device *pdev)
sdhci_remove_host(host, dead); sdhci_remove_host(host, dead);
if (msm_host->has_opp_table) dev_pm_opp_of_remove_table(&pdev->dev);
dev_pm_opp_of_remove_table(&pdev->dev);
dev_pm_opp_put_clkname(msm_host->opp_table); dev_pm_opp_put_clkname(msm_host->opp_table);
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
@ -2557,6 +2554,7 @@ static struct platform_driver sdhci_msm_driver = {
.name = "sdhci_msm", .name = "sdhci_msm",
.of_match_table = sdhci_msm_dt_match, .of_match_table = sdhci_msm_dt_match,
.pm = &sdhci_msm_pm_ops, .pm = &sdhci_msm_pm_ops,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
}, },
}; };

Просмотреть файл

@ -1543,10 +1543,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
of_node_put(node); of_node_put(node);
if (IS_ERR(sdhci_arasan->soc_ctl_base)) { if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
ret = PTR_ERR(sdhci_arasan->soc_ctl_base); ret = dev_err_probe(&pdev->dev,
if (ret != -EPROBE_DEFER) PTR_ERR(sdhci_arasan->soc_ctl_base),
dev_err(&pdev->dev, "Can't get syscon: %d\n", "Can't get syscon\n");
ret);
goto err_pltfm_free; goto err_pltfm_free;
} }
} }
@ -1694,6 +1693,7 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
static struct platform_driver sdhci_arasan_driver = { static struct platform_driver sdhci_arasan_driver = {
.driver = { .driver = {
.name = "sdhci-arasan", .name = "sdhci-arasan",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_arasan_of_match, .of_match_table = sdhci_arasan_of_match,
.pm = &sdhci_arasan_dev_pm_ops, .pm = &sdhci_arasan_dev_pm_ops,
}, },

Просмотреть файл

@ -240,6 +240,7 @@ static const struct of_device_id aspeed_sdhci_of_match[] = {
static struct platform_driver aspeed_sdhci_driver = { static struct platform_driver aspeed_sdhci_driver = {
.driver = { .driver = {
.name = "sdhci-aspeed", .name = "sdhci-aspeed",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = aspeed_sdhci_of_match, .of_match_table = aspeed_sdhci_of_match,
}, },
.probe = aspeed_sdhci_probe, .probe = aspeed_sdhci_probe,
@ -318,6 +319,7 @@ MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match);
static struct platform_driver aspeed_sdc_driver = { static struct platform_driver aspeed_sdc_driver = {
.driver = { .driver = {
.name = "sd-controller-aspeed", .name = "sd-controller-aspeed",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
.of_match_table = aspeed_sdc_of_match, .of_match_table = aspeed_sdc_of_match,
}, },

Просмотреть файл

@ -465,6 +465,7 @@ static int sdhci_at91_remove(struct platform_device *pdev)
static struct platform_driver sdhci_at91_driver = { static struct platform_driver sdhci_at91_driver = {
.driver = { .driver = {
.name = "sdhci-at91", .name = "sdhci-at91",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_at91_dt_match, .of_match_table = sdhci_at91_dt_match,
.pm = &sdhci_at91_dev_pm_ops, .pm = &sdhci_at91_dev_pm_ops,
}, },

Просмотреть файл

@ -214,6 +214,7 @@ MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
static struct platform_driver sdhci_dwcmshc_driver = { static struct platform_driver sdhci_dwcmshc_driver = {
.driver = { .driver = {
.name = "sdhci-dwcmshc", .name = "sdhci-dwcmshc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_dwcmshc_dt_ids, .of_match_table = sdhci_dwcmshc_dt_ids,
.pm = &dwcmshc_pmops, .pm = &dwcmshc_pmops,
}, },

Просмотреть файл

@ -1360,13 +1360,19 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
clk_put(clk); clk_put(clk);
} }
if (esdhc->peripheral_clock) { esdhc_clock_enable(host, false);
esdhc_clock_enable(host, false); val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
val = sdhci_readl(host, ESDHC_DMA_SYSCTL); /*
* This bit is not able to be reset by SDHCI_RESET_ALL. Need to
* initialize it as 1 or 0 once, to override the different value
* which may be configured in bootloader.
*/
if (esdhc->peripheral_clock)
val |= ESDHC_PERIPHERAL_CLK_SEL; val |= ESDHC_PERIPHERAL_CLK_SEL;
sdhci_writel(host, val, ESDHC_DMA_SYSCTL); else
esdhc_clock_enable(host, true); val &= ~ESDHC_PERIPHERAL_CLK_SEL;
} sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
esdhc_clock_enable(host, true);
} }
static int esdhc_hs400_prepare_ddr(struct mmc_host *mmc) static int esdhc_hs400_prepare_ddr(struct mmc_host *mmc)
@ -1468,6 +1474,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
static struct platform_driver sdhci_esdhc_driver = { static struct platform_driver sdhci_esdhc_driver = {
.driver = { .driver = {
.name = "sdhci-esdhc", .name = "sdhci-esdhc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_esdhc_of_match, .of_match_table = sdhci_esdhc_of_match,
.pm = &esdhc_of_dev_pm_ops, .pm = &esdhc_of_dev_pm_ops,
}, },

Просмотреть файл

@ -80,6 +80,7 @@ MODULE_DEVICE_TABLE(of, sdhci_hlwd_of_match);
static struct platform_driver sdhci_hlwd_driver = { static struct platform_driver sdhci_hlwd_driver = {
.driver = { .driver = {
.name = "sdhci-hlwd", .name = "sdhci-hlwd",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_hlwd_of_match, .of_match_table = sdhci_hlwd_of_match,
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
}, },

Просмотреть файл

@ -0,0 +1,270 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* drivers/mmc/host/sdhci-of-sparx5.c
*
* MCHP Sparx5 SoC Secure Digital Host Controller Interface.
*
* Copyright (c) 2019 Microchip Inc.
*
* Author: Lars Povlsen <lars.povlsen@microchip.com>
*/
#include <linux/sizes.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/dma-mapping.h>
#include "sdhci-pltfm.h"
#define CPU_REGS_GENERAL_CTRL (0x22 * 4)
#define MSHC_DLY_CC_MASK GENMASK(16, 13)
#define MSHC_DLY_CC_SHIFT 13
#define MSHC_DLY_CC_MAX 15
#define CPU_REGS_PROC_CTRL (0x2C * 4)
#define ACP_CACHE_FORCE_ENA BIT(4)
#define ACP_AWCACHE BIT(3)
#define ACP_ARCACHE BIT(2)
#define ACP_CACHE_MASK (ACP_CACHE_FORCE_ENA|ACP_AWCACHE|ACP_ARCACHE)
#define MSHC2_VERSION 0x500 /* Off 0x140, reg 0x0 */
#define MSHC2_TYPE 0x504 /* Off 0x140, reg 0x1 */
#define MSHC2_EMMC_CTRL 0x52c /* Off 0x140, reg 0xB */
#define MSHC2_EMMC_CTRL_EMMC_RST_N BIT(2)
#define MSHC2_EMMC_CTRL_IS_EMMC BIT(0)
struct sdhci_sparx5_data {
struct sdhci_host *host;
struct regmap *cpu_ctrl;
int delay_clock;
};
#define BOUNDARY_OK(addr, len) \
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
/*
* If DMA addr spans 128MB boundary, we split the DMA transfer into two
* so that each DMA transfer doesn't exceed the boundary.
*/
static void sdhci_sparx5_adma_write_desc(struct sdhci_host *host, void **desc,
dma_addr_t addr, int len,
unsigned int cmd)
{
int tmplen, offset;
if (likely(!len || BOUNDARY_OK(addr, len))) {
sdhci_adma_write_desc(host, desc, addr, len, cmd);
return;
}
pr_debug("%s: write_desc: splitting dma len %d, offset %pad\n",
mmc_hostname(host->mmc), len, &addr);
offset = addr & (SZ_128M - 1);
tmplen = SZ_128M - offset;
sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
addr += tmplen;
len -= tmplen;
sdhci_adma_write_desc(host, desc, addr, len, cmd);
}
static void sparx5_set_cacheable(struct sdhci_host *host, u32 value)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
pr_debug("%s: Set Cacheable = 0x%x\n", mmc_hostname(host->mmc), value);
/* Update ACP caching attributes in HW */
regmap_update_bits(sdhci_sparx5->cpu_ctrl,
CPU_REGS_PROC_CTRL, ACP_CACHE_MASK, value);
}
static void sparx5_set_delay(struct sdhci_host *host, u8 value)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
pr_debug("%s: Set DLY_CC = %u\n", mmc_hostname(host->mmc), value);
/* Update DLY_CC in HW */
regmap_update_bits(sdhci_sparx5->cpu_ctrl,
CPU_REGS_GENERAL_CTRL,
MSHC_DLY_CC_MASK,
(value << MSHC_DLY_CC_SHIFT));
}
static void sdhci_sparx5_set_emmc(struct sdhci_host *host)
{
if (!mmc_card_is_removable(host->mmc)) {
u8 value;
value = sdhci_readb(host, MSHC2_EMMC_CTRL);
if (!(value & MSHC2_EMMC_CTRL_IS_EMMC)) {
value |= MSHC2_EMMC_CTRL_IS_EMMC;
pr_debug("%s: Set EMMC_CTRL: 0x%08x\n",
mmc_hostname(host->mmc), value);
sdhci_writeb(host, value, MSHC2_EMMC_CTRL);
}
}
}
static void sdhci_sparx5_reset_emmc(struct sdhci_host *host)
{
u8 value;
pr_debug("%s: Toggle EMMC_CTRL.EMMC_RST_N\n", mmc_hostname(host->mmc));
value = sdhci_readb(host, MSHC2_EMMC_CTRL) &
~MSHC2_EMMC_CTRL_EMMC_RST_N;
sdhci_writeb(host, value, MSHC2_EMMC_CTRL);
/* For eMMC, minimum is 1us but give it 10us for good measure */
usleep_range(10, 20);
sdhci_writeb(host, value | MSHC2_EMMC_CTRL_EMMC_RST_N,
MSHC2_EMMC_CTRL);
/* For eMMC, minimum is 200us but give it 300us for good measure */
usleep_range(300, 400);
}
static void sdhci_sparx5_reset(struct sdhci_host *host, u8 mask)
{
pr_debug("%s: *** RESET: mask %d\n", mmc_hostname(host->mmc), mask);
sdhci_reset(host, mask);
/* Be sure CARD_IS_EMMC stays set */
sdhci_sparx5_set_emmc(host);
}
static const struct sdhci_ops sdhci_sparx5_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.reset = sdhci_sparx5_reset,
.adma_write_desc = sdhci_sparx5_adma_write_desc,
};
static const struct sdhci_pltfm_data sdhci_sparx5_pdata = {
.quirks = 0,
.quirks2 = SDHCI_QUIRK2_HOST_NO_CMD23 | /* Controller issue */
SDHCI_QUIRK2_NO_1_8_V, /* No sdr104, ddr50, etc */
.ops = &sdhci_sparx5_ops,
};
static int sdhci_sparx5_probe(struct platform_device *pdev)
{
int ret;
const char *syscon = "microchip,sparx5-cpu-syscon";
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_sparx5_data *sdhci_sparx5;
struct device_node *np = pdev->dev.of_node;
u32 value;
u32 extra;
host = sdhci_pltfm_init(pdev, &sdhci_sparx5_pdata,
sizeof(*sdhci_sparx5));
if (IS_ERR(host))
return PTR_ERR(host);
/*
* extra adma table cnt for cross 128M boundary handling.
*/
extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M);
if (extra > SDHCI_MAX_SEGS)
extra = SDHCI_MAX_SEGS;
host->adma_table_cnt += extra;
pltfm_host = sdhci_priv(host);
sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
sdhci_sparx5->host = host;
pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(pltfm_host->clk)) {
ret = PTR_ERR(pltfm_host->clk);
dev_err(&pdev->dev, "failed to get core clk: %d\n", ret);
goto free_pltfm;
}
ret = clk_prepare_enable(pltfm_host->clk);
if (ret)
goto free_pltfm;
if (!of_property_read_u32(np, "microchip,clock-delay", &value) &&
(value > 0 && value <= MSHC_DLY_CC_MAX))
sdhci_sparx5->delay_clock = value;
sdhci_get_of_property(pdev);
ret = mmc_of_parse(host->mmc);
if (ret)
goto err_clk;
sdhci_sparx5->cpu_ctrl = syscon_regmap_lookup_by_compatible(syscon);
if (IS_ERR(sdhci_sparx5->cpu_ctrl)) {
dev_err(&pdev->dev, "No CPU syscon regmap !\n");
ret = PTR_ERR(sdhci_sparx5->cpu_ctrl);
goto err_clk;
}
if (sdhci_sparx5->delay_clock >= 0)
sparx5_set_delay(host, sdhci_sparx5->delay_clock);
if (!mmc_card_is_removable(host->mmc)) {
/* Do a HW reset of eMMC card */
sdhci_sparx5_reset_emmc(host);
/* Update EMMC_CTRL */
sdhci_sparx5_set_emmc(host);
/* If eMMC, disable SD and SDIO */
host->mmc->caps2 |= (MMC_CAP2_NO_SDIO|MMC_CAP2_NO_SD);
}
ret = sdhci_add_host(host);
if (ret)
goto err_clk;
/* Set AXI bus master to use un-cached access (for DMA) */
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA) &&
IS_ENABLED(CONFIG_DMA_DECLARE_COHERENT))
sparx5_set_cacheable(host, ACP_CACHE_FORCE_ENA);
pr_debug("%s: SDHC version: 0x%08x\n",
mmc_hostname(host->mmc), sdhci_readl(host, MSHC2_VERSION));
pr_debug("%s: SDHC type: 0x%08x\n",
mmc_hostname(host->mmc), sdhci_readl(host, MSHC2_TYPE));
return ret;
err_clk:
clk_disable_unprepare(pltfm_host->clk);
free_pltfm:
sdhci_pltfm_free(pdev);
return ret;
}
static const struct of_device_id sdhci_sparx5_of_match[] = {
{ .compatible = "microchip,dw-sparx5-sdhci" },
{ }
};
MODULE_DEVICE_TABLE(of, sdhci_sparx5_of_match);
static struct platform_driver sdhci_sparx5_driver = {
.driver = {
.name = "sdhci-sparx5",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_sparx5_of_match,
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_sparx5_probe,
.remove = sdhci_pltfm_unregister,
};
module_platform_driver(sdhci_sparx5_driver);
MODULE_DESCRIPTION("Sparx5 SDHCI OF driver");
MODULE_AUTHOR("Lars Povlsen <lars.povlsen@microchip.com>");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -1297,6 +1297,7 @@ static struct platform_driver sdhci_omap_driver = {
.remove = sdhci_omap_remove, .remove = sdhci_omap_remove,
.driver = { .driver = {
.name = "sdhci-omap", .name = "sdhci-omap",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_omap_dev_pm_ops, .pm = &sdhci_omap_dev_pm_ops,
.of_match_table = omap_sdhci_match, .of_match_table = omap_sdhci_match,
}, },

Просмотреть файл

@ -24,6 +24,8 @@
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/debugfs.h>
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
#include <linux/mmc/sdhci-pci-data.h> #include <linux/mmc/sdhci-pci-data.h>
#include <linux/acpi.h> #include <linux/acpi.h>
@ -516,6 +518,8 @@ struct intel_host {
bool rpm_retune_ok; bool rpm_retune_ok;
u32 glk_rx_ctrl1; u32 glk_rx_ctrl1;
u32 glk_tun_val; u32 glk_tun_val;
u32 active_ltr;
u32 idle_ltr;
}; };
static const guid_t intel_dsm_guid = static const guid_t intel_dsm_guid =
@ -760,6 +764,108 @@ static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode)
return 0; return 0;
} }
#define INTEL_ACTIVELTR 0x804
#define INTEL_IDLELTR 0x808
#define INTEL_LTR_REQ BIT(15)
#define INTEL_LTR_SCALE_MASK GENMASK(11, 10)
#define INTEL_LTR_SCALE_1US (2 << 10)
#define INTEL_LTR_SCALE_32US (3 << 10)
#define INTEL_LTR_VALUE_MASK GENMASK(9, 0)
static void intel_cache_ltr(struct sdhci_pci_slot *slot)
{
struct intel_host *intel_host = sdhci_pci_priv(slot);
struct sdhci_host *host = slot->host;
intel_host->active_ltr = readl(host->ioaddr + INTEL_ACTIVELTR);
intel_host->idle_ltr = readl(host->ioaddr + INTEL_IDLELTR);
}
static void intel_ltr_set(struct device *dev, s32 val)
{
struct sdhci_pci_chip *chip = dev_get_drvdata(dev);
struct sdhci_pci_slot *slot = chip->slots[0];
struct intel_host *intel_host = sdhci_pci_priv(slot);
struct sdhci_host *host = slot->host;
u32 ltr;
pm_runtime_get_sync(dev);
/*
* Program latency tolerance (LTR) accordingly what has been asked
* by the PM QoS layer or disable it in case we were passed
* negative value or PM_QOS_LATENCY_ANY.
*/
ltr = readl(host->ioaddr + INTEL_ACTIVELTR);
if (val == PM_QOS_LATENCY_ANY || val < 0) {
ltr &= ~INTEL_LTR_REQ;
} else {
ltr |= INTEL_LTR_REQ;
ltr &= ~INTEL_LTR_SCALE_MASK;
ltr &= ~INTEL_LTR_VALUE_MASK;
if (val > INTEL_LTR_VALUE_MASK) {
val >>= 5;
if (val > INTEL_LTR_VALUE_MASK)
val = INTEL_LTR_VALUE_MASK;
ltr |= INTEL_LTR_SCALE_32US | val;
} else {
ltr |= INTEL_LTR_SCALE_1US | val;
}
}
if (ltr == intel_host->active_ltr)
goto out;
writel(ltr, host->ioaddr + INTEL_ACTIVELTR);
writel(ltr, host->ioaddr + INTEL_IDLELTR);
/* Cache the values into lpss structure */
intel_cache_ltr(slot);
out:
pm_runtime_put_autosuspend(dev);
}
static bool intel_use_ltr(struct sdhci_pci_chip *chip)
{
switch (chip->pdev->device) {
case PCI_DEVICE_ID_INTEL_BYT_EMMC:
case PCI_DEVICE_ID_INTEL_BYT_EMMC2:
case PCI_DEVICE_ID_INTEL_BYT_SDIO:
case PCI_DEVICE_ID_INTEL_BYT_SD:
case PCI_DEVICE_ID_INTEL_BSW_EMMC:
case PCI_DEVICE_ID_INTEL_BSW_SDIO:
case PCI_DEVICE_ID_INTEL_BSW_SD:
return false;
default:
return true;
}
}
static void intel_ltr_expose(struct sdhci_pci_chip *chip)
{
struct device *dev = &chip->pdev->dev;
if (!intel_use_ltr(chip))
return;
dev->power.set_latency_tolerance = intel_ltr_set;
dev_pm_qos_expose_latency_tolerance(dev);
}
static void intel_ltr_hide(struct sdhci_pci_chip *chip)
{
struct device *dev = &chip->pdev->dev;
if (!intel_use_ltr(chip))
return;
dev_pm_qos_hide_latency_tolerance(dev);
dev->power.set_latency_tolerance = NULL;
}
static void byt_probe_slot(struct sdhci_pci_slot *slot) static void byt_probe_slot(struct sdhci_pci_slot *slot)
{ {
struct mmc_host_ops *ops = &slot->host->mmc_host_ops; struct mmc_host_ops *ops = &slot->host->mmc_host_ops;
@ -774,6 +880,43 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot)
ops->start_signal_voltage_switch = intel_start_signal_voltage_switch; ops->start_signal_voltage_switch = intel_start_signal_voltage_switch;
device_property_read_u32(dev, "max-frequency", &mmc->f_max); device_property_read_u32(dev, "max-frequency", &mmc->f_max);
if (!mmc->slotno) {
slot->chip->slots[mmc->slotno] = slot;
intel_ltr_expose(slot->chip);
}
}
static void byt_add_debugfs(struct sdhci_pci_slot *slot)
{
struct intel_host *intel_host = sdhci_pci_priv(slot);
struct mmc_host *mmc = slot->host->mmc;
struct dentry *dir = mmc->debugfs_root;
if (!intel_use_ltr(slot->chip))
return;
debugfs_create_x32("active_ltr", 0444, dir, &intel_host->active_ltr);
debugfs_create_x32("idle_ltr", 0444, dir, &intel_host->idle_ltr);
intel_cache_ltr(slot);
}
static int byt_add_host(struct sdhci_pci_slot *slot)
{
int ret = sdhci_add_host(slot->host);
if (!ret)
byt_add_debugfs(slot);
return ret;
}
static void byt_remove_slot(struct sdhci_pci_slot *slot, int dead)
{
struct mmc_host *mmc = slot->host->mmc;
if (!mmc->slotno)
intel_ltr_hide(slot->chip);
} }
static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
@ -855,6 +998,8 @@ static int glk_emmc_add_host(struct sdhci_pci_slot *slot)
if (ret) if (ret)
goto cleanup; goto cleanup;
byt_add_debugfs(slot);
return 0; return 0;
cleanup: cleanup:
@ -1032,6 +1177,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
#endif #endif
.allow_runtime_pm = true, .allow_runtime_pm = true,
.probe_slot = byt_emmc_probe_slot, .probe_slot = byt_emmc_probe_slot,
.add_host = byt_add_host,
.remove_slot = byt_remove_slot,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
SDHCI_QUIRK_NO_LED, SDHCI_QUIRK_NO_LED,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
@ -1045,6 +1192,7 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
.allow_runtime_pm = true, .allow_runtime_pm = true,
.probe_slot = glk_emmc_probe_slot, .probe_slot = glk_emmc_probe_slot,
.add_host = glk_emmc_add_host, .add_host = glk_emmc_add_host,
.remove_slot = byt_remove_slot,
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.suspend = sdhci_cqhci_suspend, .suspend = sdhci_cqhci_suspend,
.resume = sdhci_cqhci_resume, .resume = sdhci_cqhci_resume,
@ -1075,6 +1223,8 @@ static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
SDHCI_QUIRK2_PRESET_VALUE_BROKEN, SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.allow_runtime_pm = true, .allow_runtime_pm = true,
.probe_slot = ni_byt_sdio_probe_slot, .probe_slot = ni_byt_sdio_probe_slot,
.add_host = byt_add_host,
.remove_slot = byt_remove_slot,
.ops = &sdhci_intel_byt_ops, .ops = &sdhci_intel_byt_ops,
.priv_size = sizeof(struct intel_host), .priv_size = sizeof(struct intel_host),
}; };
@ -1092,6 +1242,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
SDHCI_QUIRK2_PRESET_VALUE_BROKEN, SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.allow_runtime_pm = true, .allow_runtime_pm = true,
.probe_slot = byt_sdio_probe_slot, .probe_slot = byt_sdio_probe_slot,
.add_host = byt_add_host,
.remove_slot = byt_remove_slot,
.ops = &sdhci_intel_byt_ops, .ops = &sdhci_intel_byt_ops,
.priv_size = sizeof(struct intel_host), .priv_size = sizeof(struct intel_host),
}; };
@ -1111,6 +1263,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
.allow_runtime_pm = true, .allow_runtime_pm = true,
.own_cd_for_runtime_pm = true, .own_cd_for_runtime_pm = true,
.probe_slot = byt_sd_probe_slot, .probe_slot = byt_sd_probe_slot,
.add_host = byt_add_host,
.remove_slot = byt_remove_slot,
.ops = &sdhci_intel_byt_ops, .ops = &sdhci_intel_byt_ops,
.priv_size = sizeof(struct intel_host), .priv_size = sizeof(struct intel_host),
}; };

Просмотреть файл

@ -14,6 +14,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include "sdhci.h" #include "sdhci.h"
#include "sdhci-pci.h" #include "sdhci-pci.h"
#include "cqhci.h"
/* Genesys Logic extra registers */ /* Genesys Logic extra registers */
#define SDHCI_GLI_9750_WT 0x800 #define SDHCI_GLI_9750_WT 0x800
@ -81,9 +82,16 @@
#define GLI_9763E_VHS_REV_R 0x0 #define GLI_9763E_VHS_REV_R 0x0
#define GLI_9763E_VHS_REV_M 0x1 #define GLI_9763E_VHS_REV_M 0x1
#define GLI_9763E_VHS_REV_W 0x2 #define GLI_9763E_VHS_REV_W 0x2
#define PCIE_GLI_9763E_MB 0x888
#define GLI_9763E_MB_CMDQ_OFF BIT(19)
#define PCIE_GLI_9763E_SCR 0x8E0 #define PCIE_GLI_9763E_SCR 0x8E0
#define GLI_9763E_SCR_AXI_REQ BIT(9) #define GLI_9763E_SCR_AXI_REQ BIT(9)
#define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200
#define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \
SDHCI_TRNS_BLK_CNT_EN | \
SDHCI_TRNS_DMA)
#define PCI_GLI_9755_WT 0x800 #define PCI_GLI_9755_WT 0x800
#define PCI_GLI_9755_WT_EN BIT(0) #define PCI_GLI_9755_WT_EN BIT(0)
#define GLI_9755_WT_EN_ON 0x1 #define GLI_9755_WT_EN_ON 0x1
@ -578,6 +586,30 @@ static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
return sdhci_pci_resume_host(chip); return sdhci_pci_resume_host(chip);
} }
static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip)
{
struct sdhci_pci_slot *slot = chip->slots[0];
int ret;
ret = sdhci_pci_gli_resume(chip);
if (ret)
return ret;
return cqhci_resume(slot->host->mmc);
}
static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip)
{
struct sdhci_pci_slot *slot = chip->slots[0];
int ret;
ret = cqhci_suspend(slot->host->mmc);
if (ret)
return ret;
return sdhci_suspend_host(slot->host);
}
#endif #endif
static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc, static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc,
@ -614,6 +646,110 @@ static void sdhci_set_gl9763e_signaling(struct sdhci_host *host,
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
} }
static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc)
{
sdhci_dumpregs(mmc_priv(mmc));
}
static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc)
{
struct cqhci_host *cq_host = mmc->cqe_private;
u32 value;
value = cqhci_readl(cq_host, CQHCI_CFG);
value |= CQHCI_ENABLE;
cqhci_writel(cq_host, value, CQHCI_CFG);
}
static void sdhci_gl9763e_cqe_enable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
sdhci_writew(host, GLI_9763E_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
sdhci_cqe_enable(mmc);
}
static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask)
{
int cmd_error = 0;
int data_error = 0;
if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
return intmask;
cqhci_irq(host->mmc, intmask, cmd_error, data_error);
return 0;
}
static void sdhci_gl9763e_cqe_post_disable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
struct cqhci_host *cq_host = mmc->cqe_private;
u32 value;
value = cqhci_readl(cq_host, CQHCI_CFG);
value &= ~CQHCI_ENABLE;
cqhci_writel(cq_host, value, CQHCI_CFG);
sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
}
static const struct cqhci_host_ops sdhci_gl9763e_cqhci_ops = {
.enable = sdhci_gl9763e_cqe_enable,
.disable = sdhci_cqe_disable,
.dumpregs = sdhci_gl9763e_dumpregs,
.pre_enable = sdhci_gl9763e_cqe_pre_enable,
.post_disable = sdhci_gl9763e_cqe_post_disable,
};
static int gl9763e_add_host(struct sdhci_pci_slot *slot)
{
struct device *dev = &slot->chip->pdev->dev;
struct sdhci_host *host = slot->host;
struct cqhci_host *cq_host;
bool dma64;
int ret;
ret = sdhci_setup_host(host);
if (ret)
return ret;
cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL);
if (!cq_host) {
ret = -ENOMEM;
goto cleanup;
}
cq_host->mmio = host->ioaddr + SDHCI_GLI_9763E_CQE_BASE_ADDR;
cq_host->ops = &sdhci_gl9763e_cqhci_ops;
dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
if (dma64)
cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
ret = cqhci_init(cq_host, host->mmc, dma64);
if (ret)
goto cleanup;
ret = __sdhci_add_host(host);
if (ret)
goto cleanup;
return 0;
cleanup:
sdhci_cleanup_host(host);
return ret;
}
static void sdhci_gl9763e_reset(struct sdhci_host *host, u8 mask)
{
if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) &&
host->mmc->cqe_private)
cqhci_deactivate(host->mmc);
sdhci_reset(host, mask);
}
static void gli_set_gl9763e(struct sdhci_pci_slot *slot) static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
{ {
struct pci_dev *pdev = slot->chip->pdev; struct pci_dev *pdev = slot->chip->pdev;
@ -636,7 +772,9 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
{ {
struct pci_dev *pdev = slot->chip->pdev;
struct sdhci_host *host = slot->host; struct sdhci_host *host = slot->host;
u32 value;
host->mmc->caps |= MMC_CAP_8_BIT_DATA | host->mmc->caps |= MMC_CAP_8_BIT_DATA |
MMC_CAP_1_8V_DDR | MMC_CAP_1_8V_DDR |
@ -646,6 +784,11 @@ static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
MMC_CAP2_HS400_ES | MMC_CAP2_HS400_ES |
MMC_CAP2_NO_SDIO | MMC_CAP2_NO_SDIO |
MMC_CAP2_NO_SD; MMC_CAP2_NO_SD;
pci_read_config_dword(pdev, PCIE_GLI_9763E_MB, &value);
if (!(value & GLI_9763E_MB_CMDQ_OFF))
host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
gli_pcie_enable_msi(slot); gli_pcie_enable_msi(slot);
host->mmc_host_ops.hs400_enhanced_strobe = host->mmc_host_ops.hs400_enhanced_strobe =
gl9763e_hs400_enhanced_strobe; gl9763e_hs400_enhanced_strobe;
@ -699,9 +842,10 @@ static const struct sdhci_ops sdhci_gl9763e_ops = {
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma, .enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset, .reset = sdhci_gl9763e_reset,
.set_uhs_signaling = sdhci_set_gl9763e_signaling, .set_uhs_signaling = sdhci_set_gl9763e_signaling,
.voltage_switch = sdhci_gli_voltage_switch, .voltage_switch = sdhci_gli_voltage_switch,
.irq = sdhci_gl9763e_cqhci_irq,
}; };
const struct sdhci_pci_fixes sdhci_gl9763e = { const struct sdhci_pci_fixes sdhci_gl9763e = {
@ -709,6 +853,8 @@ const struct sdhci_pci_fixes sdhci_gl9763e = {
.probe_slot = gli_probe_slot_gl9763e, .probe_slot = gli_probe_slot_gl9763e,
.ops = &sdhci_gl9763e_ops, .ops = &sdhci_gl9763e_ops,
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.resume = sdhci_pci_gli_resume, .resume = sdhci_cqhci_gli_resume,
.suspend = sdhci_cqhci_gli_suspend,
#endif #endif
.add_host = gl9763e_add_host,
}; };

Просмотреть файл

@ -241,6 +241,7 @@ MODULE_DEVICE_TABLE(of, pic32_sdhci_id_table);
static struct platform_driver pic32_sdhci_driver = { static struct platform_driver pic32_sdhci_driver = {
.driver = { .driver = {
.name = "pic32-sdhci", .name = "pic32-sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(pic32_sdhci_id_table), .of_match_table = of_match_ptr(pic32_sdhci_id_table),
}, },
.probe = pic32_sdhci_probe, .probe = pic32_sdhci_probe,

Просмотреть файл

@ -226,6 +226,7 @@ free:
static struct platform_driver sdhci_pxav2_driver = { static struct platform_driver sdhci_pxav2_driver = {
.driver = { .driver = {
.name = "sdhci-pxav2", .name = "sdhci-pxav2",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(sdhci_pxav2_of_match), .of_match_table = of_match_ptr(sdhci_pxav2_of_match),
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
}, },

Просмотреть файл

@ -567,6 +567,7 @@ static const struct dev_pm_ops sdhci_pxav3_pmops = {
static struct platform_driver sdhci_pxav3_driver = { static struct platform_driver sdhci_pxav3_driver = {
.driver = { .driver = {
.name = "sdhci-pxav3", .name = "sdhci-pxav3",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(sdhci_pxav3_of_match), .of_match_table = of_match_ptr(sdhci_pxav3_of_match),
.pm = &sdhci_pxav3_pmops, .pm = &sdhci_pxav3_pmops,
}, },

Просмотреть файл

@ -461,7 +461,9 @@ static int sdhci_s3c_parse_dt(struct device *dev,
} }
#endif #endif
#ifdef CONFIG_OF
static const struct of_device_id sdhci_s3c_dt_match[]; static const struct of_device_id sdhci_s3c_dt_match[];
#endif
static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data( static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data(
struct platform_device *pdev) struct platform_device *pdev)
@ -784,6 +786,7 @@ static struct platform_driver sdhci_s3c_driver = {
.id_table = sdhci_s3c_driver_ids, .id_table = sdhci_s3c_driver_ids,
.driver = { .driver = {
.name = "s3c-sdhci", .name = "s3c-sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(sdhci_s3c_dt_match), .of_match_table = of_match_ptr(sdhci_s3c_dt_match),
.pm = &sdhci_s3c_pmops, .pm = &sdhci_s3c_pmops,
}, },

Просмотреть файл

@ -220,6 +220,7 @@ MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match);
static struct platform_driver sdhci_sirf_driver = { static struct platform_driver sdhci_sirf_driver = {
.driver = { .driver = {
.name = "sdhci-sirf", .name = "sdhci-sirf",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_sirf_of_match, .of_match_table = sdhci_sirf_of_match,
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
}, },

Просмотреть файл

@ -181,6 +181,7 @@ MODULE_DEVICE_TABLE(of, sdhci_spear_id_table);
static struct platform_driver sdhci_driver = { static struct platform_driver sdhci_driver = {
.driver = { .driver = {
.name = "sdhci", .name = "sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pm_ops, .pm = &sdhci_pm_ops,
.of_match_table = of_match_ptr(sdhci_spear_id_table), .of_match_table = of_match_ptr(sdhci_spear_id_table),
}, },

Просмотреть файл

@ -387,7 +387,7 @@ static void sdhci_sprd_request_done(struct sdhci_host *host,
if (mmc_hsq_finalize_request(host->mmc, mrq)) if (mmc_hsq_finalize_request(host->mmc, mrq))
return; return;
mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq);
} }
static struct sdhci_ops sdhci_sprd_ops = { static struct sdhci_ops sdhci_sprd_ops = {
@ -433,7 +433,7 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
} }
static int sdhci_sprd_request_atomic(struct mmc_host *mmc, static int sdhci_sprd_request_atomic(struct mmc_host *mmc,
struct mmc_request *mrq) struct mmc_request *mrq)
{ {
sdhci_sprd_check_auto_cmd23(mmc, mrq); sdhci_sprd_check_auto_cmd23(mmc, mrq);
@ -787,6 +787,7 @@ static struct platform_driver sdhci_sprd_driver = {
.remove = sdhci_sprd_remove, .remove = sdhci_sprd_remove,
.driver = { .driver = {
.name = "sdhci_sprd_r11", .name = "sdhci_sprd_r11",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(sdhci_sprd_of_match), .of_match_table = of_match_ptr(sdhci_sprd_of_match),
.pm = &sdhci_sprd_pm_ops, .pm = &sdhci_sprd_pm_ops,
}, },

Просмотреть файл

@ -521,6 +521,7 @@ static struct platform_driver sdhci_st_driver = {
.remove = sdhci_st_remove, .remove = sdhci_st_remove,
.driver = { .driver = {
.name = "sdhci-st", .name = "sdhci-st",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_st_pmops, .pm = &sdhci_st_pmops,
.of_match_table = of_match_ptr(st_sdhci_match), .of_match_table = of_match_ptr(st_sdhci_match),
}, },

Просмотреть файл

@ -1660,11 +1660,8 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
clk = devm_clk_get(mmc_dev(host->mmc), NULL); clk = devm_clk_get(mmc_dev(host->mmc), NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
rc = PTR_ERR(clk); rc = dev_err_probe(&pdev->dev, PTR_ERR(clk),
"failed to get clock\n");
if (rc != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to get clock: %d\n", rc);
goto err_clk_get; goto err_clk_get;
} }
clk_prepare_enable(clk); clk_prepare_enable(clk);
@ -1785,6 +1782,7 @@ static SIMPLE_DEV_PM_OPS(sdhci_tegra_dev_pm_ops, sdhci_tegra_suspend,
static struct platform_driver sdhci_tegra_driver = { static struct platform_driver sdhci_tegra_driver = {
.driver = { .driver = {
.name = "sdhci-tegra", .name = "sdhci-tegra",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_tegra_dt_match, .of_match_table = sdhci_tegra_dt_match,
.pm = &sdhci_tegra_dev_pm_ops, .pm = &sdhci_tegra_dev_pm_ops,
}, },

Просмотреть файл

@ -677,6 +677,7 @@ MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
static struct platform_driver sdhci_xenon_driver = { static struct platform_driver sdhci_xenon_driver = {
.driver = { .driver = {
.name = "xenon-sdhci", .name = "xenon-sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_xenon_dt_ids, .of_match_table = sdhci_xenon_dt_ids,
.pm = &sdhci_xenon_dev_pm_ops, .pm = &sdhci_xenon_dev_pm_ops,
}, },

Просмотреть файл

@ -2,10 +2,11 @@
/* /*
* sdhci_am654.c - SDHCI driver for TI's AM654 SOCs * sdhci_am654.c - SDHCI driver for TI's AM654 SOCs
* *
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com
* *
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@ -18,9 +19,11 @@
/* CTL_CFG Registers */ /* CTL_CFG Registers */
#define CTL_CFG_2 0x14 #define CTL_CFG_2 0x14
#define CTL_CFG_3 0x18
#define SLOTTYPE_MASK GENMASK(31, 30) #define SLOTTYPE_MASK GENMASK(31, 30)
#define SLOTTYPE_EMBEDDED BIT(30) #define SLOTTYPE_EMBEDDED BIT(30)
#define TUNINGFORSDR50_MASK BIT(13)
/* PHY Registers */ /* PHY Registers */
#define PHY_CTRL1 0x100 #define PHY_CTRL1 0x100
@ -65,6 +68,14 @@
#define RETRIM_MASK BIT(RETRIM_SHIFT) #define RETRIM_MASK BIT(RETRIM_SHIFT)
#define SELDLYTXCLK_SHIFT 17 #define SELDLYTXCLK_SHIFT 17
#define SELDLYTXCLK_MASK BIT(SELDLYTXCLK_SHIFT) #define SELDLYTXCLK_MASK BIT(SELDLYTXCLK_SHIFT)
#define SELDLYRXCLK_SHIFT 16
#define SELDLYRXCLK_MASK BIT(SELDLYRXCLK_SHIFT)
#define ITAPDLYSEL_SHIFT 0
#define ITAPDLYSEL_MASK GENMASK(4, 0)
#define ITAPDLYENA_SHIFT 8
#define ITAPDLYENA_MASK BIT(ITAPDLYENA_SHIFT)
#define ITAPCHGWIN_SHIFT 9
#define ITAPCHGWIN_MASK BIT(ITAPCHGWIN_SHIFT)
#define DRIVER_STRENGTH_50_OHM 0x0 #define DRIVER_STRENGTH_50_OHM 0x0
#define DRIVER_STRENGTH_33_OHM 0x1 #define DRIVER_STRENGTH_33_OHM 0x1
@ -72,7 +83,7 @@
#define DRIVER_STRENGTH_100_OHM 0x3 #define DRIVER_STRENGTH_100_OHM 0x3
#define DRIVER_STRENGTH_40_OHM 0x4 #define DRIVER_STRENGTH_40_OHM 0x4
#define CLOCK_TOO_SLOW_HZ 400000 #define CLOCK_TOO_SLOW_HZ 50000000
/* Command Queue Host Controller Interface Base address */ /* Command Queue Host Controller Interface Base address */
#define SDHCI_AM654_CQE_BASE_ADDR 0x200 #define SDHCI_AM654_CQE_BASE_ADDR 0x200
@ -84,14 +95,56 @@ static struct regmap_config sdhci_am654_regmap_config = {
.fast_io = true, .fast_io = true,
}; };
struct timing_data {
const char *otap_binding;
const char *itap_binding;
u32 capability;
};
static const struct timing_data td[] = {
[MMC_TIMING_LEGACY] = {"ti,otap-del-sel-legacy",
"ti,itap-del-sel-legacy",
0},
[MMC_TIMING_MMC_HS] = {"ti,otap-del-sel-mmc-hs",
"ti,itap-del-sel-mmc-hs",
MMC_CAP_MMC_HIGHSPEED},
[MMC_TIMING_SD_HS] = {"ti,otap-del-sel-sd-hs",
"ti,itap-del-sel-sd-hs",
MMC_CAP_SD_HIGHSPEED},
[MMC_TIMING_UHS_SDR12] = {"ti,otap-del-sel-sdr12",
"ti,itap-del-sel-sdr12",
MMC_CAP_UHS_SDR12},
[MMC_TIMING_UHS_SDR25] = {"ti,otap-del-sel-sdr25",
"ti,itap-del-sel-sdr25",
MMC_CAP_UHS_SDR25},
[MMC_TIMING_UHS_SDR50] = {"ti,otap-del-sel-sdr50",
NULL,
MMC_CAP_UHS_SDR50},
[MMC_TIMING_UHS_SDR104] = {"ti,otap-del-sel-sdr104",
NULL,
MMC_CAP_UHS_SDR104},
[MMC_TIMING_UHS_DDR50] = {"ti,otap-del-sel-ddr50",
NULL,
MMC_CAP_UHS_DDR50},
[MMC_TIMING_MMC_DDR52] = {"ti,otap-del-sel-ddr52",
"ti,itap-del-sel-ddr52",
MMC_CAP_DDR},
[MMC_TIMING_MMC_HS200] = {"ti,otap-del-sel-hs200",
NULL,
MMC_CAP2_HS200},
[MMC_TIMING_MMC_HS400] = {"ti,otap-del-sel-hs400",
NULL,
MMC_CAP2_HS400},
};
struct sdhci_am654_data { struct sdhci_am654_data {
struct regmap *base; struct regmap *base;
bool legacy_otapdly; bool legacy_otapdly;
int otap_del_sel[11]; int otap_del_sel[ARRAY_SIZE(td)];
int itap_del_sel[ARRAY_SIZE(td)];
int clkbuf_sel; int clkbuf_sel;
int trm_icp; int trm_icp;
int drv_strength; int drv_strength;
bool dll_on;
int strb_sel; int strb_sel;
u32 flags; u32 flags;
}; };
@ -106,26 +159,6 @@ struct sdhci_am654_driver_data {
#define DLL_CALIB (1 << 4) #define DLL_CALIB (1 << 4)
}; };
struct timing_data {
const char *binding;
u32 capability;
};
static const struct timing_data td[] = {
[MMC_TIMING_LEGACY] = {"ti,otap-del-sel-legacy", 0},
[MMC_TIMING_MMC_HS] = {"ti,otap-del-sel-mmc-hs", MMC_CAP_MMC_HIGHSPEED},
[MMC_TIMING_SD_HS] = {"ti,otap-del-sel-sd-hs", MMC_CAP_SD_HIGHSPEED},
[MMC_TIMING_UHS_SDR12] = {"ti,otap-del-sel-sdr12", MMC_CAP_UHS_SDR12},
[MMC_TIMING_UHS_SDR25] = {"ti,otap-del-sel-sdr25", MMC_CAP_UHS_SDR25},
[MMC_TIMING_UHS_SDR50] = {"ti,otap-del-sel-sdr50", MMC_CAP_UHS_SDR50},
[MMC_TIMING_UHS_SDR104] = {"ti,otap-del-sel-sdr104",
MMC_CAP_UHS_SDR104},
[MMC_TIMING_UHS_DDR50] = {"ti,otap-del-sel-ddr50", MMC_CAP_UHS_DDR50},
[MMC_TIMING_MMC_DDR52] = {"ti,otap-del-sel-ddr52", MMC_CAP_DDR},
[MMC_TIMING_MMC_HS200] = {"ti,otap-del-sel-hs200", MMC_CAP2_HS200},
[MMC_TIMING_MMC_HS400] = {"ti,otap-del-sel-hs400", MMC_CAP2_HS400},
};
static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock) static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@ -134,6 +167,10 @@ static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock)
u32 mask, val; u32 mask, val;
int ret; int ret;
/* Disable delay chain mode */
regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
SELDLYTXCLK_MASK | SELDLYRXCLK_MASK, 0);
if (sdhci_am654->flags & FREQSEL_2_BIT) { if (sdhci_am654->flags & FREQSEL_2_BIT) {
switch (clock) { switch (clock) {
case 200000000: case 200000000:
@ -188,8 +225,32 @@ static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock)
dev_err(mmc_dev(host->mmc), "DLL failed to relock\n"); dev_err(mmc_dev(host->mmc), "DLL failed to relock\n");
return; return;
} }
}
sdhci_am654->dll_on = true; static void sdhci_am654_write_itapdly(struct sdhci_am654_data *sdhci_am654,
u32 itapdly)
{
/* Set ITAPCHGWIN before writing to ITAPDLY */
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK,
1 << ITAPCHGWIN_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYSEL_MASK,
itapdly << ITAPDLYSEL_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
}
static void sdhci_am654_setup_delay_chain(struct sdhci_am654_data *sdhci_am654,
unsigned char timing)
{
u32 mask, val;
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
val = 1 << SELDLYTXCLK_SHIFT | 1 << SELDLYRXCLK_SHIFT;
mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK;
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask, val);
sdhci_am654_write_itapdly(sdhci_am654,
sdhci_am654->itap_del_sel[timing]);
} }
static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
@ -201,11 +262,7 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
u32 otap_del_ena; u32 otap_del_ena;
u32 mask, val; u32 mask, val;
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;
}
sdhci_set_clock(host, clock); sdhci_set_clock(host, clock);
@ -233,14 +290,10 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
if (timing > MMC_TIMING_UHS_SDR25 && clock > CLOCK_TOO_SLOW_HZ) { if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ)
regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
SELDLYTXCLK_MASK, 0);
sdhci_am654_setup_dll(host, clock); sdhci_am654_setup_dll(host, clock);
} else { else
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, sdhci_am654_setup_delay_chain(sdhci_am654, timing);
SELDLYTXCLK_MASK, 1 << SELDLYTXCLK_SHIFT);
}
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
sdhci_am654->clkbuf_sel); sdhci_am654->clkbuf_sel);
@ -272,9 +325,19 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
sdhci_set_clock(host, clock); sdhci_set_clock(host, clock);
} }
static u8 sdhci_am654_write_power_on(struct sdhci_host *host, u8 val, int reg)
{
writeb(val, host->ioaddr + reg);
usleep_range(1000, 10000);
return readb(host->ioaddr + reg);
}
#define MAX_POWER_ON_TIMEOUT 1500000 /* us */
static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg) static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg)
{ {
unsigned char timing = host->mmc->ios.timing; unsigned char timing = host->mmc->ios.timing;
u8 pwr;
int ret;
if (reg == SDHCI_HOST_CONTROL) { if (reg == SDHCI_HOST_CONTROL) {
switch (timing) { switch (timing) {
@ -291,6 +354,19 @@ static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg)
} }
writeb(val, host->ioaddr + reg); writeb(val, host->ioaddr + reg);
if (reg == SDHCI_POWER_CONTROL && (val & SDHCI_POWER_ON)) {
/*
* Power on will not happen until the card detect debounce
* timer expires. Wait at least 1.5 seconds for the power on
* bit to be set
*/
ret = read_poll_timeout(sdhci_am654_write_power_on, pwr,
pwr & SDHCI_POWER_ON, 0,
MAX_POWER_ON_TIMEOUT, false, host, val,
reg);
if (ret)
dev_warn(mmc_dev(host->mmc), "Power on failed\n");
}
} }
static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode) static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode)
@ -322,7 +398,46 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask)
return 0; return 0;
} }
#define ITAP_MAX 32
static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host,
u32 opcode)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len;
u32 itap;
/* Enable ITAPDLY */
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK,
1 << ITAPDLYENA_SHIFT);
for (itap = 0; itap < ITAP_MAX; itap++) {
sdhci_am654_write_itapdly(sdhci_am654, itap);
cur_val = !mmc_send_tuning(host->mmc, opcode, NULL);
if (cur_val && !prev_val)
pass_window = itap;
if (!cur_val)
fail_len++;
prev_val = cur_val;
}
/*
* Having determined the length of the failing window and start of
* the passing window calculate the length of the passing window and
* set the final value halfway through it considering the range as a
* circular buffer
*/
pass_len = ITAP_MAX - fail_len;
itap = (pass_window + (pass_len >> 1)) % ITAP_MAX;
sdhci_am654_write_itapdly(sdhci_am654, itap);
return 0;
}
static struct sdhci_ops sdhci_am654_ops = { static struct sdhci_ops sdhci_am654_ops = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
@ -352,6 +467,7 @@ static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
}; };
static struct sdhci_ops sdhci_j721e_8bit_ops = { static struct sdhci_ops sdhci_j721e_8bit_ops = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
@ -375,6 +491,7 @@ static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
}; };
static struct sdhci_ops sdhci_j721e_4bit_ops = { static struct sdhci_ops sdhci_j721e_4bit_ops = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
@ -445,7 +562,7 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
int i; int i;
int ret; int ret;
ret = device_property_read_u32(dev, td[MMC_TIMING_LEGACY].binding, ret = device_property_read_u32(dev, td[MMC_TIMING_LEGACY].otap_binding,
&sdhci_am654->otap_del_sel[MMC_TIMING_LEGACY]); &sdhci_am654->otap_del_sel[MMC_TIMING_LEGACY]);
if (ret) { if (ret) {
/* /*
@ -468,11 +585,11 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
for (i = MMC_TIMING_MMC_HS; i <= MMC_TIMING_MMC_HS400; i++) { for (i = MMC_TIMING_MMC_HS; i <= MMC_TIMING_MMC_HS400; i++) {
ret = device_property_read_u32(dev, td[i].binding, ret = device_property_read_u32(dev, td[i].otap_binding,
&sdhci_am654->otap_del_sel[i]); &sdhci_am654->otap_del_sel[i]);
if (ret) { if (ret) {
dev_dbg(dev, "Couldn't find %s\n", dev_dbg(dev, "Couldn't find %s\n",
td[i].binding); td[i].otap_binding);
/* /*
* Remove the corresponding capability * Remove the corresponding capability
* if an otap-del-sel value is not found * if an otap-del-sel value is not found
@ -482,6 +599,10 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
else else
host->mmc->caps2 &= ~td[i].capability; host->mmc->caps2 &= ~td[i].capability;
} }
if (td[i].itap_binding)
device_property_read_u32(dev, td[i].itap_binding,
&sdhci_am654->itap_del_sel[i]);
} }
return 0; return 0;
@ -527,6 +648,10 @@ static int sdhci_am654_init(struct sdhci_host *host)
regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK, regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK,
ctl_cfg_2); ctl_cfg_2);
/* Enable tuning for SDR50 */
regmap_update_bits(sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK,
TUNINGFORSDR50_MASK);
ret = sdhci_setup_host(host); ret = sdhci_setup_host(host);
if (ret) if (ret)
return ret; return ret;
@ -614,6 +739,7 @@ static const struct of_device_id sdhci_am654_of_match[] = {
}, },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, sdhci_am654_of_match);
static int sdhci_am654_probe(struct platform_device *pdev) static int sdhci_am654_probe(struct platform_device *pdev)
{ {
@ -721,6 +847,7 @@ static int sdhci_am654_remove(struct platform_device *pdev)
static struct platform_driver sdhci_am654_driver = { static struct platform_driver sdhci_am654_driver = {
.driver = { .driver = {
.name = "sdhci-am654", .name = "sdhci-am654",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_am654_of_match, .of_match_table = sdhci_am654_of_match,
}, },
.probe = sdhci_am654_probe, .probe = sdhci_am654_probe,

Просмотреть файл

@ -219,6 +219,7 @@ MODULE_DEVICE_TABLE(acpi, f_sdh30_acpi_ids);
static struct platform_driver sdhci_f_sdh30_driver = { static struct platform_driver sdhci_f_sdh30_driver = {
.driver = { .driver = {
.name = "f_sdh30", .name = "f_sdh30",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(f_sdh30_dt_ids), .of_match_table = of_match_ptr(f_sdh30_dt_ids),
.acpi_match_table = ACPI_PTR(f_sdh30_acpi_ids), .acpi_match_table = ACPI_PTR(f_sdh30_acpi_ids),
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,

Просмотреть файл

@ -1562,6 +1562,7 @@ static struct platform_driver sh_mmcif_driver = {
.remove = sh_mmcif_remove, .remove = sh_mmcif_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sh_mmcif_dev_pm_ops, .pm = &sh_mmcif_dev_pm_ops,
.of_match_table = sh_mmcif_of_match, .of_match_table = sh_mmcif_of_match,
}, },

Просмотреть файл

@ -1514,6 +1514,7 @@ static const struct dev_pm_ops sunxi_mmc_pm_ops = {
static struct platform_driver sunxi_mmc_driver = { static struct platform_driver sunxi_mmc_driver = {
.driver = { .driver = {
.name = "sunxi-mmc", .name = "sunxi-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(sunxi_mmc_of_match), .of_match_table = of_match_ptr(sunxi_mmc_of_match),
.pm = &sunxi_mmc_pm_ops, .pm = &sunxi_mmc_pm_ops,
}, },

Просмотреть файл

@ -77,18 +77,10 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
static void tmio_mmc_reset(struct tmio_mmc_host *host) static void tmio_mmc_reset(struct tmio_mmc_host *host)
{ {
/* FIXME - should we set stop clock reg here */
sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
usleep_range(10000, 11000); usleep_range(10000, 11000);
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
usleep_range(10000, 11000); usleep_range(10000, 11000);
if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) {
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
}
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
@ -221,6 +213,7 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
static struct platform_driver tmio_mmc_driver = { static struct platform_driver tmio_mmc_driver = {
.driver = { .driver = {
.name = "tmio-mmc", .name = "tmio-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &tmio_mmc_dev_pm_ops, .pm = &tmio_mmc_dev_pm_ops,
}, },
.probe = tmio_mmc_probe, .probe = tmio_mmc_probe,

Просмотреть файл

@ -178,14 +178,8 @@ struct tmio_mmc_host {
unsigned int direction, int blk_size); unsigned int direction, int blk_size);
int (*write16_hook)(struct tmio_mmc_host *host, int addr); int (*write16_hook)(struct tmio_mmc_host *host, int addr);
void (*reset)(struct tmio_mmc_host *host); void (*reset)(struct tmio_mmc_host *host);
void (*hw_reset)(struct tmio_mmc_host *host);
bool (*check_retune)(struct tmio_mmc_host *host); bool (*check_retune)(struct tmio_mmc_host *host);
void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq);
/*
* Mandatory callback for tuning to occur which is optional for SDR50
* and mandatory for SDR104.
*/
int (*execute_tuning)(struct tmio_mmc_host *host, u32 opcode);
void (*prepare_hs400_tuning)(struct tmio_mmc_host *host); void (*prepare_hs400_tuning)(struct tmio_mmc_host *host);
void (*hs400_downgrade)(struct tmio_mmc_host *host); void (*hs400_downgrade)(struct tmio_mmc_host *host);

Просмотреть файл

@ -172,24 +172,15 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
usleep_range(10000, 11000); usleep_range(10000, 11000);
if (host->reset)
host->reset(host);
if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) { if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) {
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
} }
} }
static void tmio_mmc_hw_reset(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
host->reset(host);
tmio_mmc_abort_dma(host);
if (host->hw_reset)
host->hw_reset(host);
}
static void tmio_mmc_reset_work(struct work_struct *work) static void tmio_mmc_reset_work(struct work_struct *work)
{ {
struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host,
@ -228,11 +219,12 @@ static void tmio_mmc_reset_work(struct work_struct *work)
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
tmio_mmc_hw_reset(host->mmc); tmio_mmc_reset(host);
/* Ready for new calls */ /* Ready for new calls */
host->mrq = NULL; host->mrq = NULL;
tmio_mmc_abort_dma(host);
mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq);
} }
@ -720,24 +712,6 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
return 0; return 0;
} }
static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
int ret;
if (!host->execute_tuning)
return 0;
ret = host->execute_tuning(host, opcode);
if (ret < 0) {
dev_warn(&host->pdev->dev, "Tuning procedure failed\n");
tmio_mmc_hw_reset(mmc);
}
return ret;
}
static void tmio_process_mrq(struct tmio_mmc_host *host, static void tmio_process_mrq(struct tmio_mmc_host *host,
struct mmc_request *mrq) struct mmc_request *mrq)
{ {
@ -835,6 +809,9 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
return; return;
} }
if (host->fixup_request)
host->fixup_request(host, mrq);
mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq);
} }
@ -1011,8 +988,6 @@ static struct mmc_host_ops tmio_mmc_ops = {
.get_cd = tmio_mmc_get_cd, .get_cd = tmio_mmc_get_cd,
.enable_sdio_irq = tmio_mmc_enable_sdio_irq, .enable_sdio_irq = tmio_mmc_enable_sdio_irq,
.multi_io_quirk = tmio_multi_io_quirk, .multi_io_quirk = tmio_multi_io_quirk,
.hw_reset = tmio_mmc_hw_reset,
.execute_tuning = tmio_mmc_execute_tuning,
}; };
static int tmio_mmc_init_ocr(struct tmio_mmc_host *host) static int tmio_mmc_init_ocr(struct tmio_mmc_host *host)
@ -1156,9 +1131,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
mmc->caps & MMC_CAP_NEEDS_POLL || mmc->caps & MMC_CAP_NEEDS_POLL ||
!mmc_card_is_removable(mmc)); !mmc_card_is_removable(mmc));
if (!_host->reset)
_host->reset = tmio_mmc_reset;
/* /*
* On Gen2+, eMMC with NONREMOVABLE currently fails because native * On Gen2+, eMMC with NONREMOVABLE currently fails because native
* hotplug gets disabled. It seems RuntimePM related yet we need further * hotplug gets disabled. It seems RuntimePM related yet we need further
@ -1180,7 +1152,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
_host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; _host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
_host->set_clock(_host, 0); _host->set_clock(_host, 0);
tmio_mmc_hw_reset(mmc); tmio_mmc_reset(_host);
_host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK); _host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK);
tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
@ -1283,7 +1255,7 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
struct tmio_mmc_host *host = dev_get_drvdata(dev); struct tmio_mmc_host *host = dev_get_drvdata(dev);
tmio_mmc_clk_enable(host); tmio_mmc_clk_enable(host);
tmio_mmc_hw_reset(host->mmc); tmio_mmc_reset(host);
if (host->clk_cache) if (host->clk_cache)
host->set_clock(host, host->clk_cache); host->set_clock(host, host->clk_cache);

Просмотреть файл

@ -409,8 +409,9 @@ static void uniphier_sd_clk_disable(struct tmio_mmc_host *host)
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
} }
static void uniphier_sd_hw_reset(struct tmio_mmc_host *host) static void uniphier_sd_hw_reset(struct mmc_host *mmc)
{ {
struct tmio_mmc_host *host = mmc_priv(mmc);
struct uniphier_sd_priv *priv = uniphier_sd_priv(host); struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
reset_control_assert(priv->rst_hw); reset_control_assert(priv->rst_hw);
@ -597,7 +598,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
ret = PTR_ERR(priv->rst_hw); ret = PTR_ERR(priv->rst_hw);
goto free_host; goto free_host;
} }
host->hw_reset = uniphier_sd_hw_reset; host->ops.hw_reset = uniphier_sd_hw_reset;
} }
if (host->mmc->caps & MMC_CAP_UHS) { if (host->mmc->caps & MMC_CAP_UHS) {
@ -684,6 +685,7 @@ static struct platform_driver uniphier_sd_driver = {
.remove = uniphier_sd_remove, .remove = uniphier_sd_remove,
.driver = { .driver = {
.name = "uniphier-sd", .name = "uniphier-sd",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = uniphier_sd_match, .of_match_table = uniphier_sd_match,
}, },
}; };

Просмотреть файл

@ -1890,6 +1890,7 @@ static struct platform_driver usdhi6_driver = {
.remove = usdhi6_remove, .remove = usdhi6_remove,
.driver = { .driver = {
.name = "usdhi6rol0", .name = "usdhi6rol0",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = usdhi6_of_match, .of_match_table = usdhi6_of_match,
}, },
}; };

Просмотреть файл

@ -1257,11 +1257,14 @@ static void __maybe_unused via_init_sdc_pm(struct via_crdr_mmc_host *host)
static int __maybe_unused via_sd_suspend(struct device *dev) static int __maybe_unused via_sd_suspend(struct device *dev)
{ {
struct via_crdr_mmc_host *host; struct via_crdr_mmc_host *host;
unsigned long flags;
host = dev_get_drvdata(dev); host = dev_get_drvdata(dev);
spin_lock_irqsave(&host->lock, flags);
via_save_pcictrlreg(host); via_save_pcictrlreg(host);
via_save_sdcreg(host); via_save_sdcreg(host);
spin_unlock_irqrestore(&host->lock, flags);
device_wakeup_enable(dev); device_wakeup_enable(dev);

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше