- 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 {
compatible = "fsl,imx8qxp-usdhc";
compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc";
interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x5b010000 0x10000>;
clocks = <&conn_lpcg IMX_CONN_LPCG_SDHC0_IPG_CLK>,

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

@ -21,23 +21,26 @@ description: |
properties:
compatible:
enum:
- fsl,imx25-esdhc
- fsl,imx35-esdhc
- fsl,imx51-esdhc
- fsl,imx53-esdhc
- fsl,imx6q-usdhc
- fsl,imx6sl-usdhc
- fsl,imx6sx-usdhc
- fsl,imx6ull-usdhc
- fsl,imx7d-usdhc
- fsl,imx7ulp-usdhc
- fsl,imx8mq-usdhc
- fsl,imx8mm-usdhc
- fsl,imx8mn-usdhc
- fsl,imx8mp-usdhc
- fsl,imx8qm-usdhc
- fsl,imx8qxp-usdhc
oneOf:
- enum:
- fsl,imx25-esdhc
- fsl,imx35-esdhc
- fsl,imx51-esdhc
- fsl,imx53-esdhc
- fsl,imx6q-usdhc
- fsl,imx6sl-usdhc
- fsl,imx6sx-usdhc
- fsl,imx6ull-usdhc
- fsl,imx7d-usdhc
- fsl,imx7ulp-usdhc
- items:
- enum:
- fsl,imx8mm-usdhc
- fsl,imx8mn-usdhc
- fsl,imx8mp-usdhc
- fsl,imx8mq-usdhc
- fsl,imx8qxp-usdhc
- const: fsl,imx7d-usdhc
reg:
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
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:
$nodename:
pattern: "^mmc(@.*)?$"

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

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

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

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

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

@ -50,6 +50,7 @@ properties:
- renesas,sdhi-r8a774a1 # RZ/G2M
- renesas,sdhi-r8a774b1 # RZ/G2N
- renesas,sdhi-r8a774c0 # RZ/G2E
- renesas,sdhi-r8a774e1 # RZ/G2H
- renesas,sdhi-r8a7795 # R-Car H3
- renesas,sdhi-r8a7796 # 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) {
dbg("the pba at %d doesn' contain boot block ID", pba);
dbg("the pba at %d doesn't contain boot block ID", pba);
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);
const char *type;
unsigned int i;
int retval = 0;
switch (card->type) {
@ -98,6 +99,17 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
card->cis.vendor, card->cis.device);
if (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);
}
/**
* 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 ret;

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

@ -376,6 +376,20 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
}
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.
* @extra: sizeof private data structure
@ -387,6 +401,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
int err;
struct mmc_host *host;
int alias_id, min_idx, max_idx;
host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
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 */
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) {
kfree(host);
return NULL;

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

@ -1168,13 +1168,13 @@ static int mmc_select_hs400(struct mmc_card *card)
return err;
}
/* Set host controller to HS timing */
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
/* Prepare host to downgrade to HS timing */
if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host);
/* Set host controller to HS timing */
mmc_set_timing(host, MMC_TIMING_MMC_HS);
/* Reduce frequency to HS frequency */
max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr);
@ -1253,6 +1253,9 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
if (err)
goto out_err;
if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host);
mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
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);
if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host);
err = mmc_switch_status(card, true);
if (err)
goto out_err;
@ -1763,13 +1763,17 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
goto free_card;
if (mmc_card_hs200(card)) {
host->doing_init_tune = 1;
err = mmc_hs200_tuning(card);
if (!err)
err = mmc_select_hs400(card);
host->doing_init_tune = 0;
if (err)
goto free_card;
err = mmc_select_hs400(card);
if (err)
goto free_card;
} else if (!mmc_card_hs400es(card)) {
/* Select the desired bus width optionally */
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,
},
{
.name = "Correct xfer_size at read (start failure)",
.name = "Proper xfer_size at read (start failure)",
.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,
},
{
.name = "Correct xfer_size at read (midway failure)",
.name = "Proper xfer_size at read (midway failure)",
.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(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[] = {
&dev_attr_vendor.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_csd.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,
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);
/* CIS vendor and device ids are available only for Combo cards */
if ((attr == &dev_attr_vendor.attr || attr == &dev_attr_device.attr) &&
card->type != MMC_TYPE_SD_COMBO)
/* 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 ||
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 attr->mode;

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

@ -29,12 +29,36 @@
MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor);
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(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[] = {
&dev_attr_vendor.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_rca.attr,
NULL,

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

@ -28,34 +28,50 @@
#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
/* show configuration fields */
#define sdio_config_attr(field, format_string) \
#define sdio_config_attr(field, format_string, args...) \
static ssize_t \
field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct sdio_func *func; \
\
func = dev_to_sdio_func (dev); \
return sprintf (buf, format_string, func->field); \
return sprintf(buf, format_string, args); \
} \
static DEVICE_ATTR_RO(field)
sdio_config_attr(class, "0x%02x\n");
sdio_config_attr(vendor, "0x%04x\n");
sdio_config_attr(device, "0x%04x\n");
sdio_config_attr(class, "0x%02x\n", func->class);
sdio_config_attr(vendor, "0x%04x\n", func->vendor);
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)
{
struct sdio_func *func = dev_to_sdio_func (dev);
#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); \
\
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",
func->class, func->vendor, func->device);
}
static DEVICE_ATTR_RO(modalias);
sdio_info_attr(1);
sdio_info_attr(2);
sdio_info_attr(3);
sdio_info_attr(4);
static struct attribute *sdio_dev_attrs[] = {
&dev_attr_class.attr,
&dev_attr_vendor.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,
NULL,
};
@ -106,6 +122,7 @@ static int
sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct sdio_func *func = dev_to_sdio_func(dev);
unsigned int i;
if (add_uevent_var(env,
"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))
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,
"MODALIAS=sdio:c%02Xv%04Xd%04X",
func->class, func->vendor, func->device))

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

