MMC core:

- A few minor improvements and cleanups
 
 MMC host:
  - Remove some redundant calls to local_irq_{save,restore}()
  - Replace kmap_atomic() with kmap_local_page()
  - Take return values from mmc_add_host() into account
  - dw_mmc-pltfm: Add support to configure clk-phase for socfpga
  - hsq: Minimize latency by using a fifo to dispatch requests
  - litex_mmc: Fixup corner case for polling mode
  - mtk-sd: Add inline crypto engine clock control
  - mtk-sd: Add support for the mediatek MT7986 variant
  - renesas_sdhi: Improve reset from HS400 mode
  - renesas_sdhi: Take DMA end interrupts into account
  - sdhci: Avoid unnecessary update of clock
  - sdhci: Fix an SD tuning issue
  - sdhci-brcmst: Add Kamal Dasu as maintainer for the Broadcom driver
  - sdhci-esdhc-imx: Improve tuning logic
  - sdhci-esdhc-imx: Improve support for the imxrt1050 variant
  - sdhci_f_sdh30: Add support for non-removable media
  - sdhci_f_sdh30: Add support for the Socionext F_SDH30_E51 variant
  - sdhci_f_sdh30: Add reset control support
  - sdhci-msm: Add support for the Qcom SM8550/SM8350/SM6375 variants
  - sdhci-msm: Add support for the Qcom MSM8976 variant
  - sdhci-of-arasan: Add support for dynamic configuration
  - sdhci-of-esdhc: Limit the clock frequency to confirm to spec
  - sdhci-pci: Enable asynchronous probe
  - sdhci-sprd: Improve card detection
  - sdhci-tegra: Improve reset support
  - sdhci-tegra: Add support to program MC stream ID
  - sunplus-mmc: Add new mmc driver for the Sunplus SP7021 controller
  - vub300: Fix warning splat for SDIO irq
 
 MEMSTICK core:
  - memstick: A few minor improvements and cleanups
 
 CLK/IOMMU:
  - clk: socfpga: Drop redundant support for clk-phase for the SD/MMC clk
  - iommu: Add tegra specific helper to get stream_id
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmOYUeUXHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCnUmA//cdC4gF86ROp+d2lKZVHn9FVK
 jgF0NJ9DZiDOZm7qta7rqmAGo/Xq9sacHq65qGjXMeei/MNrwu7xW/U3Ihk0pK9z
 Gnphck3JgbkLJ6ijxsuBqNavsYjXJVqys3f2qThXYh+xXyLAfIvOtPj9984EfdvR
 AtZuTwpvebNxB6Qu6SFIYZ4Yt4ZaTN/AuCRyjS9HHNLugjbgditZQcw6wjqlTRb7
 fhSNwK3srWGzdthtiiXBoFSjjpd7AESGPjqaGDJNgIDYxFXOUX2vx2eb15s1beVN
 i7pN8D83StNjF+PF551trUyNCaW4Ukbl7hHTqC9sFvjgtRFVB97oSoxm7F03fsX3
 bM6USXtG1xOGkPG9Dqneuhee157UCgNIWs46H/CuZYmGgBN6I7l0Jt3+Lru5IwwQ
 NstKcLS6xaWyYOEAoAR5yFDJXBagxEXNArtHkzoLabvcsk0XPdGAMd87RUuyGgXt
 Vpd4VjH1VSDcaG7DF3+XR3uTy5mUAOrehBrVr1eKH7gYRpr4TLlYgE/a3AkSs/m+
 3ftM3o6hraHKqwY32vDG9vSsuLrGdh286rEypmc1gmejiNTz+SFSIex1YoefWtx2
 O0u+7plcauuUX+7EQ79RzZkB/FS40uL3wxAii7Ta+on4P7Cwuh6jo1Hakvy5JjtW
 5733RKV5nkKUkKMOwsU=
 =nstz
 -----END PGP SIGNATURE-----

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

Pull MMC and MEMSTICK updates from Ulf Hansson:
 "MMC core:
   - A few minor improvements and cleanups

  MMC host:
   - Remove some redundant calls to local_irq_{save,restore}()
   - Replace kmap_atomic() with kmap_local_page()
   - Take return values from mmc_add_host() into account
   - dw_mmc-pltfm: Add support to configure clk-phase for socfpga
   - hsq: Minimize latency by using a fifo to dispatch requests
   - litex_mmc: Fixup corner case for polling mode
   - mtk-sd: Add inline crypto engine clock control
   - mtk-sd: Add support for the mediatek MT7986 variant
   - renesas_sdhi: Improve reset from HS400 mode
   - renesas_sdhi: Take DMA end interrupts into account
   - sdhci: Avoid unnecessary update of clock
   - sdhci: Fix an SD tuning issue
   - sdhci-brcmst: Add Kamal Dasu as maintainer for the Broadcom driver
   - sdhci-esdhc-imx: Improve tuning logic
   - sdhci-esdhc-imx: Improve support for the imxrt1050 variant
   - sdhci_f_sdh30: Add support for non-removable media
   - sdhci_f_sdh30: Add support for the Socionext F_SDH30_E51 variant
   - sdhci_f_sdh30: Add reset control support
   - sdhci-msm: Add support for the Qcom SM8550/SM8350/SM6375 variants
   - sdhci-msm: Add support for the Qcom MSM8976 variant
   - sdhci-of-arasan: Add support for dynamic configuration
   - sdhci-of-esdhc: Limit the clock frequency to confirm to spec
   - sdhci-pci: Enable asynchronous probe
   - sdhci-sprd: Improve card detection
   - sdhci-tegra: Improve reset support
   - sdhci-tegra: Add support to program MC stream ID
   - sunplus-mmc: Add new mmc driver for the Sunplus SP7021 controller
   - vub300: Fix warning splat for SDIO irq

  MEMSTICK core:
   - memstick: A few minor improvements and cleanups

  CLK/IOMMU:
   - clk: socfpga: Drop redundant support for clk-phase for the SD/MMC clk
   - iommu: Add tegra specific helper to get stream_id"

* tag 'mmc-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (108 commits)
  mmc: sdhci-sprd: Disable CLK_AUTO when the clock is less than 400K
  mmc: sdhci-of-esdhc: Modify mismatched function name
  memstick/mspro_block: Convert to use sysfs_emit()/sysfs_emit_at() APIs
  mmc: sdhci-tegra: Issue CMD and DAT resets together
  mmc: sdhci-tegra: Add support to program MC stream ID
  mmc: sdhci-tegra: Separate Tegra194 and Tegra234 SoC data
  mmc: sdhci-tegra: Sort includes alphabetically
  iommu/tegra: Add tegra_dev_iommu_get_stream_id() helper
  iommu: Add note about struct iommu_fwspec usage
  mmc: sdhci-brcmstb: Resolve "unused" warnings with CONFIG_OF=n
  dt-bindings: mmc: sdhci-msm: allow dma-coherent
  dt-bindings: mmc: sdhci-msm: drop properties mentioned in common MMC
  dt-bindings: mmc: sdhci-msm: cleanup style
  dt-bindings: mmc: sdhci-am654: cleanup style
  dt-bindings: mmc: sdhci: document sdhci-caps and sdhci-caps-mask
  mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING
  MAINTAINERS: Update maintainer for SDHCI Broadcom BRCMSTB driver
  mmc: sdhci-of-esdhc: limit the SDHC clock frequency
  mmc: sdhci: Remove unneeded semicolon
  mmc: core: Normalize the error handling branch in sd_read_ext_regs()
  ...
This commit is contained in:
Linus Torvalds 2022-12-13 13:41:26 -08:00
commit 71946a25f3
82 changed files with 2119 additions and 730 deletions

View File

@ -95,7 +95,9 @@ properties:
PIO (polled I/O) interrupt and occurs when the FIFO needs to be
emptied as part of a bulk read from the card. Some variants have these
two interrupts wired into the same line (logic OR) and in that case
only one interrupt may be provided.
only one interrupt may be provided. The interrupt-names property is
not used due to inconsistency of existing DTs regarding its content.
deprecated: false
minItems: 1
maxItems: 2

View File

@ -50,11 +50,11 @@ properties:
- const: fsl,imx8mm-usdhc
- items:
- enum:
- fsl,imx8dxl-usdhc
- fsl,imx8qm-usdhc
- const: fsl,imx8qxp-usdhc
- items:
- enum:
- fsl,imx8dxl-usdhc
- fsl,imx8mm-usdhc
- fsl,imx8mn-usdhc
- fsl,imx8mp-usdhc
@ -71,6 +71,7 @@ properties:
deprecated: true
- items:
- enum:
- fsl,imx8dxl-usdhc
- fsl,imx8qm-usdhc
- const: fsl,imx8qxp-usdhc
- const: fsl,imx7d-usdhc

View File

@ -0,0 +1,57 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/fujitsu,sdhci-fujitsu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Fujitsu/Socionext SDHCI controller (F_SDH30)
maintainers:
- Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
allOf:
- $ref: mmc-controller.yaml#
properties:
compatible:
enum:
- fujitsu,mb86s70-sdhci-3.0
- socionext,f-sdh30-e51-mmc
reg:
maxItems: 1
clocks:
maxItems: 2
clock-names:
items:
- const: iface
- const: core
resets:
maxItems: 1
fujitsu,cmd-dat-delay-select:
type: boolean
description: |
Indicating that this host requires the CMD_DAT_DELAY control to be enabled
unevaluatedProperties: false
required:
- compatible
- reg
- clocks
- clock-names
examples:
- |
sdhci1: mmc@36600000 {
compatible = "fujitsu,mb86s70-sdhci-3.0";
reg = <0x36600000 0x1000>;
bus-width = <4>;
vqmmc-supply = <&vccq_sdhci1>;
clocks = <&clock 2 2 0>, <&clock 2 3 0>;
clock-names = "iface", "core";
};

View File

@ -293,7 +293,6 @@ properties:
description:
SDIO only. Preserves card power during a suspend/resume cycle.
# Deprecated: enable-sdio-wakeup
wakeup-source:
$ref: /schemas/types.yaml#/definitions/flag
description:

View File

@ -10,9 +10,6 @@ maintainers:
- Chaotian Jing <chaotian.jing@mediatek.com>
- Wenbin Mei <wenbin.mei@mediatek.com>
allOf:
- $ref: mmc-controller.yaml#
properties:
compatible:
oneOf:
@ -23,6 +20,7 @@ properties:
- mediatek,mt6795-mmc
- mediatek,mt7620-mmc
- mediatek,mt7622-mmc
- mediatek,mt7986-mmc
- mediatek,mt8135-mmc
- mediatek,mt8173-mmc
- mediatek,mt8183-mmc
@ -48,27 +46,11 @@ properties:
description:
Should contain phandle for the clock feeding the MMC controller.
minItems: 2
items:
- description: source clock (required).
- description: HCLK which used for host (required).
- description: independent source clock gate (required for MT2712).
- description: bus clock used for internal register access (required for MT2712 MSDC0/3).
- description: msdc subsys clock gate (required for MT8192).
- description: peripheral bus clock gate (required for MT8192).
- description: AXI bus clock gate (required for MT8192).
- description: AHB bus clock gate (required for MT8192).
maxItems: 7
clock-names:
minItems: 2
items:
- const: source
- const: hclk
- const: source_cg
- const: bus_clk
- const: sys_cg
- const: pclk_cg
- const: axi_cg
- const: ahb_cg
maxItems: 7
interrupts:
description:
@ -190,15 +172,144 @@ required:
- vmmc-supply
- vqmmc-supply
if:
properties:
compatible:
contains:
const: mediatek,mt8183-mmc
then:
properties:
reg:
minItems: 2
allOf:
- $ref: mmc-controller.yaml#
- if:
properties:
compatible:
enum:
- mediatek,mt2701-mmc
- mediatek,mt6779-mmc
- mediatek,mt6795-mmc
- mediatek,mt7620-mmc
- mediatek,mt7622-mmc
- mediatek,mt7623-mmc
- mediatek,mt8135-mmc
- mediatek,mt8173-mmc
- mediatek,mt8183-mmc
- mediatek,mt8186-mmc
- mediatek,mt8188-mmc
- mediatek,mt8195-mmc
- mediatek,mt8516-mmc
then:
properties:
clocks:
minItems: 2
items:
- description: source clock
- description: HCLK which used for host
- description: independent source clock gate
clock-names:
minItems: 2
items:
- const: source
- const: hclk
- const: source_cg
- if:
properties:
compatible:
contains:
const: mediatek,mt2712-mmc
then:
properties:
clocks:
minItems: 3
items:
- description: source clock
- description: HCLK which used for host
- description: independent source clock gate
- description: bus clock used for internal register access (required for MSDC0/3).
clock-names:
minItems: 3
items:
- const: source
- const: hclk
- const: source_cg
- const: bus_clk
- if:
properties:
compatible:
contains:
const: mediatek,mt8183-mmc
then:
properties:
reg:
minItems: 2
- if:
properties:
compatible:
contains:
enum:
- mediatek,mt7986-mmc
then:
properties:
clocks:
minItems: 3
items:
- description: source clock
- description: HCLK which used for host
- description: independent source clock gate
- description: bus clock used for internal register access (required for MSDC0/3).
- description: msdc subsys clock gate
clock-names:
minItems: 3
items:
- const: source
- const: hclk
- const: source_cg
- const: bus_clk
- const: sys_cg
- if:
properties:
compatible:
enum:
- mediatek,mt8186-mmc
- mediatek,mt8188-mmc
- mediatek,mt8195-mmc
then:
properties:
clocks:
items:
- description: source clock
- description: HCLK which used for host
- description: independent source clock gate
- description: crypto clock used for data encrypt/decrypt (optional)
clock-names:
items:
- const: source
- const: hclk
- const: source_cg
- const: crypto
- if:
properties:
compatible:
contains:
const: mediatek,mt8192-mmc
then:
properties:
clocks:
items:
- description: source clock
- description: HCLK which used for host
- description: independent source clock gate
- description: msdc subsys clock gate
- description: peripheral bus clock gate
- description: AXI bus clock gate
- description: AHB bus clock gate
clock-names:
items:
- const: source
- const: hclk
- const: source_cg
- const: sys_cg
- const: pclk_cg
- const: axi_cg
- const: ahb_cg
unevaluatedProperties: false

View File