@ -23,9 +23,16 @@
static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
const unsigned char *buf, unsigned size)
{
u8 major_rev, minor_rev;
unsigned i, nr_strings;
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
the TPLLV1_INFO field. Trailing garbage is ignored. */
buf += 2;
@ -57,9 +64,13 @@ static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
}
if (func) {
func->major_rev = major_rev;
func->minor_rev = minor_rev;
func->num_info = nr_strings;
func->info = (const char**)buffer;
} else {
card->major_rev = major_rev;
card->minor_rev = minor_rev;
card->num_info = nr_strings;
card->info = (const char**)buffer;
}

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

@ -178,7 +178,7 @@ config MMC_SDHCI_OF_AT91
config MMC_SDHCI_OF_ESDHC
tristate "SDHCI OF support for the Freescale eSDHC controller"
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 FSL_GUTS
help
@ -213,6 +213,18 @@ config MMC_SDHCI_OF_DWCMSHC
If you have a controller with this interface, say Y or M here.
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
tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
depends on MMC_SDHCI_PLTFM
@ -226,7 +238,7 @@ config MMC_SDHCI_CADENCE
config MMC_SDHCI_CNS3XXX
tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
depends on ARCH_CNS3XXX
depends on ARCH_CNS3XXX || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
help
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
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
select MMC_SDHCI_IO_ACCESSORS
select MMC_CQHCI
@ -264,7 +276,7 @@ config MMC_SDHCI_ESDHC_IMX
config MMC_SDHCI_DOVE
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
select MMC_SDHCI_IO_ACCESSORS
help
@ -277,7 +289,7 @@ config MMC_SDHCI_DOVE
config MMC_SDHCI_TEGRA
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
select MMC_SDHCI_IO_ACCESSORS
select MMC_CQHCI
@ -289,7 +301,8 @@ config MMC_SDHCI_TEGRA
config MMC_SDHCI_S3C
tristate "SDHCI support on Samsung S3C SoC"
depends on MMC_SDHCI && PLAT_SAMSUNG
depends on MMC_SDHCI
depends on PLAT_SAMSUNG || COMPILE_TEST
help
This selects the Secure Digital Host Controller Interface (SDHCI)
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
tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs"
depends on ARCH_SIRF
depends on ARCH_SIRF || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help
@ -339,7 +352,8 @@ config MMC_SDHCI_PXAV2
config MMC_SDHCI_SPEAR
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
help
This selects the Secure Digital Host Controller Interface (SDHCI)
@ -362,7 +376,7 @@ config MMC_SDHCI_S3C_DMA
config MMC_SDHCI_BCM_KONA
tristate "SDHCI support on Broadcom KONA platform"
depends on ARCH_BCM_MOBILE
depends on ARCH_BCM_MOBILE || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
help
This selects the Broadcom Kona Secure Digital Host Controller
@ -410,7 +424,8 @@ config MMC_SDHCI_IPROC
config MMC_MESON_GX
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
This selects support for the Amlogic SD/MMC Host Controller
found on the S905/GX*/AXG family of SoCs. This controller is
@ -446,7 +461,7 @@ config MMC_MESON_MX_SDIO
config MMC_MOXART
tristate "MOXART SD/MMC Host Controller support"
depends on ARCH_MOXART && MMC
depends on ARCH_MOXART || COMPILE_TEST
help
This selects support for the MOXART SD/MMC Host Controller.
MOXA provides one multi-functional card reader which can
@ -455,7 +470,7 @@ config MMC_MOXART
config MMC_SDHCI_ST
tristate "SDHCI support on STMicroelectronics SoC"
depends on ARCH_STI || FSP2
depends on ARCH_STI || FSP2 || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help
@ -525,7 +540,7 @@ config MMC_ATMELMCI
config MMC_SDHCI_MSM
tristate "Qualcomm SDHCI Controller Support"
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
depends on ARCH_QCOM || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
select MMC_CQHCI
@ -575,7 +590,7 @@ config MMC_TIFM_SD
config MMC_MVSDIO
tristate "Marvell MMC/SD/SDIO host driver"
depends on PLAT_ORION
depends on PLAT_ORION || (COMPILE_TEST && ARM)
depends on OF
help
This selects the Marvell SDIO host driver.
@ -587,7 +602,7 @@ config MMC_MVSDIO
config MMC_DAVINCI
tristate "TI DAVINCI Multimedia Card Interface support"
depends on ARCH_DAVINCI
depends on ARCH_DAVINCI || COMPILE_TEST
help
This selects the TI DAVINCI Multimedia card Interface.
If you have an DAVINCI board with a Multimedia Card slot,
@ -669,7 +684,7 @@ config MMC_SDRICOH_CS
config MMC_SDHCI_SPRD
tristate "Spreadtrum SDIO host Controller"
depends on ARCH_SPRD
depends on ARCH_SPRD || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
select MMC_HSQ
@ -686,7 +701,7 @@ config MMC_TMIO_CORE
config MMC_TMIO
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
help
This provides support for the SD/MMC cell found in TC6393XB,
@ -777,7 +792,7 @@ config MMC_CAVIUM_THUNDERX
config MMC_DW
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
This selects support for the Synopsys DesignWare Mobile Storage IP
block, this provides host support for SD and MMC interfaces, in both
@ -959,7 +974,7 @@ config MMC_REALTEK_USB
config MMC_SUNXI
tristate "Allwinner sunxi SD/MMC Host Controller support"
depends on ARCH_SUNXI
depends on ARCH_SUNXI || COMPILE_TEST
help
This selects support for the SD/MMC Host Controller on
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_HLWD) += sdhci-of-hlwd.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_IPROC) += sdhci-iproc.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,
.driver = {
.name = DRV_NAME_ALCOR_PCI_SDMMC,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &alcor_mmc_pm_ops
},
};

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

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

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

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

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

@ -1189,6 +1189,7 @@ static struct platform_driver au1xmmc_driver = {
.resume = au1xmmc_resume,
.driver = {
.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);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
if (ret != -EPROBE_DEFER)
dev_err(dev, "could not get clk: %d\n", ret);
ret = dev_err_probe(dev, PTR_ERR(clk), "could not get clk\n");
goto err;
}
@ -1476,6 +1474,7 @@ static struct platform_driver bcm2835_driver = {
.remove = bcm2835_remove,
.driver = {
.name = "sdhost-bcm2835",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = bcm2835_match,
},
};

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

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

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

@ -376,6 +376,9 @@ static void cqhci_off(struct mmc_host *mmc)
else
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;
}
@ -580,6 +583,9 @@ static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
__cqhci_enable(cq_host);
if (!mmc->cqe_on) {
if (cq_host->ops->pre_enable)
cq_host->ops->pre_enable(mmc);
cqhci_writel(cq_host, 0, CQHCI_CTL);
mmc->cqe_on = true;
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 (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq,
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)

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

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

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

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

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

@ -200,6 +200,7 @@ static struct platform_driver dw_mci_hi3798cv200_driver = {
.remove = dw_mci_hi3798cv200_remove,
.driver = {
.name = "dwmmc_hi3798cv200",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.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,
.driver = {
.name = "dwmmc_k3",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_k3_match,
.pm = &dw_mci_k3_dev_pm_ops,
},

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

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

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

@ -383,6 +383,7 @@ static struct platform_driver dw_mci_rockchip_pltfm_driver = {
.remove = dw_mci_rockchip_remove,
.driver = {
.name = "dwmmc_rockchip",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_rockchip_match,
.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 dw_mci_zx_priv_data *priv;
struct regmap *sysc_base;
int ret;
/* syscon is needed only by emmc */
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);
of_node_put(node);
if (IS_ERR(sysc_base)) {
ret = PTR_ERR(sysc_base);
if (ret != -EPROBE_DEFER)
dev_err(host->dev, "Can't get syscon: %d\n",
ret);
return ret;
}
if (IS_ERR(sysc_base))
return dev_err_probe(host->dev, PTR_ERR(sysc_base),
"Can't get syscon\n");
} else {
return 0;
}
@ -227,6 +222,7 @@ static struct platform_driver dw_mci_zx_pltfm_driver = {
.remove = dw_mci_pltfm_remove,
.driver = {
.name = "dwmmc_zx",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = dw_mci_zx_match,
.pm = &dw_mci_zx_dev_pm_ops,
},

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

@ -3161,12 +3161,9 @@ int dw_mci_probe(struct dw_mci *host)
if (!host->pdata) {
host->pdata = dw_mci_parse_dt(host);
if (PTR_ERR(host->pdata) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
} else if (IS_ERR(host->pdata)) {
dev_err(host->dev, "platform data not available\n");
return -EINVAL;
}
if (IS_ERR(host->pdata))
return dev_err_probe(host->dev, PTR_ERR(host->pdata),
"platform data not available\n");
}
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);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"could not parse device properties: %d\n", ret);
dev_err_probe(&pdev->dev, ret, "could not parse device properties\n");
goto err_free_host;
}
@ -1126,6 +1124,7 @@ static struct platform_driver jz4740_mmc_driver = {
.remove = jz4740_mmc_remove,
.driver = {
.name = "jz4740-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(jz4740_mmc_of_match),
.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);
clk = devm_clk_get(host->dev, name);
if (IS_ERR(clk)) {
if (clk != ERR_PTR(-EPROBE_DEFER))
dev_err(host->dev, "Missing clock %s\n", name);
return PTR_ERR(clk);
}
if (IS_ERR(clk))
return dev_err_probe(host->dev, PTR_ERR(clk),
"Missing clock %s\n", name);
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;
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;
else
dly = 0;
@ -1077,12 +1075,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
}
ret = device_reset_optional(&pdev->dev);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "device reset failed: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(&pdev->dev, ret, "device reset failed\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->regs = devm_ioremap_resource(&pdev->dev, res);
@ -1270,6 +1264,7 @@ static struct platform_driver meson_mmc_driver = {
.remove = meson_mmc_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.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,
.driver = {
.name = "meson-mx-sdhc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.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,
.driver = {
.name = "meson-mx-sdio",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.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
clock_rate = spi->max_speed_hz;
timeout = data->timeout_ns +
timeout = data->timeout_ns / 1000 +
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
* each 512-byte block

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

@ -689,19 +689,18 @@ static int moxart_remove(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, NULL);
if (mmc) {
if (!IS_ERR(host->dma_chan_tx))
dma_release_channel(host->dma_chan_tx);
if (!IS_ERR(host->dma_chan_rx))
dma_release_channel(host->dma_chan_rx);
mmc_remove_host(mmc);
mmc_free_host(mmc);
if (!IS_ERR(host->dma_chan_tx))
dma_release_channel(host->dma_chan_tx);
if (!IS_ERR(host->dma_chan_rx))
dma_release_channel(host->dma_chan_rx);
mmc_remove_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;
}
@ -717,6 +716,7 @@ static struct platform_driver moxart_mmc_driver = {
.remove = moxart_remove,
.driver = {
.name = "mmc-moxart",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = moxart_mmc_match,
},
};

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

@ -397,7 +397,6 @@ struct msdc_delay_phase {
struct msdc_host {
struct device *dev;
const struct mtk_mmc_compatible *dev_comp;
struct mmc_host *mmc; /* mmc structure */
int cmd_rsp;
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)
{
struct mmc_host *mmc = mmc_from_priv(host);
u64 timeout, clk_ns;
u32 mode = 0;
if (host->mmc->actual_clock == 0) {
if (mmc->actual_clock == 0) {
timeout = 0;
} else {
clk_ns = 1000000000ULL;
do_div(clk_ns, host->mmc->actual_clock);
do_div(clk_ns, mmc->actual_clock);
timeout = ns + clk_ns - 1;
do_div(timeout, clk_ns);
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)
{
struct mmc_host *mmc = mmc_from_priv(host);
u32 mode;
u32 flags;
u32 div;
@ -811,7 +812,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
if (!hz) {
dev_dbg(host->dev, "set mclk to 0\n");
host->mclk = 0;
host->mmc->actual_clock = 0;
mmc->actual_clock = 0;
sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
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))
cpu_relax();
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
host->mmc->actual_clock = sclk;
mmc->actual_clock = sclk;
host->mclk = hz;
host->timing = timing;
/* 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,
* 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);
if (host->top_base) {
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,
MSDC_PAD_TUNE_CMDRRDLY,
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);
}
@ -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,
struct mmc_request *mrq, struct mmc_command *cmd)
{
struct mmc_host *mmc = mmc_from_priv(host);
/* rawcmd :
* vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 |
* 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;
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))
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)
{
struct mmc_host *mmc = mmc_from_priv(host);
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);
if (reg_inten & MSDC_INTEN_SDIOIRQ) {
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 ||
reg_ps & MSDC_PS_DATA1)) {
__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);
if (host->error)
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)
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)
{
struct mmc_host *mmc = mmc_from_priv(host);
int cmd_err = 0, dat_err = 0;
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);
}
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)
{
struct msdc_host *host = (struct msdc_host *) dev_id;
struct mmc_host *mmc = mmc_from_priv(host);
while (true) {
unsigned long flags;
@ -1551,18 +1556,18 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
spin_unlock_irqrestore(&host->lock, flags);
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
sdio_signal_irq(host->mmc);
sdio_signal_irq(mmc);
if ((events & event_mask) & MSDC_INT_CDSC) {
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;
}
if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
break;
if ((host->mmc->caps2 & MMC_CAP2_CQE) &&
if ((mmc->caps2 & MMC_CAP2_CQE) &&
(events & MSDC_INT_CMDQ)) {
msdc_cmdq_irq(host, events);
/* 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 = {
.post_req = msdc_post_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 = {
.enable = msdc_cqe_enable,
.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,
@ -2434,7 +2461,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
host->dev = &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);
/* Set host parameters to mmc */
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;
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),
GFP_KERNEL);
if (!host->cq_host) {
@ -2560,7 +2586,7 @@ static int msdc_drv_remove(struct platform_device *pdev)
pm_runtime_get_sync(host->dev);
platform_set_drvdata(pdev, NULL);
mmc_remove_host(host->mmc);
mmc_remove_host(mmc);
msdc_deinit_hw(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),
host->dma.bd, host->dma.bd_addr);
mmc_free_host(host->mmc);
mmc_free_host(mmc);
return 0;
}
@ -2607,6 +2633,7 @@ static void msdc_save_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;
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);
}
if (sdio_irq_claimed(host->mmc))
if (sdio_irq_claimed(mmc))
__msdc_enable_sdio_irq(host, 1);
}
@ -2667,6 +2694,7 @@ static struct platform_driver mt_msdc_driver = {
.remove = msdc_drv_remove,
.driver = {
.name = "mtk-msdc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = msdc_of_ids,
.pm = &msdc_dev_pm_ops,
},

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

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

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

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

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

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

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

@ -1504,6 +1504,7 @@ static struct platform_driver mmc_omap_driver = {
.remove = mmc_omap_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.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;
/* Disable the clocks */
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
clk_disable_unprepare(host->dbclk);
/* Turn the power off */
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 */
if (!ret)
ret = omap_hsmmc_set_power(host, 1);
if (host->dbclk)
clk_prepare_enable(host->dbclk);
clk_prepare_enable(host->dbclk);
if (ret != 0)
goto err;
@ -2014,8 +2012,7 @@ err_irq:
pm_runtime_dont_use_autosuspend(host->dev);
pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev);
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
clk_disable_unprepare(host->dbclk);
err1:
mmc_free_host(mmc);
err:
@ -2037,8 +2034,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev);
device_init_wakeup(&pdev->dev, false);
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
clk_disable_unprepare(host->dbclk);
mmc_free_host(host->mmc);
@ -2063,8 +2059,7 @@ static int omap_hsmmc_suspend(struct device *dev)
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);
return 0;
@ -2080,8 +2075,7 @@ static int omap_hsmmc_resume(struct device *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))
omap_hsmmc_conf_bus_power(host);
@ -2171,6 +2165,7 @@ static struct platform_driver omap_hsmmc_driver = {
.remove = omap_hsmmc_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &omap_hsmmc_dev_pm_ops,
.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 = {
.driver = {
.name = "owl_mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = owl_mmc_of_match,
},
.probe = owl_mmc_probe,

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

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

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

@ -33,10 +33,13 @@ struct renesas_sdhi_of_data {
unsigned short max_segs;
};
#define SDHI_CALIB_TABLE_MAX 32
struct renesas_sdhi_quirks {
bool hs400_disabled;
bool hs400_4taps;
u32 hs400_bad_taps;
const u8 (*hs400_calib_table)[SDHI_CALIB_TABLE_MAX];
};
struct tmio_mmc_dma {
@ -58,7 +61,8 @@ struct renesas_sdhi {
void __iomem *scc_ctl;
u32 scc_tappos;
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 */
DECLARE_BITMAP(taps, BITS_PER_LONG);

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

@ -26,6 +26,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/mfd/tmio.h>
#include <linux/sh_dma.h>
@ -47,6 +48,8 @@
#define SDHI_VER_GEN3_SD 0xcc10
#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)
{
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;
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);
/*
@ -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_SMPCMP 0x00C
#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_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_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,
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_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,
@ -403,6 +452,74 @@ static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
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,
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) &
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_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;
}
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
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 long *bitmap;
priv->doing_tune = false;
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;
}
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);
int i;
int i, ret;
priv->tap_num = renesas_sdhi_init_tuning(host);
if (!priv->tap_num)
@ -515,7 +666,6 @@ static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode)
return -EINVAL;
}
priv->doing_tune = true;
bitmap_zero(priv->taps, 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 */
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);
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) == 0)
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)
@ -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))
return false;
if (mmc_doing_retune(host->mmc) || priv->doing_tune)
if (mmc_doing_tune(host->mmc))
return false;
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);
}
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)
{
int timeout = 1000;
@ -711,6 +843,13 @@ static int renesas_sdhi_multi_io_quirk(struct mmc_card *card,
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)
{
/* 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),
};
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.
* 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 = "ES3.*", .data = &sdhi_quirks_bad_taps2367 },
{ .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 = "r8a77965", .data = &sdhi_quirks_bad_taps2367 },
{ .soc_id = "r8a77965", .data = &sdhi_quirks_r8a77965 },
{ .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 },
{ .soc_id = "r8a77990", .data = &sdhi_quirks_r8a77990 },
{ /* Sentinel. */ },
};
@ -862,11 +1017,11 @@ int renesas_sdhi_probe(struct platform_device *pdev,
renesas_sdhi_start_signal_voltage_switch;
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) {
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->hw_reset = renesas_sdhi_hw_reset;
}
}
@ -915,6 +1070,14 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (ver == SDHI_VER_GEN2_SDR50)
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);
if (ret < 0)
goto edisclk;
@ -943,8 +1106,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (!hit)
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->ops.execute_tuning = renesas_sdhi_execute_tuning;
host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning;
host->ops.hs400_downgrade = renesas_sdhi_disable_scc;
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)
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 */
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 = {
.driver = {
.name = "renesas_sdhi_internal_dmac",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &renesas_sdhi_internal_dmac_dev_pm_ops,
.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 = {
.driver = {
.name = "sh_mobile_sdhi",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &renesas_sdhi_sys_dmac_dev_pm_ops,
.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,
.driver = {
.name = DRV_NAME_RTSX_PCI_SDMMC,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
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)
{
struct rtsx_ucr *ucr = host->ucr;
int err;
dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n",
__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, SD_CFG1, SD_ASYNC_FIFO_RST, 0);
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (err)
return err;
return 0;
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
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,
.driver = {
.name = "rtsx_usb_sdmmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.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)
{
u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize;
u32 datcon, datcnt, datsta, fsta, imask;
u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer;
u32 datcon, datcnt, datsta, fsta;
con = readl(host->base + S3C2410_SDICON);
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);
r3 = readl(host->base + S3C2410_SDIRSP3);
timer = readl(host->base + S3C2410_SDITIMER);
bsize = readl(host->base + S3C2410_SDIBSIZE);
datcon = readl(host->base + S3C2410_SDIDCON);
datcnt = readl(host->base + S3C2410_SDIDCNT);
datsta = readl(host->base + S3C2410_SDIDSTA);
fsta = readl(host->base + S3C2410_SDIFSTA);
imask = readl(host->base + host->sdiimsk);
dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n",
prefix, con, pre, timer);
@ -396,9 +394,6 @@ static void s3cmci_enable_irq(struct s3cmci_host *host, bool more)
local_irq_restore(flags);
}
/**
*
*/
static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer)
{
unsigned long flags;
@ -1379,7 +1374,7 @@ static int s3cmci_state_show(struct seq_file *seq, void *v)
{
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, "Prescale = %d\n", host->prescaler);
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;
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);
if (ret)
@ -1809,6 +1804,7 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids);
static struct platform_driver s3cmci_driver = {
.driver = {
.name = "s3c-sdi",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = s3cmci_dt_match,
},
.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->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.set_ios = amd_set_ios;
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 = {
.driver = {
.name = "sdhci-acpi",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.acpi_match_table = sdhci_acpi_ids,
.pm = &sdhci_acpi_pm_ops,
},

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

@ -324,6 +324,7 @@ err_pltfm_free:
static struct platform_driver sdhci_bcm_kona_driver = {
.driver = {
.name = "sdhci-kona",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops,
.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);
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
if (PTR_ERR(clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "Clock not found in Device Tree\n");
clk = NULL;
}
clk = devm_clk_get_optional(&pdev->dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
"Failed to get clock from Device Tree\n");
res = clk_prepare_enable(clk);
if (res)
return res;
@ -328,6 +326,7 @@ MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
static struct platform_driver sdhci_brcmstb_driver = {
.driver = {
.name = "sdhci-brcmstb",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops,
.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 = {
.driver = {
.name = "sdhci-cdns",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_cdns_pm_ops,
.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 = {
.driver = {
.name = "sdhci-cns3xxx",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_cns3xxx_probe,

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

@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table);
static struct platform_driver sdhci_dove_driver = {
.driver = {
.name = "sdhci-dove",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops,
.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)
{
u32 reg;
u8 sw_rst;
int ret;
/* FIXME: delay a bit for card to be ready for next tuning due to errors */
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 |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_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
* 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);
} 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;
imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(imx_data->pinctrl)) {
err = PTR_ERR(imx_data->pinctrl);
if (IS_ERR(imx_data->pinctrl))
dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n");
}
if (esdhc_is_usdhc(imx_data)) {
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 = {
.driver = {
.name = "sdhci-esdhc-imx",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = imx_esdhc_dt_ids,
.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 = {
.driver = {
.name = "sdhci-esdhc-mcf",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = sdhci_esdhc_mcf_probe,
.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 = {
.pdata = &sdhci_bcm2711_pltfm_data,
.mmc_caps = MMC_CAP_3_3V_DDR,
};
static const struct of_device_id sdhci_iproc_of_match[] = {
@ -368,6 +369,7 @@ err:
static struct platform_driver sdhci_iproc_driver = {
.driver = {
.name = "sdhci-iproc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_iproc_of_match,
.acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids),
.pm = &sdhci_pltfm_pmops,

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

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

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

@ -263,7 +263,6 @@ struct sdhci_msm_host {
unsigned long clk_rate;
struct mmc_host *mmc;
struct opp_table *opp_table;
bool has_opp_table;
bool use_14lpp_dll_reset;
bool tuning_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,sdm845-sdhci", .data = &sdm845_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 */
ret = dev_pm_opp_of_add_table(&pdev->dev);
if (!ret) {
msm_host->has_opp_table = true;
} else if (ret != -ENODEV) {
if (ret && ret != -ENODEV) {
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 */
@ -2469,8 +2467,8 @@ clk_disable:
clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
msm_host->bulk_clks);
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);
bus_clk_disable:
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);
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);
pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@ -2557,6 +2554,7 @@ static struct platform_driver sdhci_msm_driver = {
.name = "sdhci_msm",
.of_match_table = sdhci_msm_dt_match,
.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);
if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
ret = PTR_ERR(sdhci_arasan->soc_ctl_base);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Can't get syscon: %d\n",
ret);
ret = dev_err_probe(&pdev->dev,
PTR_ERR(sdhci_arasan->soc_ctl_base),
"Can't get syscon\n");
goto err_pltfm_free;
}
}
@ -1694,6 +1693,7 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
static struct platform_driver sdhci_arasan_driver = {
.driver = {
.name = "sdhci-arasan",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_arasan_of_match,
.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 = {
.driver = {
.name = "sdhci-aspeed",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = aspeed_sdhci_of_match,
},
.probe = aspeed_sdhci_probe,
@ -318,6 +319,7 @@ MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match);
static struct platform_driver aspeed_sdc_driver = {
.driver = {
.name = "sd-controller-aspeed",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops,
.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 = {
.driver = {
.name = "sdhci-at91",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_at91_dt_match,
.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 = {
.driver = {
.name = "sdhci-dwcmshc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_dwcmshc_dt_ids,
.pm = &dwcmshc_pmops,
},

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

@ -1360,13 +1360,19 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
clk_put(clk);
}
if (esdhc->peripheral_clock) {
esdhc_clock_enable(host, false);
val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
esdhc_clock_enable(host, false);
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;
sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
esdhc_clock_enable(host, true);
}
else
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)
@ -1468,6 +1474,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
static struct platform_driver sdhci_esdhc_driver = {
.driver = {
.name = "sdhci-esdhc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_esdhc_of_match,
.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 = {
.driver = {
.name = "sdhci-hlwd",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_hlwd_of_match,
.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,
.driver = {
.name = "sdhci-omap",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_omap_dev_pm_ops,
.of_match_table = omap_sdhci_match,
},

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

@ -24,6 +24,8 @@
#include <linux/iopoll.h>
#include <linux/gpio.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/debugfs.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/mmc/sdhci-pci-data.h>
#include <linux/acpi.h>
@ -516,6 +518,8 @@ struct intel_host {
bool rpm_retune_ok;
u32 glk_rx_ctrl1;
u32 glk_tun_val;
u32 active_ltr;
u32 idle_ltr;
};
static const guid_t intel_dsm_guid =
@ -760,6 +764,108 @@ static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode)
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)
{
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;
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)
@ -855,6 +998,8 @@ static int glk_emmc_add_host(struct sdhci_pci_slot *slot)
if (ret)
goto cleanup;
byt_add_debugfs(slot);
return 0;
cleanup:
@ -1032,6 +1177,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
#endif
.allow_runtime_pm = true,
.probe_slot = byt_emmc_probe_slot,
.add_host = byt_add_host,
.remove_slot = byt_remove_slot,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
SDHCI_QUIRK_NO_LED,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
@ -1045,6 +1192,7 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
.allow_runtime_pm = true,
.probe_slot = glk_emmc_probe_slot,
.add_host = glk_emmc_add_host,
.remove_slot = byt_remove_slot,
#ifdef CONFIG_PM_SLEEP
.suspend = sdhci_cqhci_suspend,
.resume = sdhci_cqhci_resume,
@ -1075,6 +1223,8 @@ static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.allow_runtime_pm = true,
.probe_slot = ni_byt_sdio_probe_slot,
.add_host = byt_add_host,
.remove_slot = byt_remove_slot,
.ops = &sdhci_intel_byt_ops,
.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,
.allow_runtime_pm = true,
.probe_slot = byt_sdio_probe_slot,
.add_host = byt_add_host,
.remove_slot = byt_remove_slot,
.ops = &sdhci_intel_byt_ops,
.priv_size = sizeof(struct intel_host),
};
@ -1111,6 +1263,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
.allow_runtime_pm = true,
.own_cd_for_runtime_pm = true,
.probe_slot = byt_sd_probe_slot,
.add_host = byt_add_host,
.remove_slot = byt_remove_slot,
.ops = &sdhci_intel_byt_ops,
.priv_size = sizeof(struct intel_host),
};

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

@ -14,6 +14,7 @@
#include <linux/delay.h>
#include "sdhci.h"
#include "sdhci-pci.h"
#include "cqhci.h"
/* Genesys Logic extra registers */
#define SDHCI_GLI_9750_WT 0x800
@ -81,9 +82,16 @@
#define GLI_9763E_VHS_REV_R 0x0
#define GLI_9763E_VHS_REV_M 0x1
#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 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_EN BIT(0)
#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);
}
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
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);
}
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)
{
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)
{
struct pci_dev *pdev = slot->chip->pdev;
struct sdhci_host *host = slot->host;
u32 value;
host->mmc->caps |= MMC_CAP_8_BIT_DATA |
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_NO_SDIO |
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);
host->mmc_host_ops.hs400_enhanced_strobe =
gl9763e_hs400_enhanced_strobe;
@ -699,9 +842,10 @@ static const struct sdhci_ops sdhci_gl9763e_ops = {
.set_clock = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.reset = sdhci_gl9763e_reset,
.set_uhs_signaling = sdhci_set_gl9763e_signaling,
.voltage_switch = sdhci_gli_voltage_switch,
.irq = sdhci_gl9763e_cqhci_irq,
};
const struct sdhci_pci_fixes sdhci_gl9763e = {
@ -709,6 +853,8 @@ const struct sdhci_pci_fixes sdhci_gl9763e = {
.probe_slot = gli_probe_slot_gl9763e,
.ops = &sdhci_gl9763e_ops,
#ifdef CONFIG_PM_SLEEP
.resume = sdhci_pci_gli_resume,
.resume = sdhci_cqhci_gli_resume,
.suspend = sdhci_cqhci_gli_suspend,
#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 = {
.driver = {
.name = "pic32-sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(pic32_sdhci_id_table),
},
.probe = pic32_sdhci_probe,

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

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

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

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

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

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

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

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

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

@ -181,6 +181,7 @@ MODULE_DEVICE_TABLE(of, sdhci_spear_id_table);
static struct platform_driver sdhci_driver = {
.driver = {
.name = "sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pm_ops,
.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))
return;
mmc_request_done(host->mmc, mrq);
mmc_request_done(host->mmc, mrq);
}
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,
struct mmc_request *mrq)
struct mmc_request *mrq)
{
sdhci_sprd_check_auto_cmd23(mmc, mrq);
@ -787,6 +787,7 @@ static struct platform_driver sdhci_sprd_driver = {
.remove = sdhci_sprd_remove,
.driver = {
.name = "sdhci_sprd_r11",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(sdhci_sprd_of_match),
.pm = &sdhci_sprd_pm_ops,
},

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

@ -521,6 +521,7 @@ static struct platform_driver sdhci_st_driver = {
.remove = sdhci_st_remove,
.driver = {
.name = "sdhci-st",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_st_pmops,
.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);
if (IS_ERR(clk)) {
rc = PTR_ERR(clk);
if (rc != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to get clock: %d\n", rc);
rc = dev_err_probe(&pdev->dev, PTR_ERR(clk),
"failed to get clock\n");
goto err_clk_get;
}
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 = {
.driver = {
.name = "sdhci-tegra",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_tegra_dt_match,
.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 = {
.driver = {
.name = "xenon-sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_xenon_dt_ids,
.pm = &sdhci_xenon_dev_pm_ops,
},

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

@ -2,10 +2,11 @@
/*
* 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/iopoll.h>
#include <linux/of.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
@ -18,9 +19,11 @@
/* CTL_CFG Registers */
#define CTL_CFG_2 0x14
#define CTL_CFG_3 0x18
#define SLOTTYPE_MASK GENMASK(31, 30)
#define SLOTTYPE_EMBEDDED BIT(30)
#define TUNINGFORSDR50_MASK BIT(13)
/* PHY Registers */
#define PHY_CTRL1 0x100
@ -65,6 +68,14 @@
#define RETRIM_MASK BIT(RETRIM_SHIFT)
#define SELDLYTXCLK_SHIFT 17
#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_33_OHM 0x1
@ -72,7 +83,7 @@
#define DRIVER_STRENGTH_100_OHM 0x3
#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 */
#define SDHCI_AM654_CQE_BASE_ADDR 0x200
@ -84,14 +95,56 @@ static struct regmap_config sdhci_am654_regmap_config = {
.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 regmap *base;
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 trm_icp;
int drv_strength;
bool dll_on;
int strb_sel;
u32 flags;
};
@ -106,26 +159,6 @@ struct sdhci_am654_driver_data {
#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)
{
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;
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) {
switch (clock) {
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");
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)
@ -201,11 +262,7 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
u32 otap_del_ena;
u32 mask, val;
if (sdhci_am654->dll_on) {
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
sdhci_am654->dll_on = false;
}
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
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);
if (timing > MMC_TIMING_UHS_SDR25 && clock > CLOCK_TOO_SLOW_HZ) {
regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
SELDLYTXCLK_MASK, 0);
if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ)
sdhci_am654_setup_dll(host, clock);
} else {
regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
SELDLYTXCLK_MASK, 1 << SELDLYTXCLK_SHIFT);
}
else
sdhci_am654_setup_delay_chain(sdhci_am654, timing);
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
sdhci_am654->clkbuf_sel);
@ -272,9 +325,19 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
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)
{
unsigned char timing = host->mmc->ios.timing;
u8 pwr;
int ret;
if (reg == SDHCI_HOST_CONTROL) {
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);
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)
@ -322,7 +398,46 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask)
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 = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.set_uhs_signaling = sdhci_set_uhs_signaling,
@ -352,6 +467,7 @@ static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
};
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_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.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 = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.set_uhs_signaling = sdhci_set_uhs_signaling,
@ -445,7 +562,7 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
int i;
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]);
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++) {
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]);
if (ret) {
dev_dbg(dev, "Couldn't find %s\n",
td[i].binding);
td[i].otap_binding);
/*
* Remove the corresponding capability
* 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
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;
@ -527,6 +648,10 @@ static int sdhci_am654_init(struct sdhci_host *host)
regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK,
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);
if (ret)
return ret;
@ -614,6 +739,7 @@ static const struct of_device_id sdhci_am654_of_match[] = {
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdhci_am654_of_match);
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 = {
.driver = {
.name = "sdhci-am654",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_am654_of_match,
},
.probe = sdhci_am654_probe,

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

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

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

@ -1562,6 +1562,7 @@ static struct platform_driver sh_mmcif_driver = {
.remove = sh_mmcif_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sh_mmcif_dev_pm_ops,
.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 = {
.driver = {
.name = "sunxi-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(sunxi_mmc_of_match),
.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)
{
/* FIXME - should we set stop clock reg here */
sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
usleep_range(10000, 11000);
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
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
@ -221,6 +213,7 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
static struct platform_driver tmio_mmc_driver = {
.driver = {
.name = "tmio-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &tmio_mmc_dev_pm_ops,
},
.probe = tmio_mmc_probe,

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

@ -178,14 +178,8 @@ struct tmio_mmc_host {
unsigned int direction, int blk_size);
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
void (*reset)(struct tmio_mmc_host *host);
void (*hw_reset)(struct tmio_mmc_host *host);
bool (*check_retune)(struct tmio_mmc_host *host);
/*
* 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 (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq);
void (*prepare_hs400_tuning)(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);
usleep_range(10000, 11000);
if (host->reset)
host->reset(host);
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);
}
}
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)
{
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);
tmio_mmc_hw_reset(host->mmc);
tmio_mmc_reset(host);
/* Ready for new calls */
host->mrq = NULL;
tmio_mmc_abort_dma(host);
mmc_request_done(host->mmc, mrq);
}
@ -720,24 +712,6 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
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,
struct mmc_request *mrq)
{
@ -835,6 +809,9 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
return;
}
if (host->fixup_request)
host->fixup_request(host, 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,
.enable_sdio_irq = tmio_mmc_enable_sdio_irq,
.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)
@ -1156,9 +1131,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
mmc->caps & MMC_CAP_NEEDS_POLL ||
!mmc_card_is_removable(mmc));
if (!_host->reset)
_host->reset = tmio_mmc_reset;
/*
* On Gen2+, eMMC with NONREMOVABLE currently fails because native
* 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->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);
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);
tmio_mmc_clk_enable(host);
tmio_mmc_hw_reset(host->mmc);
tmio_mmc_reset(host);
if (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);
}
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);
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);
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) {
@ -684,6 +685,7 @@ static struct platform_driver uniphier_sd_driver = {
.remove = uniphier_sd_remove,
.driver = {
.name = "uniphier-sd",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = uniphier_sd_match,
},
};

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

@ -1890,6 +1890,7 @@ static struct platform_driver usdhi6_driver = {
.remove = usdhi6_remove,
.driver = {
.name = "usdhi6rol0",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.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)
{
struct via_crdr_mmc_host *host;
unsigned long flags;
host = dev_get_drvdata(dev);
spin_lock_irqsave(&host->lock, flags);
via_save_pcictrlreg(host);
via_save_sdcreg(host);
spin_unlock_irqrestore(&host->lock, flags);
device_wakeup_enable(dev);

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