@ -64,6 +64,7 @@ properties:
- enum:
- renesas,sdhi-r8a779a0 # R-Car V3U
- renesas,sdhi-r8a779f0 # R-Car S4-8
- renesas,sdhi-r8a779g0 # R-Car V4H
- const: renesas,rcar-gen4-sdhi # R-Car Gen4
reg:

View File

@ -71,6 +71,9 @@ properties:
to control the clock phases, "ciu-sample" is required for tuning
high speed modes.
power-domains:
maxItems: 1
rockchip,default-sample-phase:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0

View File

@ -2,8 +2,8 @@
# 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#"
$id: http://devicetree.org/schemas/mmc/sdhci-am654.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI AM654 MMC Controller
@ -11,17 +11,18 @@ maintainers:
- Ulf Hansson <ulf.hansson@linaro.org>
allOf:
- $ref: mmc-controller.yaml#
- $ref: sdhci-common.yaml#
properties:
compatible:
oneOf:
- const: ti,am654-sdhci-5.1
- const: ti,j721e-sdhci-8bit
- const: ti,j721e-sdhci-4bit
- const: ti,am64-sdhci-8bit
- const: ti,am64-sdhci-4bit
- const: ti,am62-sdhci
- enum:
- ti,am62-sdhci
- ti,am64-sdhci-4bit
- ti,am64-sdhci-8bit
- ti,am654-sdhci-5.1
- ti,j721e-sdhci-4bit
- ti,j721e-sdhci-8bit
- items:
- const: ti,j7200-sdhci-8bit
- const: ti,j721e-sdhci-8bit
@ -49,8 +50,6 @@ properties:
- const: clk_ahb
- const: clk_xin
sdhci-caps-mask: true
dma-coherent:
type: boolean
@ -61,67 +60,67 @@ properties:
ti,otap-del-sel-legacy:
description: Output tap delay for SD/MMC legacy timing
$ref: "/schemas/types.yaml#/definitions/uint32"
$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"
$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"
$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"
$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"
$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"
$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"
$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"
$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"
$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"
$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"
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 0xf
@ -131,49 +130,55 @@ properties:
ti,itap-del-sel-legacy:
description: Input tap delay for SD/MMC legacy timing
$ref: "/schemas/types.yaml#/definitions/uint32"
$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"
$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"
$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"
$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"
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 0x1f
ti,itap-del-sel-ddr50:
description: Input tap delay for MMC DDR50 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"
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 0x1f
ti,trm-icp:
description: DLL trim select
$ref: "/schemas/types.yaml#/definitions/uint32"
$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"
$ref: /schemas/types.yaml#/definitions/uint32
enum:
- 33
- 40
@ -183,11 +188,11 @@ properties:
ti,strobe-sel:
description: strobe select delay for HS400 speed mode.
$ref: "/schemas/types.yaml#/definitions/uint32"
$ref: /schemas/types.yaml#/definitions/uint32
ti,clkbuf-sel:
description: Clock Delay Buffer Select
$ref: "/schemas/types.yaml#/definitions/uint32"
$ref: /schemas/types.yaml#/definitions/uint32
ti,fails-without-test-cd:
$ref: /schemas/types.yaml#/definitions/flag

View File

@ -0,0 +1,32 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/sdhci-common.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: SDHCI Controller Common Properties
maintainers:
- Adrian Hunter <adrian.hunter@intel.com>
description:
Common properties present on Secure Digital Host Controller Interface (SDHCI)
devices.
properties:
sdhci-caps:
$ref: /schemas/types.yaml#/definitions/uint64
description:
Additionally present SDHCI capabilities - values for SDHCI_CAPABILITIES
and SDHCI_CAPABILITIES_1 registers.
sdhci-caps-mask:
$ref: /schemas/types.yaml#/definitions/uint64
description:
Masked SDHCI capabilities to remove from SDHCI_CAPABILITIES and
SDHCI_CAPABILITIES_1 registers.
allOf:
- $ref: mmc-controller.yaml#
additionalProperties: true

View File

@ -1,32 +0,0 @@
* Fujitsu SDHCI controller
This file documents differences between the core properties in mmc.txt
and the properties used by the sdhci_f_sdh30 driver.
Required properties:
- compatible: "fujitsu,mb86s70-sdhci-3.0"
- clocks: Must contain an entry for each entry in clock-names. It is a
list of phandles and clock-specifier pairs.
See ../clocks/clock-bindings.txt for details.
- clock-names: Should contain the following two entries:
"iface" - clock used for sdhci interface
"core" - core clock for sdhci controller
Optional properties:
- vqmmc-supply: phandle to the regulator device tree node, mentioned
as the VCCQ/VDD_IO supply in the eMMC/SD specs.
- fujitsu,cmd-dat-delay-select: boolean property indicating that this host
requires the CMD_DAT_DELAY control to be enabled.
Example:
sdhci1: mmc@36600000 {
compatible = "fujitsu,mb86s70-sdhci-3.0";
reg = <0 0x36600000 0x1000>;
interrupts = <0 172 0x4>,
<0 173 0x4>;
bus-width = <4>;
vqmmc-supply = <&vccq_sdhci1>;
clocks = <&clock 2 2 0>, <&clock 2 3 0>;
clock-names = "iface", "core";
};

View File

@ -1,9 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/mmc/sdhci-msm.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/mmc/sdhci-msm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SDHCI controller (sdhci-msm)
@ -26,6 +25,7 @@ properties:
- qcom,msm8226-sdhci
- qcom,msm8953-sdhci
- qcom,msm8974-sdhci
- qcom,msm8976-sdhci
- qcom,msm8916-sdhci
- qcom,msm8992-sdhci
- qcom,msm8994-sdhci
@ -45,9 +45,12 @@ properties:
- qcom,sm6115-sdhci
- qcom,sm6125-sdhci
- qcom,sm6350-sdhci
- qcom,sm6375-sdhci
- qcom,sm8150-sdhci
- qcom,sm8250-sdhci
- qcom,sm8350-sdhci
- qcom,sm8450-sdhci
- qcom,sm8550-sdhci
- const: qcom,sdhci-msm-v5 # for sdcc version 5.0
reg:
@ -80,6 +83,8 @@ properties:
- const: cal
- const: sleep
dma-coherent: true
interrupts:
maxItems: 2
@ -133,16 +138,6 @@ properties:
description: A phandle to sdhci power domain node
maxItems: 1
mmc-ddr-1_8v: true
mmc-hs200-1_8v: true
mmc-hs400-1_8v: true
bus-width: true
max-frequency: true
operating-points-v2: true
patternProperties:
@ -165,7 +160,7 @@ required:
- interrupts
allOf:
- $ref: mmc-controller.yaml#
- $ref: sdhci-common.yaml#
- if:
properties:

View File

@ -45,6 +45,17 @@ properties:
- const: block
- const: timer
resets:
maxItems: 5
reset-names:
items:
- const: core
- const: bus
- const: axi
- const: block
- const: timer
rockchip,txclk-tapnum:
description: Specify the number of delay for tx sampling.
$ref: /schemas/types.yaml#/definitions/uint8

View File

@ -0,0 +1,61 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) Sunplus Ltd. Co. 2021
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/sunplus,mmc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Sunplus MMC Controller
maintainers:
- Tony Huang <tonyhuang.sunplus@gmail.com>
- Li-hao Kuo <lhjeff911@gmail.com>
allOf:
- $ref: "mmc-controller.yaml"
properties:
compatible:
enum:
- sunplus,sp7021-mmc
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
resets:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
- resets
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
mmc0: mmc@9c003b00 {
compatible = "sunplus,sp7021-mmc";
reg = <0x9c003b00 0x180>;
interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clkc 0x4e>;
resets = <&rstc 0x3e>;
bus-width = <8>;
max-frequency = <52000000>;
non-removable;
disable-wp;
cap-mmc-highspeed;
mmc-ddr-3_3v;
no-sdio;
no-sd;
};

View File

@ -6,9 +6,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synopsys Designware Mobile Storage Host Controller Binding
allOf:
- $ref: "synopsys-dw-mshc-common.yaml#"
maintainers:
- Ulf Hansson <ulf.hansson@linaro.org>
@ -38,6 +35,35 @@ properties:
- const: biu
- const: ciu
altr,sysmgr-syscon:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: phandle to the sysmgr node
- description: register offset that controls the SDMMC clock phase
- description: register shift for the smplsel(drive in) setting
description:
This property is optional. Contains the phandle to System Manager block
that contains the SDMMC clock-phase control register. The first value is
the pointer to the sysmgr, the 2nd value is the register offset for the
SDMMC clock phase register, and the 3rd value is the bit shift for the
smplsel(drive in) setting.
allOf:
- $ref: synopsys-dw-mshc-common.yaml#
- if:
properties:
compatible:
contains:
const: altr,socfpga-dw-mshc
then:
properties:
altr,sysmgr-syscon: true
else:
properties:
altr,sysmgr-syscon: false
required:
- compatible
- reg

View File

@ -17,15 +17,14 @@ interrupt.
List of legacy properties and respective binding document
---------------------------------------------------------
1. "enable-sdio-wakeup" Documentation/devicetree/bindings/mmc/mmc.txt
2. "gpio-key,wakeup" Documentation/devicetree/bindings/input/gpio-keys{,-polled}.txt
3. "has-tpo" Documentation/devicetree/bindings/rtc/rtc-opal.txt
4. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
1. "gpio-key,wakeup" Documentation/devicetree/bindings/input/gpio-keys{,-polled}.txt
2. "has-tpo" Documentation/devicetree/bindings/rtc/rtc-opal.txt
3. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
Documentation/devicetree/bindings/mfd/tc3589x.txt
Documentation/devicetree/bindings/input/touchscreen/ads7846.txt
5. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
6. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung-keypad.txt
7. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
4. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
5. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung-keypad.txt
6. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
Examples
--------

View File

@ -18612,6 +18612,7 @@ K: \bsecure_computing
K: \bTIF_SECCOMP\b
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) Broadcom BRCMSTB DRIVER
M: Kamal Dasu <kdasu.kdev@gmail.com>
M: Al Cooper <alcooperx@gmail.com>
R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
L: linux-mmc@vger.kernel.org
@ -18622,6 +18623,7 @@ SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
M: Adrian Hunter <adrian.hunter@intel.com>
L: linux-mmc@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/mmc/sdhci-common.yaml
F: drivers/mmc/host/sdhci*
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
@ -19884,6 +19886,13 @@ W: https://sunplus.atlassian.net/wiki/spaces/doc/overview
F: Documentation/devicetree/bindings/net/sunplus,sp7021-emac.yaml
F: drivers/net/ethernet/sunplus/
SUNPLUS MMC DRIVER
M: Tony Huang <tonyhuang.sunplus@gmail.com>
M: Li-hao Kuo <lhjeff911@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/mmc/sunplus,mmc.yaml
F: drivers/mmc/host/sunplus-mmc.c
SUNPLUS OCOTP DRIVER
M: Vincent Shih <vincent.sunplus@gmail.com>
S: Maintained

View File

@ -35,59 +35,7 @@ static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw *hwclk,
return parent_rate / div;
}
static int socfpga_clk_prepare(struct clk_hw *hwclk)
{
struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
int i;
u32 hs_timing;
u32 clk_phase[2];
if (socfpgaclk->clk_phase[0] || socfpgaclk->clk_phase[1]) {
for (i = 0; i < ARRAY_SIZE(clk_phase); i++) {
switch (socfpgaclk->clk_phase[i]) {
case 0:
clk_phase[i] = 0;
break;
case 45:
clk_phase[i] = 1;
break;
case 90:
clk_phase[i] = 2;
break;
case 135:
clk_phase[i] = 3;
break;
case 180:
clk_phase[i] = 4;
break;
case 225:
clk_phase[i] = 5;
break;
case 270:
clk_phase[i] = 6;
break;
case 315:
clk_phase[i] = 7;
break;
default:
clk_phase[i] = 0;
break;
}
}
hs_timing = SYSMGR_SDMMC_CTRL_SET_AS10(clk_phase[0], clk_phase[1]);
if (!IS_ERR(socfpgaclk->sys_mgr_base_addr))
regmap_write(socfpgaclk->sys_mgr_base_addr,
SYSMGR_SDMMCGRP_CTRL_OFFSET, hs_timing);
else
pr_err("%s: cannot set clk_phase because sys_mgr_base_addr is not available!\n",
__func__);
}
return 0;
}
static struct clk_ops gateclk_ops = {
.prepare = socfpga_clk_prepare,
.recalc_rate = socfpga_gate_clk_recalc_rate,
};
@ -96,7 +44,6 @@ static void __init __socfpga_gate_init(struct device_node *node,
{
u32 clk_gate[2];
u32 div_reg[3];
u32 clk_phase[2];
u32 fixed_div;
struct clk_hw *hw_clk;
struct socfpga_gate_clk *socfpga_clk;
@ -136,21 +83,6 @@ static void __init __socfpga_gate_init(struct device_node *node,
socfpga_clk->div_reg = NULL;
}
rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
if (!rc) {
socfpga_clk->clk_phase[0] = clk_phase[0];
socfpga_clk->clk_phase[1] = clk_phase[1];
socfpga_clk->sys_mgr_base_addr =
syscon_regmap_lookup_by_compatible("altr,sys-mgr");
if (IS_ERR(socfpga_clk->sys_mgr_base_addr)) {
pr_err("%s: failed to find altr,sys-mgr regmap!\n",
__func__);
kfree(socfpga_clk);
return;
}
}
of_property_read_string(node, "clock-output-names", &clk_name);
init.name = clk_name;

View File

@ -108,61 +108,7 @@ static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
return parent_rate / div;
}
static int socfpga_clk_prepare(struct clk_hw *hwclk)
{
struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
struct regmap *sys_mgr_base_addr;
int i;
u32 hs_timing;
u32 clk_phase[2];
if (socfpgaclk->clk_phase[0] || socfpgaclk->clk_phase[1]) {
sys_mgr_base_addr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
if (IS_ERR(sys_mgr_base_addr)) {
pr_err("%s: failed to find altr,sys-mgr regmap!\n", __func__);
return -EINVAL;
}
for (i = 0; i < 2; i++) {
switch (socfpgaclk->clk_phase[i]) {
case 0:
clk_phase[i] = 0;
break;
case 45:
clk_phase[i] = 1;
break;
case 90:
clk_phase[i] = 2;
break;
case 135:
clk_phase[i] = 3;
break;
case 180:
clk_phase[i] = 4;
break;
case 225:
clk_phase[i] = 5;
break;
case 270:
clk_phase[i] = 6;
break;
case 315:
clk_phase[i] = 7;
break;
default:
clk_phase[i] = 0;
break;
}
}
hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1]);
regmap_write(sys_mgr_base_addr, SYSMGR_SDMMCGRP_CTRL_OFFSET,
hs_timing);
}
return 0;
}
static struct clk_ops gateclk_ops = {
.prepare = socfpga_clk_prepare,
.recalc_rate = socfpga_clk_recalc_rate,
.get_parent = socfpga_clk_get_parent,
.set_parent = socfpga_clk_set_parent,
@ -172,7 +118,6 @@ void __init socfpga_gate_init(struct device_node *node)
{
u32 clk_gate[2];
u32 div_reg[3];
u32 clk_phase[2];
u32 fixed_div;
struct clk_hw *hw_clk;
struct socfpga_gate_clk *socfpga_clk;
@ -218,12 +163,6 @@ void __init socfpga_gate_init(struct device_node *node)
socfpga_clk->div_reg = NULL;
}
rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
if (!rc) {
socfpga_clk->clk_phase[0] = clk_phase[0];
socfpga_clk->clk_phase[1] = clk_phase[1];
}
of_property_read_string(node, "clock-output-names", &clk_name);
init.name = clk_name;

View File

@ -50,7 +50,6 @@ struct socfpga_gate_clk {
u32 width; /* only valid if div_reg != 0 */
u32 shift; /* only valid if div_reg != 0 */
u32 bypass_shift; /* only valid if bypass_reg != 0 */
u32 clk_phase[2];
};
struct socfpga_periph_clk {

View File

@ -2116,6 +2116,11 @@ static int msb_init_disk(struct memstick_dev *card)
dbg("Set total disk size to %lu sectors", capacity);
msb->io_queue = alloc_ordered_workqueue("ms_block", WQ_MEM_RECLAIM);
if (!msb->io_queue) {
rc = -ENOMEM;
goto out_cleanup_disk;
}
INIT_WORK(&msb->io_work, msb_io_work);
sg_init_table(msb->prealloc_sg, MS_BLOCK_MAX_SEGS+1);
@ -2125,10 +2130,12 @@ static int msb_init_disk(struct memstick_dev *card)
msb_start(card);
rc = device_add_disk(&card->dev, msb->disk, NULL);
if (rc)
goto out_cleanup_disk;
goto out_destroy_workqueue;
dbg("Disk added");
return 0;
out_destroy_workqueue:
destroy_workqueue(msb->io_queue);
out_cleanup_disk:
put_disk(msb->disk);
out_free_tag_set:

View File

@ -260,8 +260,8 @@ static ssize_t mspro_block_attr_show_default(struct device *dev,
buffer[rc++] = '\n';
}
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "%02x ",
((unsigned char *)s_attr->data)[cnt]);
rc += sysfs_emit_at(buffer, rc, "%02x ",
((unsigned char *)s_attr->data)[cnt]);
}
return rc;
}
@ -290,61 +290,43 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev,
date_tz_f *= 15;
}
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n",
x_sys->class);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block size: %x\n",
be16_to_cpu(x_sys->block_size));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block count: %x\n",
be16_to_cpu(x_sys->block_count));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "user block count: %x\n",
be16_to_cpu(x_sys->user_block_count));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n",
be16_to_cpu(x_sys->page_size));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: "
"GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n",
date_tz, date_tz_f,
be16_to_cpup((__be16 *)&x_sys->assembly_date[1]),
x_sys->assembly_date[3], x_sys->assembly_date[4],
x_sys->assembly_date[5], x_sys->assembly_date[6],
x_sys->assembly_date[7]);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "serial number: %x\n",
be32_to_cpu(x_sys->serial_number));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc,
"assembly maker code: %x\n",
x_sys->assembly_maker_code);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly model code: "
"%02x%02x%02x\n", x_sys->assembly_model_code[0],
x_sys->assembly_model_code[1],
x_sys->assembly_model_code[2]);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory maker code: %x\n",
be16_to_cpu(x_sys->memory_maker_code));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory model code: %x\n",
be16_to_cpu(x_sys->memory_model_code));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vcc: %x\n",
x_sys->vcc);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vpp: %x\n",
x_sys->vpp);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller number: %x\n",
be16_to_cpu(x_sys->controller_number));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc,
"controller function: %x\n",
be16_to_cpu(x_sys->controller_function));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",
be16_to_cpu(x_sys->start_sector));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "unit size: %x\n",
be16_to_cpu(x_sys->unit_size));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sub class: %x\n",
x_sys->ms_sub_class);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "interface type: %x\n",
x_sys->interface_type);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller code: %x\n",
be16_to_cpu(x_sys->controller_code));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "format type: %x\n",
x_sys->format_type);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "device type: %x\n",
x_sys->device_type);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "mspro id: %s\n",
x_sys->mspro_id);
rc += sysfs_emit_at(buffer, rc, "class: %x\n", x_sys->class);
rc += sysfs_emit_at(buffer, rc, "block size: %x\n", be16_to_cpu(x_sys->block_size));
rc += sysfs_emit_at(buffer, rc, "block count: %x\n", be16_to_cpu(x_sys->block_count));
rc += sysfs_emit_at(buffer, rc, "user block count: %x\n",
be16_to_cpu(x_sys->user_block_count));
rc += sysfs_emit_at(buffer, rc, "page size: %x\n", be16_to_cpu(x_sys->page_size));
rc += sysfs_emit_at(buffer, rc, "assembly date: GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n",
date_tz, date_tz_f,
be16_to_cpup((__be16 *)&x_sys->assembly_date[1]),
x_sys->assembly_date[3], x_sys->assembly_date[4],
x_sys->assembly_date[5], x_sys->assembly_date[6],
x_sys->assembly_date[7]);
rc += sysfs_emit_at(buffer, rc, "serial number: %x\n", be32_to_cpu(x_sys->serial_number));
rc += sysfs_emit_at(buffer, rc, "assembly maker code: %x\n", x_sys->assembly_maker_code);
rc += sysfs_emit_at(buffer, rc, "assembly model code: %02x%02x%02x\n",
x_sys->assembly_model_code[0],
x_sys->assembly_model_code[1],
x_sys->assembly_model_code[2]);
rc += sysfs_emit_at(buffer, rc, "memory maker code: %x\n",
be16_to_cpu(x_sys->memory_maker_code));
rc += sysfs_emit_at(buffer, rc, "memory model code: %x\n",
be16_to_cpu(x_sys->memory_model_code));
rc += sysfs_emit_at(buffer, rc, "vcc: %x\n", x_sys->vcc);
rc += sysfs_emit_at(buffer, rc, "vpp: %x\n", x_sys->vpp);
rc += sysfs_emit_at(buffer, rc, "controller number: %x\n",
be16_to_cpu(x_sys->controller_number));
rc += sysfs_emit_at(buffer, rc, "controller function: %x\n",
be16_to_cpu(x_sys->controller_function));
rc += sysfs_emit_at(buffer, rc, "start sector: %x\n", be16_to_cpu(x_sys->start_sector));
rc += sysfs_emit_at(buffer, rc, "unit size: %x\n", be16_to_cpu(x_sys->unit_size));
rc += sysfs_emit_at(buffer, rc, "sub class: %x\n", x_sys->ms_sub_class);
rc += sysfs_emit_at(buffer, rc, "interface type: %x\n", x_sys->interface_type);
rc += sysfs_emit_at(buffer, rc, "controller code: %x\n",
be16_to_cpu(x_sys->controller_code));
rc += sysfs_emit_at(buffer, rc, "format type: %x\n", x_sys->format_type);
rc += sysfs_emit_at(buffer, rc, "device type: %x\n", x_sys->device_type);
rc += sysfs_emit_at(buffer, rc, "mspro id: %s\n", x_sys->mspro_id);
return rc;
}
@ -356,7 +338,7 @@ static ssize_t mspro_block_attr_show_modelname(struct device *dev,
struct mspro_sys_attr,
dev_attr);
return scnprintf(buffer, PAGE_SIZE, "%s", (char *)s_attr->data);
return sysfs_emit(buffer, "%s", (char *)s_attr->data);
}
static ssize_t mspro_block_attr_show_mbr(struct device *dev,
@ -369,27 +351,17 @@ static ssize_t mspro_block_attr_show_mbr(struct device *dev,
struct mspro_mbr *x_mbr = x_attr->data;
ssize_t rc = 0;
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "boot partition: %x\n",
x_mbr->boot_partition);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start head: %x\n",
x_mbr->start_head);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",
x_mbr->start_sector);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cylinder: %x\n",
x_mbr->start_cylinder);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "partition type: %x\n",
x_mbr->partition_type);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end head: %x\n",
x_mbr->end_head);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end sector: %x\n",
x_mbr->end_sector);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end cylinder: %x\n",
x_mbr->end_cylinder);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sectors: %x\n",
x_mbr->start_sectors);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc,
"sectors per partition: %x\n",
x_mbr->sectors_per_partition);
rc += sysfs_emit_at(buffer, rc, "boot partition: %x\n", x_mbr->boot_partition);
rc += sysfs_emit_at(buffer, rc, "start head: %x\n", x_mbr->start_head);
rc += sysfs_emit_at(buffer, rc, "start sector: %x\n", x_mbr->start_sector);
rc += sysfs_emit_at(buffer, rc, "start cylinder: %x\n", x_mbr->start_cylinder);
rc += sysfs_emit_at(buffer, rc, "partition type: %x\n", x_mbr->partition_type);
rc += sysfs_emit_at(buffer, rc, "end head: %x\n", x_mbr->end_head);
rc += sysfs_emit_at(buffer, rc, "end sector: %x\n", x_mbr->end_sector);
rc += sysfs_emit_at(buffer, rc, "end cylinder: %x\n", x_mbr->end_cylinder);
rc += sysfs_emit_at(buffer, rc, "start sectors: %x\n", x_mbr->start_sectors);
rc += sysfs_emit_at(buffer, rc, "sectors per partition: %x\n",
x_mbr->sectors_per_partition);
return rc;
}
@ -409,22 +381,19 @@ static ssize_t mspro_block_attr_show_specfile(struct device *dev,
memcpy(ext, x_spfile->ext, 3);
ext[3] = 0;
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "name: %s\n", name);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "ext: %s\n", ext);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "attribute: %x\n",
x_spfile->attr);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "time: %d:%d:%d\n",
x_spfile->time >> 11,
(x_spfile->time >> 5) & 0x3f,
(x_spfile->time & 0x1f) * 2);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "date: %d-%d-%d\n",
(x_spfile->date >> 9) + 1980,
(x_spfile->date >> 5) & 0xf,
x_spfile->date & 0x1f);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cluster: %x\n",
x_spfile->cluster);
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "size: %x\n",
x_spfile->size);
rc += sysfs_emit_at(buffer, rc, "name: %s\n", name);
rc += sysfs_emit_at(buffer, rc, "ext: %s\n", ext);
rc += sysfs_emit_at(buffer, rc, "attribute: %x\n", x_spfile->attr);
rc += sysfs_emit_at(buffer, rc, "time: %d:%d:%d\n",
x_spfile->time >> 11,
(x_spfile->time >> 5) & 0x3f,
(x_spfile->time & 0x1f) * 2);
rc += sysfs_emit_at(buffer, rc, "date: %d-%d-%d\n",
(x_spfile->date >> 9) + 1980,
(x_spfile->date >> 5) & 0xf,
x_spfile->date & 0x1f);
rc += sysfs_emit_at(buffer, rc, "start cluster: %x\n", x_spfile->cluster);
rc += sysfs_emit_at(buffer, rc, "size: %x\n", x_spfile->size);
return rc;
}
@ -438,16 +407,14 @@ static ssize_t mspro_block_attr_show_devinfo(struct device *dev,
struct mspro_devinfo *x_devinfo = x_attr->data;
ssize_t rc = 0;
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "cylinders: %x\n",
be16_to_cpu(x_devinfo->cylinders));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "heads: %x\n",
be16_to_cpu(x_devinfo->heads));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per track: %x\n",
be16_to_cpu(x_devinfo->bytes_per_track));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per sector: %x\n",
be16_to_cpu(x_devinfo->bytes_per_sector));
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sectors per track: %x\n",
be16_to_cpu(x_devinfo->sectors_per_track));
rc += sysfs_emit_at(buffer, rc, "cylinders: %x\n", be16_to_cpu(x_devinfo->cylinders));
rc += sysfs_emit_at(buffer, rc, "heads: %x\n", be16_to_cpu(x_devinfo->heads));
rc += sysfs_emit_at(buffer, rc, "bytes per track: %x\n",
be16_to_cpu(x_devinfo->bytes_per_track));
rc += sysfs_emit_at(buffer, rc, "bytes per sector: %x\n",
be16_to_cpu(x_devinfo->bytes_per_sector));
rc += sysfs_emit_at(buffer, rc, "sectors per track: %x\n",
be16_to_cpu(x_devinfo->sectors_per_track));
return rc;
}

View File

@ -514,19 +514,6 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
if (idata->ic.data_timeout_ns)
data.timeout_ns = idata->ic.data_timeout_ns;
if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
/*
* Pretend this is a data transfer and rely on the
* host driver to compute timeout. When all host
* drivers support cmd.cmd_timeout for R1B, this
* can be changed to:
*
* mrq.data = NULL;
* cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
*/
data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
}
mrq.data = &data;
}

View File

@ -359,9 +359,7 @@ int mmc_add_card(struct mmc_card *card)
uhs_bus_speed_mode, type, card->rca);
}
#ifdef CONFIG_DEBUG_FS
mmc_add_card_debugfs(card);
#endif
card->dev.of_node = mmc_of_find_child_device(card->host, 0);
device_enable_async_suspend(&card->dev);
@ -383,9 +381,7 @@ void mmc_remove_card(struct mmc_card *card)
{
struct mmc_host *host = card->host;
#ifdef CONFIG_DEBUG_FS
mmc_remove_card_debugfs(card);
#endif
if (mmc_card_present(card)) {
if (mmc_host_is_spi(card->host)) {

View File

@ -56,7 +56,7 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
/*
* Enabling software CRCs on the data blocks can be a significant (30%)
* performance cost, and for other reasons may not always be desired.
* So we allow it it to be disabled.
* So we allow it to be disabled.
*/
bool use_spi_crc = 1;
module_param(use_spi_crc, bool, 0);
@ -142,8 +142,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
int err = cmd->error;
/* Flag re-tuning needed on CRC errors */
if (cmd->opcode != MMC_SEND_TUNING_BLOCK &&
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
if (!mmc_op_tuning(cmd->opcode) &&
!host->retune_crc_disable &&
(err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) ||
(mrq->data && mrq->data->error == -EILSEQ) ||
@ -527,7 +526,7 @@ EXPORT_SYMBOL(mmc_cqe_post_req);
* mmc_cqe_recovery - Recover from CQE errors.
* @host: MMC host to recover
*
* Recovery consists of stopping CQE, stopping eMMC, discarding the queue in
* Recovery consists of stopping CQE, stopping eMMC, discarding the queue
* in eMMC, and discarding the queue in CQE. CQE must call
* mmc_cqe_request_done() on all requests. An error is returned if the eMMC
* fails to discard its queue.

View File

@ -86,11 +86,26 @@ int mmc_attach_sdio(struct mmc_host *host);
extern bool use_spi_crc;
/* Debugfs information for hosts and cards */
#ifdef CONFIG_DEBUG_FS
void mmc_add_host_debugfs(struct mmc_host *host);
void mmc_remove_host_debugfs(struct mmc_host *host);
void mmc_add_card_debugfs(struct mmc_card *card);
void mmc_remove_card_debugfs(struct mmc_card *card);
#else
static inline void mmc_add_host_debugfs(struct mmc_host *host)
{
}
static inline void mmc_remove_host_debugfs(struct mmc_host *host)
{
}
static inline void mmc_add_card_debugfs(struct mmc_card *card)
{
}
static inline void mmc_remove_card_debugfs(struct mmc_card *card)
{
}
#endif
int mmc_execute_tuning(struct mmc_card *card);
int mmc_hs200_to_hs400(struct mmc_card *card);

View File

@ -269,7 +269,7 @@ EXPORT_SYMBOL(mmc_of_parse_clk_phase);
* @host: host whose properties should be parsed.
*
* To keep the rest of the MMC subsystem unaware of whether DT has been
* used to to instantiate and configure this host instance or not, we
* used to instantiate and configure this host instance or not, we
* parse the properties and set respective generic mmc-host flags and
* parameters.
*/
@ -629,9 +629,7 @@ int mmc_add_host(struct mmc_host *host)
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
#ifdef CONFIG_DEBUG_FS
mmc_add_host_debugfs(host);
#endif
mmc_start_host(host);
return 0;
@ -651,9 +649,7 @@ void mmc_remove_host(struct mmc_host *host)
{
mmc_stop_host(host);
#ifdef CONFIG_DEBUG_FS
mmc_remove_host_debugfs(host);
#endif
device_del(&host->class_dev);

View File

@ -932,7 +932,6 @@ static int mmc_test_transfer(struct mmc_test_card *test,
unsigned blocks, unsigned blksz, int write)
{
int ret, i;
unsigned long flags;
if (write) {
for (i = 0; i < blocks * blksz; i++)
@ -940,9 +939,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
} else {
memset(test->scratch, 0, BUFFER_SIZE);
}
local_irq_save(flags);
sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
local_irq_restore(flags);
ret = mmc_test_set_blksize(test, blksz);
if (ret)
@ -987,9 +984,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
return RESULT_FAIL;
}
} else {
local_irq_save(flags);
sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
local_irq_restore(flags);
for (i = 0; i < blocks * blksz; i++) {
if (test->scratch[i] != (u8)i)
return RESULT_FAIL;

View File

@ -29,7 +29,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
mutex_lock(&pwrseq_list_mutex);
list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
if (p->dev->of_node == np) {
if (device_match_of_node(p->dev, np)) {
if (!try_module_get(p->owner))
dev_err(host->parent,
"increasing module refcount failed\n");

View File

@ -1259,7 +1259,7 @@ static int sd_read_ext_regs(struct mmc_card *card)
*/
err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
if (err) {
pr_warn("%s: error %d reading general info of SD ext reg\n",
pr_err("%s: error %d reading general info of SD ext reg\n",
mmc_hostname(card->host), err);
goto out;
}
@ -1273,7 +1273,12 @@ static int sd_read_ext_regs(struct mmc_card *card)
/* Number of extensions to be find. */
num_ext = gen_info_buf[4];
/* We support revision 0, but limit it to 512 bytes for simplicity. */
/*
* We only support revision 0 and limit it to 512 bytes for simplicity.
* No matter what, let's return zero to allow us to continue using the
* card, even if we can't support the features from the SD function
* extensions registers.
*/
if (rev != 0 || len > 512) {
pr_warn("%s: non-supported SD ext reg layout\n",
mmc_hostname(card->host));
@ -1288,7 +1293,7 @@ static int sd_read_ext_regs(struct mmc_card *card)
for (i = 0; i < num_ext; i++) {
err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr);
if (err) {
pr_warn("%s: error %d parsing SD ext reg\n",
pr_err("%s: error %d parsing SD ext reg\n",
mmc_hostname(card->host), err);
goto out;
}

View File

@ -14,6 +14,15 @@ config MMC_DEBUG
added host drivers please don't invent their private macro for
debugging.
config MMC_SUNPLUS
tristate "Sunplus SP7021 MMC Controller"
depends on ARCH_SUNPLUS || COMPILE_TEST
help
If you say yes here, you will get support for eMMC host interface
on Sunplus SoCs.
If unsure, say N
config MMC_ARMMMCI
tristate "ARM AMBA Multimedia Card Interface support"
depends on ARM_AMBA
@ -1040,10 +1049,10 @@ config MMC_SDHCI_MICROCHIP_PIC32
config MMC_SDHCI_BRCMSTB
tristate "Broadcom SDIO/SD/MMC support"
depends on ARCH_BRCMSTB || BMIPS_GENERIC
depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
select MMC_CQHCI
default y
default ARCH_BRCMSTB || BMIPS_GENERIC
help
This selects support for the SDIO/SD/MMC Host Controller on
Broadcom STB SoCs.

View File

@ -97,6 +97,7 @@ obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o
obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o
obj-$(CONFIG_MMC_SUNPLUS) += sunplus-mmc.o
obj-$(CONFIG_MMC_CQHCI) += cqhci.o
cqhci-y += cqhci-core.o
cqhci-$(CONFIG_MMC_CRYPTO) += cqhci-crypto.o

View File

@ -1114,7 +1114,10 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)
alcor_hw_init(host);
dev_set_drvdata(&pdev->dev, host);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto free_host;
return 0;
free_host:

View File

@ -2222,6 +2222,7 @@ static int atmci_init_slot(struct atmel_mci *host,
{
struct mmc_host *mmc;
struct atmel_mci_slot *slot;
int ret;
mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
if (!mmc)
@ -2305,11 +2306,13 @@ static int atmci_init_slot(struct atmel_mci *host,
host->slot[id] = slot;
mmc_regulator_get_supply(mmc);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret) {
mmc_free_host(mmc);
return ret;
}
if (gpio_is_valid(slot->detect_pin)) {
int ret;
timer_setup(&slot->detect_timer, atmci_detect_change, 0);
ret = request_irq(gpio_to_irq(slot->detect_pin),

View File

@ -388,7 +388,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
/* This is the pointer to the data buffer */
sg = &data->sg[host->pio.index];
sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset;
sg_ptr = kmap_local_page(sg_page(sg)) + sg->offset + host->pio.offset;
/* This is the space left inside the buffer */
sg_len = data->sg[host->pio.index].length - host->pio.offset;
@ -409,7 +409,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
__raw_writel((unsigned long)val, HOST_TXPORT(host));
wmb(); /* drain writebuffer */
}
kunmap_atomic(sg_ptr);
kunmap_local(sg_ptr);
host->pio.len -= count;
host->pio.offset += count;
@ -446,7 +446,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
if (host->pio.index < host->dma.len) {
sg = &data->sg[host->pio.index];
sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset;
sg_ptr = kmap_local_page(sg_page(sg)) + sg->offset + host->pio.offset;
/* This is the space left inside the buffer */
sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
@ -488,7 +488,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
sg_ptr[count] = (unsigned char)(val & 0xFF);
}
if (sg_ptr)
kunmap_atomic(sg_ptr);
kunmap_local(sg_ptr);
host->pio.len -= count;
host->pio.offset += count;

View File

@ -327,7 +327,6 @@ static void bcm2835_dma_complete(void *param)
static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read)
{
unsigned long flags;
size_t blksize;
unsigned long wait_max;
@ -335,8 +334,6 @@ static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read)
wait_max = jiffies + msecs_to_jiffies(500);
local_irq_save(flags);
while (blksize) {
int copy_words;
u32 hsts = 0;
@ -421,8 +418,6 @@ static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read)
}
sg_miter_stop(&host->sg_miter);
local_irq_restore(flags);
}
static void bcm2835_transfer_pio(struct bcm2835_host *host)
@ -1068,7 +1063,6 @@ static void bcm2835_dma_complete_work(struct work_struct *work)
}
if (host->drain_words) {
unsigned long flags;
void *page;
u32 *buf;
@ -1076,8 +1070,7 @@ static void bcm2835_dma_complete_work(struct work_struct *work)
host->drain_page += host->drain_offset >> PAGE_SHIFT;
host->drain_offset &= ~PAGE_MASK;
}
local_irq_save(flags);
page = kmap_atomic(host->drain_page);
page = kmap_local_page(host->drain_page);
buf = page + host->drain_offset;
while (host->drain_words) {
@ -1088,8 +1081,7 @@ static void bcm2835_dma_complete_work(struct work_struct *work)
host->drain_words--;
}
kunmap_atomic(page);
local_irq_restore(flags);
kunmap_local(page);
}
bcm2835_finish_data(host);

View File

@ -17,10 +17,16 @@
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/of.h>
#include <linux/mfd/altera-sysmgr.h>
#include <linux/regmap.h>
#include "dw_mmc.h"
#include "dw_mmc-pltfm.h"
#define SOCFPGA_DW_MMC_CLK_PHASE_STEP 45
#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel, reg_shift) \
((((smplsel) & 0x7) << reg_shift) | (((drvsel) & 0x7) << 0))
int dw_mci_pltfm_register(struct platform_device *pdev,
const struct dw_mci_drv_data *drv_data)
{
@ -62,9 +68,42 @@ const struct dev_pm_ops dw_mci_pltfm_pmops = {
};
EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
static int dw_mci_socfpga_priv_init(struct dw_mci *host)
{
struct device_node *np = host->dev->of_node;
struct regmap *sys_mgr_base_addr;
u32 clk_phase[2] = {0}, reg_offset, reg_shift;
int i, rc, hs_timing;
rc = of_property_read_variable_u32_array(np, "clk-phase-sd-hs", &clk_phase[0], 2, 0);
if (rc < 0)
return 0;
sys_mgr_base_addr = altr_sysmgr_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
if (IS_ERR(sys_mgr_base_addr)) {
dev_warn(host->dev, "clk-phase-sd-hs was specified, but failed to find altr,sys-mgr regmap!\n");
return 0;
}
of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, &reg_offset);
of_property_read_u32_index(np, "altr,sysmgr-syscon", 2, &reg_shift);
for (i = 0; i < ARRAY_SIZE(clk_phase); i++)
clk_phase[i] /= SOCFPGA_DW_MMC_CLK_PHASE_STEP;
hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1], reg_shift);
regmap_write(sys_mgr_base_addr, reg_offset, hs_timing);
return 0;
}
static const struct dw_mci_drv_data socfpga_drv_data = {
.init = dw_mci_socfpga_priv_init,
};
static const struct of_device_id dw_mci_pltfm_match[] = {
{ .compatible = "snps,dw-mshc", },
{ .compatible = "altr,socfpga-dw-mshc", },
{ .compatible = "altr,socfpga-dw-mshc", .data = &socfpga_drv_data, },
{ .compatible = "img,pistachio-dw-mshc", },
{},
};

View File

@ -334,8 +334,7 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
cmdr == MMC_READ_MULTIPLE_BLOCK ||
cmdr == MMC_WRITE_BLOCK ||
cmdr == MMC_WRITE_MULTIPLE_BLOCK ||
cmdr == MMC_SEND_TUNING_BLOCK ||
cmdr == MMC_SEND_TUNING_BLOCK_HS200 ||
mmc_op_tuning(cmdr) ||
cmdr == MMC_GEN_CMD) {
stop->opcode = MMC_STOP_TRANSMISSION;
stop->arg = 0;
@ -1363,7 +1362,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
* is just about to roll over.
*
* We do this whole thing under spinlock and only if the
* command hasn't already completed (indicating the the irq
* command hasn't already completed (indicating the irq
* already ran so we don't want the timeout).
*/
spin_lock_irqsave(&host->irq_lock, irqflags);

View File

@ -502,6 +502,7 @@ static int litex_mmc_irq_init(struct platform_device *pdev,
use_polling:
host->mmc->caps |= MMC_CAP_NEEDS_POLL;
host->irq = 0;
return 0;
}

View File

@ -1335,7 +1335,9 @@ static int meson_mmc_probe(struct platform_device *pdev)
}
mmc->ops = &meson_mmc_ops;
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto err_free_irq;
return 0;

View File

@ -13,9 +13,6 @@
#include "mmc_hsq.h"
#define HSQ_NUM_SLOTS 64
#define HSQ_INVALID_TAG HSQ_NUM_SLOTS
static void mmc_hsq_retry_handler(struct work_struct *work)
{
struct mmc_hsq *hsq = container_of(work, struct mmc_hsq, retry_work);
@ -73,7 +70,6 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains)
{
struct hsq_slot *slot;
int tag;
/*
@ -82,29 +78,12 @@ static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains)
*/
if (!remains) {
hsq->next_tag = HSQ_INVALID_TAG;
hsq->tail_tag = HSQ_INVALID_TAG;
return;
}
/*
* Increasing the next tag and check if the corresponding request is
* available, if yes, then we found a candidate request.
*/
if (++hsq->next_tag != HSQ_INVALID_TAG) {
slot = &hsq->slot[hsq->next_tag];
if (slot->mrq)
return;
}
/* Othersie we should iterate all slots to find a available tag. */
for (tag = 0; tag < HSQ_NUM_SLOTS; tag++) {
slot = &hsq->slot[tag];
if (slot->mrq)
break;
}
if (tag == HSQ_NUM_SLOTS)
tag = HSQ_INVALID_TAG;
tag = hsq->tag_slot[hsq->next_tag];
hsq->tag_slot[hsq->next_tag] = HSQ_INVALID_TAG;
hsq->next_tag = tag;
}
@ -233,8 +212,14 @@ static int mmc_hsq_request(struct mmc_host *mmc, struct mmc_request *mrq)
* Set the next tag as current request tag if no available
* next tag.
*/
if (hsq->next_tag == HSQ_INVALID_TAG)
if (hsq->next_tag == HSQ_INVALID_TAG) {
hsq->next_tag = tag;
hsq->tail_tag = tag;
hsq->tag_slot[hsq->tail_tag] = HSQ_INVALID_TAG;
} else {
hsq->tag_slot[hsq->tail_tag] = tag;
hsq->tail_tag = tag;
}
hsq->qcnt++;
@ -339,8 +324,10 @@ static const struct mmc_cqe_ops mmc_hsq_ops = {
int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
{
int i;
hsq->num_slots = HSQ_NUM_SLOTS;
hsq->next_tag = HSQ_INVALID_TAG;
hsq->tail_tag = HSQ_INVALID_TAG;
hsq->slot = devm_kcalloc(mmc_dev(mmc), hsq->num_slots,
sizeof(struct hsq_slot), GFP_KERNEL);
@ -351,6 +338,9 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
hsq->mmc->cqe_private = hsq;
mmc->cqe_ops = &mmc_hsq_ops;
for (i = 0; i < HSQ_NUM_SLOTS; i++)
hsq->tag_slot[i] = HSQ_INVALID_TAG;
INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler);
spin_lock_init(&hsq->lock);
init_waitqueue_head(&hsq->wait_queue);

View File

@ -2,6 +2,9 @@
#ifndef LINUX_MMC_HSQ_H
#define LINUX_MMC_HSQ_H
#define HSQ_NUM_SLOTS 64
#define HSQ_INVALID_TAG HSQ_NUM_SLOTS
struct hsq_slot {
struct mmc_request *mrq;
};
@ -17,6 +20,8 @@ struct mmc_hsq {
int next_tag;
int num_slots;
int qcnt;
int tail_tag;
int tag_slot[HSQ_NUM_SLOTS];
bool enabled;
bool waiting_for_idle;

View File

@ -2256,7 +2256,9 @@ static int mmci_probe(struct amba_device *dev,
pm_runtime_set_autosuspend_delay(&dev->dev, 50);
pm_runtime_use_autosuspend(&dev->dev);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto clk_disable;
pm_runtime_put(&dev->dev);
return 0;

View File

@ -665,7 +665,9 @@ static int moxart_probe(struct platform_device *pdev)
goto out;
dev_set_drvdata(dev, mmc);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto out;
dev_dbg(dev, "IRQ=%d, FIFO is %d bytes\n", irq, host->fifo_width);

View File

@ -452,6 +452,7 @@ struct msdc_host {
struct clk *bus_clk; /* bus clock which used to access register */
struct clk *src_clk_cg; /* msdc source clock control gate */
struct clk *sys_clk_cg; /* msdc subsys clock control gate */
struct clk *crypto_clk; /* msdc crypto clock control gate */
struct clk_bulk_data bulk_clks[MSDC_NR_CLOCKS];
u32 mclk; /* mmc subsystem clock frequency */
u32 src_clk_freq; /* source clock frequency */
@ -552,6 +553,19 @@ static const struct mtk_mmc_compatible mt7622_compat = {
.support_64g = false,
};
static const struct mtk_mmc_compatible mt7986_compat = {
.clk_div_bits = 12,
.recheck_sdio_irq = true,
.hs400_tune = false,
.pad_tune_reg = MSDC_PAD_TUNE0,
.async_fifo = true,
.data_tune = true,
.busy_check = true,
.stop_clk_fix = true,
.enhance_rx = true,
.support_64g = true,
};
static const struct mtk_mmc_compatible mt8135_compat = {
.clk_div_bits = 8,
.recheck_sdio_irq = true,
@ -609,6 +623,7 @@ static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt6795-mmc", .data = &mt6795_compat},
{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
{ .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat},
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
{ .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
@ -735,7 +750,7 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
else
bd[j].bd_info &= ~BDMA_DESC_EOL;
/* checksume need to clear first */
/* checksum need to clear first */
bd[j].bd_info &= ~BDMA_DESC_CHECKSUM;
bd[j].bd_info |= msdc_dma_calcs((u8 *)(&bd[j]), 16) << 8;
}
@ -826,6 +841,7 @@ static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks)
static void msdc_gate_clock(struct msdc_host *host)
{
clk_bulk_disable_unprepare(MSDC_NR_CLOCKS, host->bulk_clks);
clk_disable_unprepare(host->crypto_clk);
clk_disable_unprepare(host->src_clk_cg);
clk_disable_unprepare(host->src_clk);
clk_disable_unprepare(host->bus_clk);
@ -841,6 +857,7 @@ static int msdc_ungate_clock(struct msdc_host *host)
clk_prepare_enable(host->bus_clk);
clk_prepare_enable(host->src_clk);
clk_prepare_enable(host->src_clk_cg);
clk_prepare_enable(host->crypto_clk);
ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks);
if (ret) {
dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n");
@ -1207,12 +1224,10 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
if (!sbc_error && !(events & MSDC_INT_CMDRDY)) {
if (events & MSDC_INT_CMDTMO ||
(cmd->opcode != MMC_SEND_TUNING_BLOCK &&
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
!host->hs400_tuning))
(!mmc_op_tuning(cmd->opcode) && !host->hs400_tuning))
/*
* should not clear fifo/interrupt as the tune data
* may have alreay come when cmd19/cmd21 gets response
* may have already come when cmd19/cmd21 gets response
* CRC error.
*/
msdc_reset_hw(host);
@ -1303,9 +1318,7 @@ static void msdc_cmd_next(struct msdc_host *host,
{
if ((cmd->error &&
!(cmd->error == -EILSEQ &&
(cmd->opcode == MMC_SEND_TUNING_BLOCK ||
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
host->hs400_tuning))) ||
(mmc_op_tuning(cmd->opcode) || host->hs400_tuning))) ||
(mrq->sbc && mrq->sbc->error))
msdc_request_done(host, mrq);
else if (cmd == mrq->sbc)
@ -2656,6 +2669,15 @@ static int msdc_drv_probe(struct platform_device *pdev)
goto host_free;
}
/* only eMMC has crypto property */
if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) {
host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto");
if (IS_ERR(host->crypto_clk))
host->crypto_clk = NULL;
else
mmc->caps2 |= MMC_CAP2_CRYPTO;
}
host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0) {
ret = -EINVAL;

View File

@ -1143,7 +1143,9 @@ static int mxcmci_probe(struct platform_device *pdev)
timer_setup(&host->watchdog, mxcmci_watchdog, 0);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto out_free_dma;
return 0;

View File

@ -1946,7 +1946,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (!ret)
mmc->caps |= MMC_CAP_SDIO_IRQ;
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto err_irq;
if (mmc_pdata(host)->name != NULL) {
ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);

View File

@ -763,7 +763,12 @@ static int pxamci_probe(struct platform_device *pdev)
dev_warn(dev, "gpio_ro and get_ro() both defined\n");
}
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret) {
if (host->pdata && host->pdata->exit)
host->pdata->exit(dev, mmc);
goto out;
}
return 0;

View File

@ -38,12 +38,15 @@ struct renesas_sdhi_of_data {
#define SDHI_CALIB_TABLE_MAX 32
#define sdhi_has_quirk(p, q) ((p)->quirks && (p)->quirks->q)
struct renesas_sdhi_quirks {
bool hs400_disabled;
bool hs400_4taps;
bool fixed_addr_mode;
bool dma_one_rx_only;
bool manual_tap_correction;
bool old_info1_layout;
u32 hs400_bad_taps;
const u8 (*hs400_calib_table)[SDHI_CALIB_TABLE_MAX];
};
@ -53,12 +56,17 @@ struct renesas_sdhi_of_data_with_quirks {
const struct renesas_sdhi_quirks *quirks;
};
struct tmio_mmc_dma {
/* We want both end_flags to be set before we mark DMA as finished */
#define SDHI_DMA_END_FLAG_DMA 0
#define SDHI_DMA_END_FLAG_ACCESS 1
struct renesas_sdhi_dma {
unsigned long end_flags;
enum dma_slave_buswidth dma_buswidth;
bool (*filter)(struct dma_chan *chan, void *arg);
void (*enable)(struct tmio_mmc_host *host, bool enable);
struct completion dma_dataend;
struct tasklet_struct dma_complete;
struct completion dma_dataend;
struct tasklet_struct dma_complete;
};
struct renesas_sdhi {
@ -66,7 +74,7 @@ struct renesas_sdhi {
struct clk *clkh;
struct clk *clk_cd;
struct tmio_mmc_data mmc_data;
struct tmio_mmc_dma dma_priv;
struct renesas_sdhi_dma dma_priv;
const struct renesas_sdhi_quirks *quirks;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default, *pins_uhs;

View File

@ -141,7 +141,7 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
if (priv->clkh) {
/* HS400 with 4TAP needs different clock settings */
bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
bool use_4tap = sdhi_has_quirk(priv, hs400_4taps);
bool need_slow_clkh = host->mmc->ios.timing == MMC_TIMING_MMC_HS400;
clkh_shift = use_4tap && need_slow_clkh ? 1 : 2;
ref_clk = priv->clkh;
@ -383,7 +383,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
struct tmio_mmc_host *host = mmc_priv(mmc);
struct renesas_sdhi *priv = host_to_priv(host);
u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0;
bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
bool use_4tap = sdhi_has_quirk(priv, hs400_4taps);
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
@ -395,7 +395,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF,
priv->scc_tappos_hs400);
if (priv->quirks && priv->quirks->manual_tap_correction)
if (sdhi_has_quirk(priv, manual_tap_correction))
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));
@ -546,7 +546,7 @@ 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)
if (sdhi_has_quirk(priv, hs400_calib_table) || sdhi_has_quirk(priv, hs400_bad_taps))
renesas_sdhi_adjust_hs400_mode_disable(host);
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
@ -732,7 +732,7 @@ static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
/* Change TAP position according to correction status */
if (priv->quirks && priv->quirks->manual_tap_correction &&
if (sdhi_has_quirk(priv, manual_tap_correction) &&
host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0;
/*
@ -796,7 +796,7 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host,
struct mmc_request *mrq)
{
struct renesas_sdhi *priv = host_to_priv(host);
bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
bool use_4tap = sdhi_has_quirk(priv, hs400_4taps);
bool ret = false;
/*
@ -908,7 +908,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
{
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
struct tmio_mmc_data *mmc_data;
struct tmio_mmc_dma *dma_priv;
struct renesas_sdhi_dma *dma_priv;
struct tmio_mmc_host *host;
struct renesas_sdhi *priv;
int num_irqs, irq, ret, i;
@ -990,7 +990,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
host->dma_ops = dma_ops;
if (quirks && quirks->hs400_disabled)
if (sdhi_has_quirk(priv, hs400_disabled))
host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
/* For some SoC, we disable internal WP. GPIO may override this */
@ -1018,7 +1018,6 @@ int renesas_sdhi_probe(struct platform_device *pdev,
dma_priv->filter = shdma_chan_filter;
dma_priv->enable = renesas_sdhi_enable_dma;
mmc_data->alignment_shift = 1; /* 2-byte alignment */
mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED;
/*
@ -1056,7 +1055,7 @@ 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) {
if (ver == SDHI_VER_GEN3_SDMMC && sdhi_has_quirk(priv, hs400_calib_table)) {
host->fixup_request = renesas_sdhi_fixup_request;
priv->adjust_hs400_calib_table = *(
res->start == SDHI_GEN3_MMC0_ADDR ?
@ -1068,13 +1067,15 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (ver >= SDHI_VER_GEN3_SD)
host->get_timeout_cycles = renesas_sdhi_gen3_get_cycles;
/* Check for SCC so we can reset it if needed */
if (of_data && of_data->scc_offset && ver >= SDHI_VER_GEN2_SDR104)
priv->scc_ctl = host->ctl + of_data->scc_offset;
/* Enable tuning iff we have an SCC and a supported mode */
if (of_data && of_data->scc_offset &&
(host->mmc->caps & MMC_CAP_UHS_SDR104 ||
host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR |
MMC_CAP2_HS400_1_8V))) {
if (priv->scc_ctl && (host->mmc->caps & MMC_CAP_UHS_SDR104 ||
host->mmc->caps2 & MMC_CAP2_HSX00_1_8V)) {
const struct renesas_sdhi_scc *taps = of_data->taps;
bool use_4tap = quirks && quirks->hs400_4taps;
bool use_4tap = sdhi_has_quirk(priv, hs400_4taps);
bool hit = false;
for (i = 0; i < of_data->taps_num; i++) {
@ -1092,7 +1093,6 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (!hit)
dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n");
priv->scc_ctl = host->ctl + of_data->scc_offset;
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;

View File

@ -47,9 +47,9 @@
#define RST_RESERVED_BITS GENMASK_ULL(31, 0)
/* DM_CM_INFO1 and DM_CM_INFO1_MASK */
#define INFO1_CLEAR 0
#define INFO1_MASK_CLEAR GENMASK_ULL(31, 0)
#define INFO1_DTRANEND1 BIT(17)
#define INFO1_DTRANEND1 BIT(20)
#define INFO1_DTRANEND1_OLD BIT(17)
#define INFO1_DTRANEND0 BIT(16)
/* DM_CM_INFO2 and DM_CM_INFO2_MASK */
@ -165,6 +165,7 @@ static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400_one_rx = {
.hs400_disabled = true,
.hs400_4taps = true,
.dma_one_rx_only = true,
.old_info1_layout = true,
};
static const struct renesas_sdhi_quirks sdhi_quirks_4tap = {
@ -279,24 +280,18 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
};
MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
static void
renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host *host,
int addr, u64 val)
{
writeq(val, host->ctl + addr);
}
static void
renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable)
{
struct renesas_sdhi *priv = host_to_priv(host);
u32 dma_irqs = INFO1_DTRANEND0 |
(sdhi_has_quirk(priv, old_info1_layout) ?
INFO1_DTRANEND1_OLD : INFO1_DTRANEND1);
if (!host->chan_tx || !host->chan_rx)
return;
if (!enable)
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1,
INFO1_CLEAR);
writel(enable ? ~dma_irqs : INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK);
if (priv->dma_priv.enable)
priv->dma_priv.enable(host, enable);
@ -309,22 +304,44 @@ renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host)
renesas_sdhi_internal_dmac_enable_dma(host, false);
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
RST_RESERVED_BITS & ~val);
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
RST_RESERVED_BITS | val);
writel(RST_RESERVED_BITS & ~val, host->ctl + DM_CM_RST);
writel(RST_RESERVED_BITS | val, host->ctl + DM_CM_RST);
clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
renesas_sdhi_internal_dmac_enable_dma(host, true);
}
static bool renesas_sdhi_internal_dmac_dma_irq(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
struct renesas_sdhi_dma *dma_priv = &priv->dma_priv;
u32 dma_irqs = INFO1_DTRANEND0 |
(sdhi_has_quirk(priv, old_info1_layout) ?
INFO1_DTRANEND1_OLD : INFO1_DTRANEND1);
u32 status = readl(host->ctl + DM_CM_INFO1);
if (status & dma_irqs) {
writel(status ^ dma_irqs, host->ctl + DM_CM_INFO1);
set_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags);
if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags))
tasklet_schedule(&dma_priv->dma_complete);
}
return status & dma_irqs;
}
static void
renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
struct renesas_sdhi_dma *dma_priv = &priv->dma_priv;
tasklet_schedule(&priv->dma_priv.dma_complete);
set_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags);
if (test_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags) ||
host->data->error)
tasklet_schedule(&dma_priv->dma_complete);
}
/*
@ -379,7 +396,7 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
struct scatterlist *sg = host->sg_ptr;
u32 dtran_mode = DTRAN_MODE_BUS_WIDTH;
if (!(priv->quirks && priv->quirks->fixed_addr_mode))
if (!sdhi_has_quirk(priv, fixed_addr_mode))
dtran_mode |= DTRAN_MODE_ADDR_MODE;
if (!renesas_sdhi_internal_dmac_map(host, data, COOKIE_MAPPED))
@ -387,20 +404,19 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
if (data->flags & MMC_DATA_READ) {
dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
if (priv->quirks && priv->quirks->dma_one_rx_only &&
if (sdhi_has_quirk(priv, dma_one_rx_only) &&
test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
goto force_pio_with_unmap;
} else {
dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
}
priv->dma_priv.end_flags = 0;
renesas_sdhi_internal_dmac_enable_dma(host, true);
/* set dma parameters */
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
dtran_mode);
renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
sg_dma_address(sg));
writel(dtran_mode, host->ctl + DM_CM_DTRAN_MODE);
writel(sg_dma_address(sg), host->ctl + DM_DTRAN_ADDR);
host->dma_on = true;
@ -416,12 +432,19 @@ force_pio:
static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
{
struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
struct renesas_sdhi *priv = host_to_priv(host);
tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
/* start the DMAC */
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_CTRL,
DTRAN_CTRL_DM_START);
if (!host->cmd->error) {
/* start the DMAC */
writel(DTRAN_CTRL_DM_START, host->ctl + DM_CM_DTRAN_CTRL);
} else {
/* on CMD errors, simulate DMA end immediately */
set_bit(SDHI_DMA_END_FLAG_DMA, &priv->dma_priv.end_flags);
if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &priv->dma_priv.end_flags))
tasklet_schedule(&priv->dma_priv.dma_complete);
}
}
static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host)
@ -501,11 +524,11 @@ renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
{
struct renesas_sdhi *priv = host_to_priv(host);
/* Disable DMAC interrupts, we don't use them */
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1_MASK,
INFO1_MASK_CLEAR);
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO2_MASK,
INFO2_MASK_CLEAR);
/* Disable DMAC interrupts initially */
writel(INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK);
writel(INFO2_MASK_CLEAR, host->ctl + DM_CM_INFO2_MASK);
writel(0, host->ctl + DM_CM_INFO1);
writel(0, host->ctl + DM_CM_INFO2);
/* Each value is set to non-zero to assume "enabling" each DMA */
host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
@ -537,6 +560,7 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
.abort = renesas_sdhi_internal_dmac_abort_dma,
.dataend = renesas_sdhi_internal_dmac_dataend_dma,
.end = renesas_sdhi_internal_dmac_end_dma,
.dma_irq = renesas_sdhi_internal_dmac_dma_irq,
};
static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)

View File

@ -160,7 +160,7 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)
dma_cookie_t cookie;
int ret, i;
bool aligned = true, multiple = true;
unsigned int align = (1 << host->pdata->alignment_shift) - 1;
unsigned int align = 1; /* 2-byte alignment */
for_each_sg(sg, sg_tmp, host->sg_len, i) {
if (sg_tmp->offset & align)
@ -232,7 +232,7 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
dma_cookie_t cookie;
int ret, i;
bool aligned = true, multiple = true;
unsigned int align = (1 << host->pdata->alignment_shift) - 1;
unsigned int align = 1; /* 2-byte alignment */
for_each_sg(sg, sg_tmp, host->sg_len, i) {
if (sg_tmp->offset & align)
@ -254,12 +254,11 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
/* The only sg element can be unaligned, use our bounce buffer then */
if (!aligned) {
unsigned long flags;
void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
void *sg_vaddr = kmap_local_page(sg_page(sg));
sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
memcpy(host->bounce_buf, sg_vaddr + sg->offset, host->bounce_sg.length);
kunmap_local(sg_vaddr);
host->sg_ptr = &host->bounce_sg;
sg = host->sg_ptr;
}

View File

@ -1474,6 +1474,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
struct realtek_pci_sdmmc *host;
struct rtsx_pcr *pcr;
struct pcr_handle *handle = pdev->dev.platform_data;
int ret;
if (!handle)
return -ENXIO;
@ -1511,7 +1512,13 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret) {
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_disable(&pdev->dev);
mmc_free_host(mmc);
return ret;
}
return 0;
}

View File

@ -1329,6 +1329,7 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
#ifdef RTSX_USB_USE_LEDS_CLASS
int err;
#endif
int ret;
ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent));
if (!ucr)
@ -1365,7 +1366,15 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
INIT_WORK(&host->led_work, rtsx_usb_update_led);
#endif
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret) {
#ifdef RTSX_USB_USE_LEDS_CLASS
led_classdev_unregister(&host->led);
#endif
mmc_free_host(mmc);
pm_runtime_disable(&pdev->dev);
return ret;
}
return 0;
}

View File

@ -648,10 +648,10 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev,
* 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.
* instead use 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).
* firmware that has valid presets (i.e., SDR12 <= 12 MHz).
*/
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;

View File

@ -168,7 +168,7 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
/*
* JEDEC and SD spec specify supplying 74 continuous clocks to
* device after power up. With minimum bus (100KHz) that
* that translates to 740us
* translates to 740us
*/
if (power_mode != MMC_POWER_OFF)
udelay(740);

View File

@ -179,7 +179,7 @@ static const struct brcmstb_match_priv match_priv_7216 = {
.ops = &sdhci_brcmstb_ops_7216,
};
static const struct of_device_id sdhci_brcm_of_match[] = {
static const struct of_device_id __maybe_unused sdhci_brcm_of_match[] = {
{ .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
{ .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
{ .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },

View File

@ -307,7 +307,8 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = {
| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
};
static struct esdhc_soc_data usdhc_imxrt1050_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_HS200 | ESDHC_FLAG_ERR004536,
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
};
static struct esdhc_soc_data usdhc_imx8qxp_data = {
@ -1012,6 +1013,44 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
SDHCI_HOST_CONTROL);
}
static void esdhc_reset_tuning(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 ctrl;
int ret;
/* Reset the tuning circuit */
if (esdhc_is_usdhc(imx_data)) {
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE;
writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
/* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */
ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS,
ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50);
if (ret == -ETIMEDOUT)
dev_warn(mmc_dev(host->mmc),
"Warning! clear execute tuning bit failed\n");
/*
* SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the
* usdhc IP internal logic flag execute_tuning_with_clr_buf, which
* will finally make sure the normal data transfer logic correct.
*/
ctrl = readl(host->ioaddr + SDHCI_INT_STATUS);
ctrl |= SDHCI_INT_DATA_AVAIL;
writel(ctrl, host->ioaddr + SDHCI_INT_STATUS);
}
}
}
static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
@ -1023,6 +1062,12 @@ static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (host->timing == MMC_TIMING_UHS_DDR50)
return 0;
/*
* Reset tuning circuit logic. If not, the previous tuning result
* will impact current tuning, make current tuning can't set the
* correct delay cell.
*/
esdhc_reset_tuning(host);
return sdhci_execute_tuning(mmc, opcode);
}
@ -1196,44 +1241,6 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
"warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v);
}
static void esdhc_reset_tuning(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 ctrl;
int ret;
/* Reset the tuning circuit */
if (esdhc_is_usdhc(imx_data)) {
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE;
writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
/* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */
ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS,
ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50);
if (ret == -ETIMEDOUT)
dev_warn(mmc_dev(host->mmc),
"Warning! clear execute tuning bit failed\n");
/*
* SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the
* usdhc IP internal logic flag execute_tuning_with_clr_buf, which
* will finally make sure the normal data transfer logic correct.
*/
ctrl = readl(host->ioaddr + SDHCI_INT_STATUS);
ctrl |= SDHCI_INT_DATA_AVAIL;
writel(ctrl, host->ioaddr + SDHCI_INT_STATUS);
}
}
}
static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
{
u32 m;
@ -1454,7 +1461,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
/*
* On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card
* as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the
* as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let
* the 1st linux configure power/clock for the 2nd Linux.
*
* When the 2nd Linux is booting into rootfs stage, we let the 1st Linux

View File

@ -19,6 +19,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/reset.h>
#include "sdhci-cqhci.h"
#include "sdhci-pltfm.h"
#include "cqhci.h"
@ -2218,8 +2219,7 @@ static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
if (!msm_host->use_cdr)
break;
if ((msm_host->transfer_mode & SDHCI_TRNS_READ) &&
SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200 &&
SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK)
!mmc_op_tuning(SDHCI_GET_CMD(val)))
sdhci_msm_set_cdr(host, true);
else
sdhci_msm_set_cdr(host, false);
@ -2304,13 +2304,6 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host)
pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
}
static void sdhci_msm_reset(struct sdhci_host *host, u8 mask)
{
if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL))
cqhci_deactivate(host->mmc);
sdhci_reset(host, mask);
}
static int sdhci_msm_register_vreg(struct sdhci_msm_host *msm_host)
{
int ret;
@ -2450,7 +2443,7 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
static const struct sdhci_ops sdhci_msm_ops = {
.reset = sdhci_msm_reset,
.reset = sdhci_and_cqhci_reset,
.set_clock = sdhci_msm_set_clock,
.get_min_clock = sdhci_msm_get_min_clock,
.get_max_clock = sdhci_msm_get_max_clock,

View File

@ -21,6 +21,7 @@
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/of.h>
#include <linux/firmware/xlnx-zynqmp.h>
@ -1522,6 +1523,65 @@ static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan,
return 0;
}
static int sdhci_zynqmp_set_dynamic_config(struct device *dev,
struct sdhci_arasan_data *sdhci_arasan)
{
struct sdhci_host *host = sdhci_arasan->host;
struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
const char *clk_name = clk_hw_get_name(hw);
u32 mhz, node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1;
struct reset_control *rstc;
int ret;
/* Obtain SDHC reset control */
rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
if (IS_ERR(rstc)) {
dev_err(dev, "Cannot get SDHC reset.\n");
return PTR_ERR(rstc);
}
ret = reset_control_assert(rstc);
if (ret)
return ret;
ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_FIXED, 0);
if (ret)
return ret;
ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_EMMC_SEL,
!!(host->mmc->caps & MMC_CAP_NONREMOVABLE));
if (ret)
return ret;
mhz = DIV_ROUND_CLOSEST_ULL(clk_get_rate(pltfm_host->clk), 1000000);
if (mhz > 100 && mhz <= 200)
mhz = 200;
else if (mhz > 50 && mhz <= 100)
mhz = 100;
else if (mhz > 25 && mhz <= 50)
mhz = 50;
else
mhz = 25;
ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_BASECLK, mhz);
if (ret)
return ret;
ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_8BIT,
!!(host->mmc->caps & MMC_CAP_8_BIT_DATA));
if (ret)
return ret;
ret = reset_control_deassert(rstc);
if (ret)
return ret;
usleep_range(1000, 1500);
return 0;
}
static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan)
{
struct sdhci_host *host = sdhci_arasan->host;
@ -1686,6 +1746,15 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
goto unreg_clk;
}
if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_SD_CONFIG);
if (!ret) {
ret = sdhci_zynqmp_set_dynamic_config(dev, sdhci_arasan);
if (ret)
goto unreg_clk;
}
}
sdhci_arasan->phy = ERR_PTR(-ENODEV);
if (of_device_is_compatible(np, "arasan,sdhci-5.1")) {
sdhci_arasan->phy = devm_phy_get(dev, "phy_arasan");

View File

@ -42,6 +42,12 @@ static const struct esdhc_clk_fixup ls1021a_esdhc_clk = {
.max_clk[MMC_TIMING_SD_HS] = 46500000,
};
static const struct esdhc_clk_fixup ls1043a_esdhc_clk = {
.sd_dflt_max_clk = 25000000,
.max_clk[MMC_TIMING_UHS_SDR104] = 116700000,
.max_clk[MMC_TIMING_MMC_HS200] = 116700000,
};
static const struct esdhc_clk_fixup ls1046a_esdhc_clk = {
.sd_dflt_max_clk = 25000000,
.max_clk[MMC_TIMING_UHS_SDR104] = 167000000,
@ -63,6 +69,7 @@ static const struct esdhc_clk_fixup p1010_esdhc_clk = {
static const struct of_device_id sdhci_esdhc_of_match[] = {
{ .compatible = "fsl,ls1021a-esdhc", .data = &ls1021a_esdhc_clk},
{ .compatible = "fsl,ls1043a-esdhc", .data = &ls1043a_esdhc_clk},
{ .compatible = "fsl,ls1046a-esdhc", .data = &ls1046a_esdhc_clk},
{ .compatible = "fsl,ls1012a-esdhc", .data = &ls1012a_esdhc_clk},
{ .compatible = "fsl,p1010-esdhc", .data = &p1010_esdhc_clk},
@ -91,7 +98,7 @@ struct sdhci_esdhc {
};
/**
* esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register
* esdhc_readl_fixup - Fixup the value read from incompatible eSDHC register
* to make it compatible with SD spec.
*
* @host: pointer to sdhci_host
@ -216,7 +223,7 @@ static u8 esdhc_readb_fixup(struct sdhci_host *host,
}
/**
* esdhc_write*_fixup - Fixup the SD spec register value so that it could be
* esdhc_writel_fixup - Fixup the SD spec register value so that it could be
* written into eSDHC register.
*
* @host: pointer to sdhci_host

View File

@ -370,7 +370,7 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
/*
* Stage 1: Search for a maximum pass window ignoring any
* any single point failures. If the tuning value ends up
* single point failures. If the tuning value ends up
* near it, move away from it in stage 2 below
*/
while (phase_delay <= MAX_PHASE_DELAY) {

View File

@ -38,6 +38,7 @@
#include "cqhci.h"
#include "sdhci.h"
#include "sdhci-cqhci.h"
#include "sdhci-pci.h"
static void sdhci_pci_hw_reset(struct sdhci_host *host);
@ -234,14 +235,6 @@ static void sdhci_pci_dumpregs(struct mmc_host *mmc)
sdhci_dumpregs(mmc_priv(mmc));
}
static void sdhci_cqhci_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);
}
/*****************************************************************************\
* *
* Hardware specific quirk handling *
@ -703,7 +696,7 @@ static const struct sdhci_ops sdhci_intel_glk_ops = {
.set_power = sdhci_intel_set_power,
.enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_cqhci_reset,
.reset = sdhci_and_cqhci_reset,
.set_uhs_signaling = sdhci_intel_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset,
.irq = sdhci_cqhci_irq,
@ -2283,7 +2276,8 @@ static struct pci_driver sdhci_driver = {
.probe = sdhci_pci_probe,
.remove = sdhci_pci_remove,
.driver = {
.pm = &sdhci_pci_pm_ops
.pm = &sdhci_pci_pm_ops,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};

View File

@ -15,6 +15,7 @@
#include <linux/of.h>
#include <linux/iopoll.h>
#include "sdhci.h"
#include "sdhci-cqhci.h"
#include "sdhci-pci.h"
#include "cqhci.h"
@ -922,14 +923,6 @@ cleanup:
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;
@ -1136,7 +1129,7 @@ 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_gl9763e_reset,
.reset = sdhci_and_cqhci_reset,
.set_uhs_signaling = sdhci_set_gl9763e_signaling,
.voltage_switch = sdhci_gli_voltage_switch,
.irq = sdhci_gl9763e_cqhci_irq,

View File

@ -326,8 +326,7 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
(host->timing != MMC_TIMING_UHS_SDR50))
return sdhci_execute_tuning(mmc, opcode);
if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
(opcode != MMC_SEND_TUNING_BLOCK)))
if (WARN_ON(!mmc_op_tuning(opcode)))
return -EINVAL;
/* Force power mode enter L0 */

View File

@ -228,13 +228,15 @@ static inline void _sdhci_sprd_set_clock(struct sdhci_host *host,
div = ((div & 0x300) >> 2) | ((div & 0xFF) << 8);
sdhci_enable_clk(host, div);
/* enable auto gate sdhc_enable_auto_gate */
val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI);
mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN |
SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN;
if (mask != (val & mask)) {
val |= mask;
sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI);
/* Enable CLK_AUTO when the clock is greater than 400K. */
if (clk > 400000) {
val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI);
mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN |
SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN;
if (mask != (val & mask)) {
val |= mask;
sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI);
}
}
}

View File

@ -3,28 +3,30 @@
* Copyright (C) 2010 Google, Inc.
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/iopoll.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/iommu.h>
#include <linux/iopoll.h>
#include <linux/ktime.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <soc/tegra/common.h>
@ -95,6 +97,8 @@
#define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec
#define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31)
#define SDHCI_TEGRA_CIF2AXI_CTRL_0 0x1fc
#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
@ -122,6 +126,7 @@
#define NVQUIRK_HAS_TMCLK BIT(10)
#define NVQUIRK_HAS_ANDROID_GPT_SECTOR BIT(11)
#define NVQUIRK_PROGRAM_STREAMID BIT(12)
/* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */
#define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000
@ -178,6 +183,7 @@ struct sdhci_tegra {
bool enable_hwcq;
unsigned long curr_clk_rate;
u8 tuned_tap_delay;
u32 stream_id;
};
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
@ -268,13 +274,9 @@ static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
{
bool is_tuning_cmd = 0;
bool clk_enabled;
u8 cmd;
if (reg == SDHCI_COMMAND) {
cmd = SDHCI_GET_CMD(val);
is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK ||
cmd == MMC_SEND_TUNING_BLOCK_HS200;
}
if (reg == SDHCI_COMMAND)
is_tuning_cmd = mmc_op_tuning(SDHCI_GET_CMD(val));
if (is_tuning_cmd)
clk_enabled = tegra_sdhci_configure_card_clk(host, 0);
@ -1526,7 +1528,8 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER,
.ops = &tegra186_sdhci_ops,
};
@ -1557,7 +1560,22 @@ static const struct sdhci_tegra_soc_data soc_data_tegra194 = {
.max_tap_delay = 139,
};
static const struct sdhci_tegra_soc_data soc_data_tegra234 = {
.pdata = &sdhci_tegra186_pdata,
.dma_mask = DMA_BIT_MASK(39),
.nvquirks = NVQUIRK_NEEDS_PAD_CONTROL |
NVQUIRK_HAS_PADCALIB |
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_SDR104 |
NVQUIRK_PROGRAM_STREAMID |
NVQUIRK_HAS_TMCLK,
.min_tap_delay = 95,
.max_tap_delay = 111,
};
static const struct of_device_id sdhci_tegra_dt_match[] = {
{ .compatible = "nvidia,tegra234-sdhci", .data = &soc_data_tegra234 },
{ .compatible = "nvidia,tegra194-sdhci", .data = &soc_data_tegra194 },
{ .compatible = "nvidia,tegra186-sdhci", .data = &soc_data_tegra186 },
{ .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 },
@ -1617,6 +1635,19 @@ cleanup:
return ret;
}
/* Program MC streamID for DMA transfers */
static void sdhci_tegra_program_stream_id(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
if (tegra_host->soc_data->nvquirks & NVQUIRK_PROGRAM_STREAMID) {
tegra_sdhci_writel(host, FIELD_PREP(GENMASK(15, 8), tegra_host->stream_id) |
FIELD_PREP(GENMASK(7, 0), tegra_host->stream_id),
SDHCI_TEGRA_CIF2AXI_CTRL_0);
}
}
static int sdhci_tegra_probe(struct platform_device *pdev)
{
const struct sdhci_tegra_soc_data *soc_data;
@ -1677,6 +1708,12 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
tegra_sdhci_parse_dt(host);
if (tegra_host->soc_data->nvquirks & NVQUIRK_PROGRAM_STREAMID &&
!tegra_dev_iommu_get_stream_id(&pdev->dev, &tegra_host->stream_id)) {
dev_warn(mmc_dev(host->mmc), "missing IOMMU stream ID\n");
tegra_host->stream_id = 0x7f;
}
tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
GPIOD_OUT_HIGH);
if (IS_ERR(tegra_host->power_gpio)) {
@ -1762,6 +1799,8 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
if (rc)
goto err_add_host;
sdhci_tegra_program_stream_id(host);
return 0;
err_add_host:
@ -1858,6 +1897,8 @@ static int sdhci_tegra_resume(struct device *dev)
if (ret)
return ret;
sdhci_tegra_program_stream_id(host);
ret = sdhci_resume_host(host);
if (ret)
goto disable_clk;

View File

@ -270,6 +270,11 @@ enum sdhci_reset_reason {
static void sdhci_reset_for_reason(struct sdhci_host *host, enum sdhci_reset_reason reason)
{
if (host->quirks2 & SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER) {
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
return;
}
switch (reason) {
case SDHCI_RESET_FOR_INIT:
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
@ -526,7 +531,6 @@ static inline bool sdhci_has_requests(struct sdhci_host *host)
static void sdhci_read_block_pio(struct sdhci_host *host)
{
unsigned long flags;
size_t blksize, len, chunk;
u32 scratch;
u8 *buf;
@ -536,8 +540,6 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
blksize = host->data->blksz;
chunk = 0;
local_irq_save(flags);
while (blksize) {
BUG_ON(!sg_miter_next(&host->sg_miter));
@ -564,13 +566,10 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
}
sg_miter_stop(&host->sg_miter);
local_irq_restore(flags);
}
static void sdhci_write_block_pio(struct sdhci_host *host)
{
unsigned long flags;
size_t blksize, len, chunk;
u32 scratch;
u8 *buf;
@ -581,8 +580,6 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
chunk = 0;
scratch = 0;
local_irq_save(flags);
while (blksize) {
BUG_ON(!sg_miter_next(&host->sg_miter));
@ -609,8 +606,6 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
}
sg_miter_stop(&host->sg_miter);
local_irq_restore(flags);
}
static void sdhci_transfer_pio(struct sdhci_host *host)
@ -706,16 +701,14 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host,
return sg_count;
}
static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
static char *sdhci_kmap_atomic(struct scatterlist *sg)
{
local_irq_save(*flags);
return kmap_atomic(sg_page(sg)) + sg->offset;
return kmap_local_page(sg_page(sg)) + sg->offset;
}
static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
static void sdhci_kunmap_atomic(void *buffer)
{
kunmap_atomic(buffer);
local_irq_restore(*flags);
kunmap_local(buffer);
}
void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
@ -757,7 +750,6 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
struct mmc_data *data, int sg_count)
{
struct scatterlist *sg;
unsigned long flags;
dma_addr_t addr, align_addr;
void *desc, *align;
char *buffer;
@ -789,9 +781,9 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
SDHCI_ADMA2_MASK;
if (offset) {
if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, &flags);
buffer = sdhci_kmap_atomic(sg);
memcpy(align, buffer, offset);
sdhci_kunmap_atomic(buffer, &flags);
sdhci_kunmap_atomic(buffer);
}
/* tran, valid */
@ -852,7 +844,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
int i, size;
void *align;
char *buffer;
unsigned long flags;
if (data->flags & MMC_DATA_READ) {
bool has_unaligned = false;
@ -875,9 +866,9 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
size = SDHCI_ADMA2_ALIGN -
(sg_dma_address(sg) & SDHCI_ADMA2_MASK);
buffer = sdhci_kmap_atomic(sg, &flags);
buffer = sdhci_kmap_atomic(sg);
memcpy(buffer, align, size);
sdhci_kunmap_atomic(buffer, &flags);
sdhci_kunmap_atomic(buffer);
align += SDHCI_ADMA2_ALIGN;
}
@ -1466,7 +1457,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
if (host->quirks2 &
SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) {
/* must not clear SDHCI_TRANSFER_MODE when tuning */
if (cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)
if (!mmc_op_tuning(cmd->opcode))
sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
} else {
/* clear Auto CMD settings for no data CMDs */
@ -1707,8 +1698,7 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
flags |= SDHCI_CMD_INDEX;
/* CMD19 is special in that the Data Present Select should be set */
if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
if (cmd->data || mmc_op_tuning(cmd->opcode))
flags |= SDHCI_CMD_DATA;
timeout = jiffies;
@ -2304,7 +2294,7 @@ static bool sdhci_timing_has_preset(unsigned char timing)
case MMC_TIMING_UHS_DDR50:
case MMC_TIMING_MMC_DDR52:
return true;
};
}
return false;
}
@ -2418,8 +2408,21 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->version >= SDHCI_SPEC_300) {
u16 clk, ctrl_2;
/*
* According to SDHCI Spec v3.00, if the Preset Value
* Enable in the Host Control 2 register is set, we
* need to reset SD Clock Enable before changing High
* Speed Enable to avoid generating clock glitches.
*/
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
if (clk & SDHCI_CLOCK_CARD_EN) {
clk &= ~SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
if (!host->preset_enabled) {
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
/*
* We only need to set Driver Strength if the
* preset value enable is not set.
@ -2442,30 +2445,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
host->drv_type = ios->drv_type;
} else {
/*
* According to SDHC Spec v3.00, if the Preset Value
* Enable in the Host Control 2 register is set, we
* need to reset SD Clock Enable before changing High
* Speed Enable to avoid generating clock gliches.
*/
/* Reset SD Clock Enable */
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clk &= ~SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
/* Re-enable SD Clock */
host->ops->set_clock(host, host->clock);
}
/* Reset SD Clock Enable */
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clk &= ~SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
host->ops->set_uhs_signaling(host, ios->timing);
host->timing = ios->timing;
@ -3388,8 +3369,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
{
u32 command;
/*
* CMD19 generates _only_ Buffer Read Ready interrupt if
* use sdhci_send_tuning.
@ -3398,9 +3377,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
* SDHCI_INT_DATA_AVAIL always there, stuck in irq storm.
*/
if (intmask & SDHCI_INT_DATA_AVAIL && !host->data) {
command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
if (command == MMC_SEND_TUNING_BLOCK ||
command == MMC_SEND_TUNING_BLOCK_HS200) {
if (mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) {
host->tuning_done = 1;
wake_up(&host->buf_ready_int);
return;

View File

@ -345,7 +345,7 @@ struct sdhci_adma2_64_desc {
*/
#define SDHCI_MAX_SEGS 128
/* Allow for a a command request and a data request at the same time */
/* Allow for a command request and a data request at the same time */
#define SDHCI_MAX_MRQS 2
/*
@ -478,6 +478,8 @@ struct sdhci_host {
* block count.
*/
#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18)
/* Issue CMD and DATA reset together */
#define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */

View File

@ -836,7 +836,7 @@ static int sdhci_am654_probe(struct platform_device *pdev)
ret = mmc_of_parse(host->mmc);
if (ret) {
dev_err(dev, "parsing dt failed (%d)\n", ret);
dev_err_probe(dev, ret, "parsing dt failed\n");
goto pm_runtime_put;
}

View File

@ -5,6 +5,7 @@
* Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd
* Vincent Yang <vincent.yang@tw.fujitsu.com>
* Copyright (C) 2015 Linaro Ltd Andy Green <andy.green@linaro.org>
* Copyright (C) 2019 Socionext Inc.
*/
#include <linux/acpi.h>
@ -14,6 +15,7 @@
#include <linux/of.h>
#include <linux/property.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include "sdhci-pltfm.h"
#include "sdhci_f_sdh30.h"
@ -21,6 +23,7 @@
struct f_sdhost_priv {
struct clk *clk_iface;
struct clk *clk;
struct reset_control *rst;
u32 vendor_hs200;
struct device *dev;
bool enable_cmd_dat_delay;
@ -74,6 +77,13 @@ static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask)
ctl |= F_SDH30_CMD_DAT_DELAY;
sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
}
if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) &&
!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
ctl = sdhci_readl(host, F_SDH30_TEST);
ctl |= F_SDH30_FORCE_CARD_INSERT;
sdhci_writel(host, ctl, F_SDH30_TEST);
}
}
static const struct sdhci_ops sdhci_f_sdh30_ops = {
@ -150,6 +160,16 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
ret = clk_prepare_enable(priv->clk);
if (ret)
goto err_clk;
priv->rst = devm_reset_control_get_optional_shared(dev, NULL);
if (IS_ERR(priv->rst)) {
ret = PTR_ERR(priv->rst);
goto err_rst;
}
ret = reset_control_deassert(priv->rst);
if (ret)
goto err_rst;
}
/* init vendor specific regs */
@ -168,6 +188,9 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
if (reg & SDHCI_CAN_DO_8BIT)
priv->vendor_hs200 = F_SDH30_EMMC_HS200;
if (!(reg & SDHCI_TIMEOUT_CLK_MASK))
host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
ret = sdhci_add_host(host);
if (ret)
goto err_add_host;
@ -175,6 +198,8 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
return 0;
err_add_host:
reset_control_assert(priv->rst);
err_rst:
clk_disable_unprepare(priv->clk);
err_clk:
clk_disable_unprepare(priv->clk_iface);
@ -191,8 +216,9 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev)
sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
0xffffffff);
clk_disable_unprepare(priv->clk_iface);
reset_control_assert(priv->rst);
clk_disable_unprepare(priv->clk);
clk_disable_unprepare(priv->clk_iface);
sdhci_free_host(host);
platform_set_drvdata(pdev, NULL);
@ -203,6 +229,7 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id f_sdh30_dt_ids[] = {
{ .compatible = "fujitsu,mb86s70-sdhci-3.0" },
{ .compatible = "socionext,f-sdh30-e51-mmc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids);
@ -232,5 +259,5 @@ module_platform_driver(sdhci_f_sdh30_driver);
MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD.");
MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD., Socionext Inc.");
MODULE_ALIAS("platform:f_sdh30");

View File

@ -29,4 +29,7 @@
#define F_SDH30_CMD_DAT_DELAY BIT(9)
#define F_SDH30_EMMC_HS200 BIT(24)
#define F_SDH30_TEST 0x158
#define F_SDH30_FORCE_CARD_INSERT BIT(6)
#define F_SDH30_MIN_CLOCK 400000

File diff suppressed because it is too large Load Diff

View File

@ -116,7 +116,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
unsigned char *buf;
unsigned int pos = 0, val;
buf = kmap_atomic(pg) + off;
buf = kmap_local_page(pg) + off;
if (host->cmd_flags & DATA_CARRY) {
buf[pos++] = host->bounce_buf_data[0];
host->cmd_flags &= ~DATA_CARRY;
@ -132,7 +132,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
}
buf[pos++] = (val >> 8) & 0xff;
}
kunmap_atomic(buf - off);
kunmap_local(buf - off);
}
static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
@ -142,7 +142,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
unsigned char *buf;
unsigned int pos = 0, val;
buf = kmap_atomic(pg) + off;
buf = kmap_local_page(pg) + off;
if (host->cmd_flags & DATA_CARRY) {
val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
writel(val, sock->addr + SOCK_MMCSD_DATA);
@ -159,7 +159,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
val |= (buf[pos++] << 8) & 0xff00;
writel(val, sock->addr + SOCK_MMCSD_DATA);
}
kunmap_atomic(buf - off);
kunmap_local(buf - off);
}
static void tifm_sd_transfer_data(struct tifm_sd *host)
@ -210,13 +210,13 @@ static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
struct page *src, unsigned int src_off,
unsigned int count)
{
unsigned char *src_buf = kmap_atomic(src) + src_off;
unsigned char *dst_buf = kmap_atomic(dst) + dst_off;
unsigned char *src_buf = kmap_local_page(src) + src_off;
unsigned char *dst_buf = kmap_local_page(dst) + dst_off;
memcpy(dst_buf, src_buf, count);
kunmap_atomic(dst_buf - dst_off);
kunmap_atomic(src_buf - src_off);
kunmap_local(dst_buf - dst_off);
kunmap_local(src_buf - src_off);
}
static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
@ -264,16 +264,13 @@ static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz;
unsigned int dma_len, dma_blk_cnt, dma_off;
struct scatterlist *sg = NULL;
unsigned long flags;
if (host->sg_pos == host->sg_len)
return 1;
if (host->cmd_flags & DATA_CARRY) {
host->cmd_flags &= ~DATA_CARRY;
local_irq_save(flags);
tifm_sd_bounce_block(host, r_data);
local_irq_restore(flags);
if (host->sg_pos == host->sg_len)
return 1;
}
@ -300,11 +297,9 @@ static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
if (dma_blk_cnt)
sg = &r_data->sg[host->sg_pos];
else if (dma_len) {
if (r_data->flags & MMC_DATA_WRITE) {
local_irq_save(flags);
if (r_data->flags & MMC_DATA_WRITE)
tifm_sd_bounce_block(host, r_data);
local_irq_restore(flags);
} else
else
host->cmd_flags |= DATA_CARRY;
sg = &host->bounce_buf;
@ -506,7 +501,6 @@ static void tifm_sd_card_event(struct tifm_dev *sock)
unsigned int host_status = 0;
int cmd_error = 0;
struct mmc_command *cmd = NULL;
unsigned long flags;
spin_lock(&sock->lock);
host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
@ -570,9 +564,7 @@ static void tifm_sd_card_event(struct tifm_dev *sock)
if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
| TIFM_MMCSD_BRS)) {
local_irq_save(flags);
tifm_sd_transfer_data(host);
local_irq_restore(flags);
host_status &= ~TIFM_MMCSD_AE;
}
}

View File

@ -128,6 +128,7 @@ struct tmio_mmc_dma_ops {
/* optional */
void (*end)(struct tmio_mmc_host *host); /* held host->lock */
bool (*dma_irq)(struct tmio_mmc_host *host);
};
struct tmio_mmc_host {
@ -204,20 +205,6 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
irqreturn_t tmio_mmc_irq(int irq, void *devid);
static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
unsigned long *flags)
{
local_irq_save(*flags);
return kmap_atomic(sg_page(sg)) + sg->offset;
}
static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
unsigned long *flags, void *virt)
{
kunmap_atomic(virt - sg->offset);
local_irq_restore(*flags);
}
#ifdef CONFIG_PM
int tmio_mmc_host_runtime_suspend(struct device *dev);
int tmio_mmc_host_runtime_resume(struct device *dev);

View File

@ -412,7 +412,6 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
void *sg_virt;
unsigned short *buf;
unsigned int count;
unsigned long flags;
if (host->dma_on) {
pr_err("PIO IRQ in DMA mode!\n");
@ -422,8 +421,8 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
return;
}
sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags);
buf = (unsigned short *)(sg_virt + host->sg_off);
sg_virt = kmap_local_page(sg_page(host->sg_ptr));
buf = (unsigned short *)(sg_virt + host->sg_ptr->offset + host->sg_off);
count = host->sg_ptr->length - host->sg_off;
if (count > data->blksz)
@ -437,7 +436,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
host->sg_off += count;
tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt);
kunmap_local(sg_virt);
if (host->sg_off == host->sg_ptr->length)
tmio_mmc_next_sg(host);
@ -446,11 +445,11 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host)
{
if (host->sg_ptr == &host->bounce_sg) {
unsigned long flags;
void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags);
void *sg_virt = kmap_local_page(sg_page(host->sg_orig));
memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length);
tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr);
memcpy(sg_virt + host->sg_orig->offset, host->bounce_buf,
host->bounce_sg.length);
kunmap_local(sg_virt);
}
}
@ -670,6 +669,9 @@ static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, int ireg,
return true;
}
if (host->dma_ops && host->dma_ops->dma_irq && host->dma_ops->dma_irq(host))
return true;
return false;
}

View File

@ -651,7 +651,9 @@ static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto unmap;
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto free_irq;
base = pci_resource_start(pdev, 0);
dev_dbg(&pdev->dev, "MMIO %pa, IRQ %d\n", &base, pdev->irq);
@ -660,6 +662,8 @@ static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
free_irq:
free_irq(pdev->irq, host);
unmap:
pci_iounmap(pdev, host->ioaddr);
release:

View File

@ -1151,7 +1151,9 @@ static int via_sd_probe(struct pci_dev *pcidev,
pcidev->subsystem_device == 0x3891)
sdhost->quirks = VIA_CRDR_QUIRK_300MS_PWRDELAY;
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto unmap;
return 0;

View File

@ -2049,6 +2049,7 @@ static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
return;
kref_get(&vub300->kref);
if (enable) {
set_current_state(TASK_RUNNING);
mutex_lock(&vub300->irq_mutex);
if (vub300->irqs_queued) {
vub300->irqs_queued -= 1;
@ -2064,6 +2065,7 @@ static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
vub300_queue_poll_work(vub300, 0);
}
mutex_unlock(&vub300->irq_mutex);
set_current_state(TASK_INTERRUPTIBLE);
} else {
vub300->irq_enabled = 0;
}
@ -2299,14 +2301,14 @@ static int vub300_probe(struct usb_interface *interface,
0x0000, 0x0000, &vub300->system_port_status,
sizeof(vub300->system_port_status), 1000);
if (retval < 0) {
goto error4;
goto error5;
} else if (sizeof(vub300->system_port_status) == retval) {
vub300->card_present =
(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
vub300->read_only =
(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
} else {
goto error4;
goto error5;
}
usb_set_intfdata(interface, vub300);
INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
@ -2329,8 +2331,13 @@ static int vub300_probe(struct usb_interface *interface,
"USB vub300 remote SDIO host controller[%d]"
"connected with no SD/SDIO card inserted\n",
interface_to_InterfaceNumber(interface));
mmc_add_host(mmc);
retval = mmc_add_host(mmc);
if (retval)
goto error6;
return 0;
error6:
del_timer_sync(&vub300->inactivity_timer);
error5:
mmc_free_host(mmc);
/*

View File

@ -267,7 +267,7 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
static inline char *wbsd_map_sg(struct wbsd_host *host)
{
return kmap_atomic(sg_page(host->cur_sg)) + host->cur_sg->offset;
return kmap_local_page(sg_page(host->cur_sg)) + host->cur_sg->offset;
}
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@ -439,7 +439,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
* End of scatter list entry?
*/
if (host->remain == 0) {
kunmap_atomic(buffer);
kunmap_local(buffer);
/*
* Get next entry. Check if last.
*/
@ -451,7 +451,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
}
}
}
kunmap_atomic(buffer);
kunmap_local(buffer);
/*
* This is a very dirty hack to solve a
@ -505,7 +505,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
* End of scatter list entry?
*/
if (host->remain == 0) {
kunmap_atomic(buffer);
kunmap_local(buffer);
/*
* Get next entry. Check if last.
*/
@ -517,7 +517,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
}
}
}
kunmap_atomic(buffer);
kunmap_local(buffer);
/*
* The controller stops sending interrupts for
@ -1698,7 +1698,17 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma,
*/
wbsd_init_device(host);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret) {
if (!pnp)
wbsd_chip_poweroff(host);
wbsd_release_resources(host);
wbsd_free_mmc(dev);
mmc_free_host(mmc);
return ret;
}
pr_info("%s: W83L51xD", mmc_hostname(mmc));
if (host->chip_id != 0)

View File

@ -856,11 +856,15 @@ static int wmt_mci_probe(struct platform_device *pdev)
/* configure the controller to a known 'ready' state */
wmt_reset_hardware(mmc);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto fail7;
dev_info(&pdev->dev, "WMT SDHC Controller initialized\n");
return 0;
fail7:
clk_disable_unprepare(priv->clk_sdmmc);
fail6:
clk_put(priv->clk_sdmmc);
fail5_and_a_half:

View File

@ -605,6 +605,10 @@ struct iommu_group *fsl_mc_device_group(struct device *dev);
* @flags: IOMMU_FWSPEC_* flags
* @num_ids: number of associated device IDs
* @ids: IDs which this device may present to the IOMMU
*
* Note that the IDs (and any other information, really) stored in this structure should be
* considered private to the IOMMU device driver and are not to be used directly by IOMMU
* consumers.
*/
struct iommu_fwspec {
const struct iommu_ops *ops;
@ -1099,4 +1103,25 @@ static inline void iommu_dma_compose_msi_msg(struct msi_desc *desc, struct msi_m
#endif /* CONFIG_IOMMU_DMA */
/*
* Newer generations of Tegra SoCs require devices' stream IDs to be directly programmed into
* some registers. These are always paired with a Tegra SMMU or ARM SMMU, for which the contents
* of the struct iommu_fwspec are known. Use this helper to formalize access to these internals.
*/
#define TEGRA_STREAM_ID_BYPASS 0x7f
static inline bool tegra_dev_iommu_get_stream_id(struct device *dev, u32 *stream_id)
{
#ifdef CONFIG_IOMMU_API
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
if (fwspec && fwspec->num_ids == 1) {
*stream_id = fwspec->ids[0] & 0xffff;
return true;
}
#endif
return false;
}
#endif /* __LINUX_IOMMU_H */

View File

@ -102,7 +102,6 @@ struct tmio_mmc_data {
unsigned long capabilities2;
unsigned long flags;
u32 ocr_mask; /* available voltages */
int alignment_shift;
dma_addr_t dma_rx_offset;
unsigned int max_blk_count;
unsigned short max_segs;