Merge 328141e51e ("Merge tag 'mmc-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc") into android-mainline

Steps on the way to 6.0-rc1

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I6c72d9c0c9d6d83ec087eadc92610f22a2267a18
This commit is contained in:
Greg Kroah-Hartman
2022-08-23 07:52:15 +02:00
95 changed files with 2613 additions and 864 deletions

View File

@@ -0,0 +1,80 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/dma/apple,admac.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Apple Audio DMA Controller (ADMAC)
description: |
Apple's Audio DMA Controller (ADMAC) is used to fetch and store audio samples
on SoCs from the "Apple Silicon" family.
The controller has been seen with up to 24 channels. Even-numbered channels
are TX-only, odd-numbered are RX-only. Individual channels are coupled to
fixed device endpoints.
maintainers:
- Martin Povišer <povik+lin@cutebit.org>
allOf:
- $ref: "dma-controller.yaml#"
properties:
compatible:
items:
- enum:
- apple,t6000-admac
- apple,t8103-admac
- const: apple,admac
reg:
maxItems: 1
'#dma-cells':
const: 1
description:
Clients specify a single cell with channel number.
dma-channels:
maximum: 24
interrupts:
minItems: 4
maxItems: 4
description:
Interrupts that correspond to the 4 IRQ outputs of the controller. Usually
only one of the controller outputs will be connected as an usable interrupt
source. The remaining interrupts will be left without a valid value, e.g.
in an interrupts-extended list the disconnected positions will contain
an empty phandle reference <0>.
required:
- compatible
- reg
- '#dma-cells'
- dma-channels
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/apple-aic.h>
#include <dt-bindings/interrupt-controller/irq.h>
aic: interrupt-controller {
interrupt-controller;
#interrupt-cells = <3>;
};
admac: dma-controller@238200000 {
compatible = "apple,t8103-admac", "apple,admac";
reg = <0x38200000 0x34000>;
dma-channels = <24>;
interrupts-extended = <0>,
<&aic AIC_IRQ 626 IRQ_TYPE_LEVEL_HIGH>,
<0>,
<0>;
#dma-cells = <1>;
};

View File

@@ -0,0 +1,155 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/dma/fsl,edma.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale enhanced Direct Memory Access(eDMA) Controller
description: |
The eDMA channels have multiplex capability by programmable
memory-mapped registers. channels are split into two groups, called
DMAMUX0 and DMAMUX1, specific DMA request source can only be multiplexed
by any channel of certain group, DMAMUX0 or DMAMUX1, but not both.
maintainers:
- Peng Fan <peng.fan@nxp.com>
properties:
compatible:
oneOf:
- enum:
- fsl,vf610-edma
- fsl,imx7ulp-edma
- items:
- const: fsl,ls1028a-edma
- const: fsl,vf610-edma
reg:
minItems: 2
maxItems: 3
interrupts:
minItems: 2
maxItems: 17
interrupt-names:
minItems: 2
maxItems: 17
"#dma-cells":
const: 2
dma-channels:
const: 32
clocks:
maxItems: 2
clock-names:
maxItems: 2
big-endian:
description: |
If present registers and hardware scatter/gather descriptors of the
eDMA are implemented in big endian mode, otherwise in little mode.
type: boolean
required:
- "#dma-cells"
- compatible
- reg
- interrupts
- clocks
- dma-channels
allOf:
- $ref: "dma-controller.yaml#"
- if:
properties:
compatible:
contains:
const: fsl,vf610-edma
then:
properties:
clock-names:
items:
- const: dmamux0
- const: dmamux1
interrupts:
maxItems: 2
interrupt-names:
items:
- const: edma-tx
- const: edma-err
reg:
maxItems: 3
- if:
properties:
compatible:
contains:
const: fsl,imx7ulp-edma
then:
properties:
clock-names:
items:
- const: dma
- const: dmamux0
interrupts:
maxItems: 17
reg:
maxItems: 2
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/vf610-clock.h>
edma0: dma-controller@40018000 {
#dma-cells = <2>;
compatible = "fsl,vf610-edma";
reg = <0x40018000 0x2000>,
<0x40024000 0x1000>,
<0x40025000 0x1000>;
interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
<0 9 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "edma-tx", "edma-err";
dma-channels = <32>;
clock-names = "dmamux0", "dmamux1";
clocks = <&clks VF610_CLK_DMAMUX0>, <&clks VF610_CLK_DMAMUX1>;
};
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/imx7ulp-clock.h>
edma1: dma-controller@40080000 {
#dma-cells = <2>;
compatible = "fsl,imx7ulp-edma";
reg = <0x40080000 0x2000>,
<0x40210000 0x1000>;
dma-channels = <32>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
/* last is eDMA2-ERR interrupt */
<GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "dma", "dmamux0";
clocks = <&pcc2 IMX7ULP_CLK_DMA1>, <&pcc2 IMX7ULP_CLK_DMA_MUX1>;
};

View File

@@ -1,111 +0,0 @@
* Freescale enhanced Direct Memory Access(eDMA) Controller
The eDMA channels have multiplex capability by programmble memory-mapped
registers. channels are split into two groups, called DMAMUX0 and DMAMUX1,
specific DMA request source can only be multiplexed by any channel of certain
group, DMAMUX0 or DMAMUX1, but not both.
* eDMA Controller
Required properties:
- compatible :
- "fsl,vf610-edma" for eDMA used similar to that on Vybrid vf610 SoC
- "fsl,imx7ulp-edma" for eDMA2 used similar to that on i.mx7ulp
- "fsl,ls1028a-edma" followed by "fsl,vf610-edma" for eDMA used on the
LS1028A SoC.
- reg : Specifies base physical address(s) and size of the eDMA registers.
The 1st region is eDMA control register's address and size.
The 2nd and the 3rd regions are programmable channel multiplexing
control register's address and size.
- interrupts : A list of interrupt-specifiers, one for each entry in
interrupt-names on vf610 similar SoC. But for i.mx7ulp per channel
per transmission interrupt, total 16 channel interrupt and 1
error interrupt(located in the last), no interrupt-names list on
i.mx7ulp for clean on dts.
- #dma-cells : Must be <2>.
The 1st cell specifies the DMAMUX(0 for DMAMUX0 and 1 for DMAMUX1).
Specific request source can only be multiplexed by specific channels
group called DMAMUX.
The 2nd cell specifies the request source(slot) ID.
See the SoC's reference manual for all the supported request sources.
- dma-channels : Number of channels supported by the controller
- clock-names : A list of channel group clock names. Should contain:
"dmamux0" - clock name of mux0 group
"dmamux1" - clock name of mux1 group
Note: No dmamux0 on i.mx7ulp, but another 'dma' clk added on i.mx7ulp.
- clocks : A list of phandle and clock-specifier pairs, one for each entry in
clock-names.
Optional properties:
- big-endian: If present registers and hardware scatter/gather descriptors
of the eDMA are implemented in big endian mode, otherwise in little
mode.
- interrupt-names : Should contain the below on vf610 similar SoC but not used
on i.mx7ulp similar SoC:
"edma-tx" - the transmission interrupt
"edma-err" - the error interrupt
Examples:
edma0: dma-controller@40018000 {
#dma-cells = <2>;
compatible = "fsl,vf610-edma";
reg = <0x40018000 0x2000>,
<0x40024000 0x1000>,
<0x40025000 0x1000>;
interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
<0 9 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "edma-tx", "edma-err";
dma-channels = <32>;
clock-names = "dmamux0", "dmamux1";
clocks = <&clks VF610_CLK_DMAMUX0>,
<&clks VF610_CLK_DMAMUX1>;
}; /* vf610 */
edma1: dma-controller@40080000 {
#dma-cells = <2>;
compatible = "fsl,imx7ulp-edma";
reg = <0x40080000 0x2000>,
<0x40210000 0x1000>;
dma-channels = <32>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
/* last is eDMA2-ERR interrupt */
<GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "dma", "dmamux0";
clocks = <&pcc2 IMX7ULP_CLK_DMA1>,
<&pcc2 IMX7ULP_CLK_DMA_MUX1>;
}; /* i.mx7ulp */
* DMA clients
DMA client drivers that uses the DMA function must use the format described
in the dma.txt file, using a two-cell specifier for each channel: the 1st
specifies the channel group(DMAMUX) in which this request can be multiplexed,
and the 2nd specifies the request source.
Examples:
sai2: sai@40031000 {
compatible = "fsl,vf610-sai";
reg = <0x40031000 0x1000>;
interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "sai";
clocks = <&clks VF610_CLK_SAI2>;
dma-names = "tx", "rx";
dmas = <&edma0 0 21>,
<&edma0 0 20>;
};

View File

@@ -22,6 +22,7 @@ properties:
- items:
- enum:
- mediatek,mt2712-uart-dma
- mediatek,mt8365-uart-dma
- mediatek,mt8516-uart-dma
- const: mediatek,mt6577-uart-dma
- enum:

View File

@@ -23,7 +23,9 @@ properties:
oneOf:
- const: nvidia,tegra186-gpcdma
- items:
- const: nvidia,tegra194-gpcdma
- enum:
- nvidia,tegra234-gpcdma
- nvidia,tegra194-gpcdma
- const: nvidia,tegra186-gpcdma
"#dma-cells":

View File

@@ -34,7 +34,12 @@ properties:
- const: axidma_apb_regs
interrupts:
maxItems: 1
description:
If the IP-core synthesis parameter DMAX_INTR_IO_TYPE is set to 1, this
will be per-channel interrupts. Otherwise, this is a single combined IRQ
for all channels.
minItems: 1
maxItems: 8
clocks:
items:

View File

@@ -1,138 +0,0 @@
* DMA40 DMA Controller
Required properties:
- compatible: "stericsson,dma40"
- reg: Address range of the DMAC registers
- reg-names: Names of the above areas to use during resource look-up
- interrupt: Should contain the DMAC interrupt number
- #dma-cells: must be <3>
- memcpy-channels: Channels to be used for memcpy
Optional properties:
- dma-channels: Number of channels supported by hardware - if not present
the driver will attempt to obtain the information from H/W
- disabled-channels: Channels which can not be used
Example:
dma: dma-controller@801c0000 {
compatible = "stericsson,db8500-dma40", "stericsson,dma40";
reg = <0x801C0000 0x1000 0x40010000 0x800>;
reg-names = "base", "lcpa";
interrupt-parent = <&intc>;
interrupts = <0 25 0x4>;
#dma-cells = <2>;
memcpy-channels = <56 57 58 59 60>;
disabled-channels = <12>;
dma-channels = <8>;
};
Clients
Required properties:
- dmas: Comma separated list of dma channel requests
- dma-names: Names of the aforementioned requested channels
Each dmas request consists of 4 cells:
1. A phandle pointing to the DMA controller
2. Device signal number, the signal line for single and burst requests
connected from the device to the DMA40 engine
3. The DMA request line number (only when 'use fixed channel' is set)
4. A 32bit mask specifying; mode, direction and endianness
[NB: This list will grow]
0x00000001: Mode:
Logical channel when unset
Physical channel when set
0x00000002: Direction:
Memory to Device when unset
Device to Memory when set
0x00000004: Endianness:
Little endian when unset
Big endian when set
0x00000008: Use fixed channel:
Use automatic channel selection when unset
Use DMA request line number when set
0x00000010: Set channel as high priority:
Normal priority when unset
High priority when set
Existing signal numbers for the DB8500 ASIC. Unless specified, the signals are
bidirectional, i.e. the same for RX and TX operations:
0: SPI controller 0
1: SD/MMC controller 0 (unused)
2: SD/MMC controller 1 (unused)
3: SD/MMC controller 2 (unused)
4: I2C port 1
5: I2C port 3
6: I2C port 2
7: I2C port 4
8: Synchronous Serial Port SSP0
9: Synchronous Serial Port SSP1
10: Multi-Channel Display Engine MCDE RX
11: UART port 2
12: UART port 1
13: UART port 0
14: Multirate Serial Port MSP2
15: I2C port 0
16: USB OTG in/out endpoints 7 & 15
17: USB OTG in/out endpoints 6 & 14
18: USB OTG in/out endpoints 5 & 13
19: USB OTG in/out endpoints 4 & 12
20: SLIMbus or HSI channel 0
21: SLIMbus or HSI channel 1
22: SLIMbus or HSI channel 2
23: SLIMbus or HSI channel 3
24: Multimedia DSP SXA0
25: Multimedia DSP SXA1
26: Multimedia DSP SXA2
27: Multimedia DSP SXA3
28: SD/MM controller 2
29: SD/MM controller 0
30: MSP port 1 on DB8500 v1, MSP port 3 on DB8500 v2
31: MSP port 0 or SLIMbus channel 0
32: SD/MM controller 1
33: SPI controller 2
34: i2c3 RX2 TX2
35: SPI controller 1
36: USB OTG in/out endpoints 3 & 11
37: USB OTG in/out endpoints 2 & 10
38: USB OTG in/out endpoints 1 & 9
39: USB OTG in/out endpoints 8
40: SPI controller 3
41: SD/MM controller 3
42: SD/MM controller 4
43: SD/MM controller 5
44: Multimedia DSP SXA4
45: Multimedia DSP SXA5
46: SLIMbus channel 8 or Multimedia DSP SXA6
47: SLIMbus channel 9 or Multimedia DSP SXA7
48: Crypto Accelerator 1
49: Crypto Accelerator 1 TX or Hash Accelerator 1 TX
50: Hash Accelerator 1 TX
51: memcpy TX (to be used by the DMA driver for memcpy operations)
52: SLIMbus or HSI channel 4
53: SLIMbus or HSI channel 5
54: SLIMbus or HSI channel 6
55: SLIMbus or HSI channel 7
56: memcpy (to be used by the DMA driver for memcpy operations)
57: memcpy (to be used by the DMA driver for memcpy operations)
58: memcpy (to be used by the DMA driver for memcpy operations)
59: memcpy (to be used by the DMA driver for memcpy operations)
60: memcpy (to be used by the DMA driver for memcpy operations)
61: Crypto Accelerator 0
62: Crypto Accelerator 0 TX or Hash Accelerator 0 TX
63: Hash Accelerator 0 TX
Example:
uart@80120000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x80120000 0x1000>;
interrupts = <0 11 0x4>;
dmas = <&dma 13 0 0x2>, /* Logical - DevToMem */
<&dma 13 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "rx";
};

View File

@@ -0,0 +1,159 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/dma/stericsson,dma40.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ST-Ericsson DMA40 DMA Engine
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
allOf:
- $ref: "dma-controller.yaml#"
properties:
"#dma-cells":
const: 3
description: |
The first cell is the unique device channel number as indicated by this
table for DB8500 which is the only ASIC known to use DMA40:
0: SPI controller 0
1: SD/MMC controller 0 (unused)
2: SD/MMC controller 1 (unused)
3: SD/MMC controller 2 (unused)
4: I2C port 1
5: I2C port 3
6: I2C port 2
7: I2C port 4
8: Synchronous Serial Port SSP0
9: Synchronous Serial Port SSP1
10: Multi-Channel Display Engine MCDE RX
11: UART port 2
12: UART port 1
13: UART port 0
14: Multirate Serial Port MSP2
15: I2C port 0
16: USB OTG in/out endpoints 7 & 15
17: USB OTG in/out endpoints 6 & 14
18: USB OTG in/out endpoints 5 & 13
19: USB OTG in/out endpoints 4 & 12
20: SLIMbus or HSI channel 0
21: SLIMbus or HSI channel 1
22: SLIMbus or HSI channel 2
23: SLIMbus or HSI channel 3
24: Multimedia DSP SXA0
25: Multimedia DSP SXA1
26: Multimedia DSP SXA2
27: Multimedia DSP SXA3
28: SD/MMC controller 2
29: SD/MMC controller 0
30: MSP port 1 on DB8500 v1, MSP port 3 on DB8500 v2
31: MSP port 0 or SLIMbus channel 0
32: SD/MMC controller 1
33: SPI controller 2
34: i2c3 RX2 TX2
35: SPI controller 1
36: USB OTG in/out endpoints 3 & 11
37: USB OTG in/out endpoints 2 & 10
38: USB OTG in/out endpoints 1 & 9
39: USB OTG in/out endpoints 8
40: SPI controller 3
41: SD/MMC controller 3
42: SD/MMC controller 4
43: SD/MMC controller 5
44: Multimedia DSP SXA4
45: Multimedia DSP SXA5
46: SLIMbus channel 8 or Multimedia DSP SXA6
47: SLIMbus channel 9 or Multimedia DSP SXA7
48: Crypto Accelerator 1
49: Crypto Accelerator 1 TX or Hash Accelerator 1 TX
50: Hash Accelerator 1 TX
51: memcpy TX (to be used by the DMA driver for memcpy operations)
52: SLIMbus or HSI channel 4
53: SLIMbus or HSI channel 5
54: SLIMbus or HSI channel 6
55: SLIMbus or HSI channel 7
56: memcpy (to be used by the DMA driver for memcpy operations)
57: memcpy (to be used by the DMA driver for memcpy operations)
58: memcpy (to be used by the DMA driver for memcpy operations)
59: memcpy (to be used by the DMA driver for memcpy operations)
60: memcpy (to be used by the DMA driver for memcpy operations)
61: Crypto Accelerator 0
62: Crypto Accelerator 0 TX or Hash Accelerator 0 TX
63: Hash Accelerator 0 TX
The second cell is the DMA request line number. This is only used when
a fixed channel is allocated, and indicated by setting bit 3 in the
flags field (see below).
The third cell is a 32bit flags bitfield with the following possible
bits set:
0x00000001 (bit 0) - mode:
Logical channel when unset
Physical channel when set
0x00000002 (bit 1) - direction:
Memory to Device when unset
Device to Memory when set
0x00000004 (bit 2) - endianness:
Little endian when unset
Big endian when set
0x00000008 (bit 3) - use fixed channel:
Use automatic channel selection when unset
Use DMA request line number when set
0x00000010 (bit 4) - set channel as high priority:
Normal priority when unset
High priority when set
compatible:
items:
- const: stericsson,db8500-dma40
- const: stericsson,dma40
reg:
items:
- description: DMA40 memory base
- description: LCPA memory base
reg-names:
items:
- const: base
- const: lcpa
interrupts:
maxItems: 1
clocks:
maxItems: 1
memcpy-channels:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: Array of u32 elements indicating which channels on the DMA
engine are elegible for memcpy transfers
required:
- "#dma-cells"
- compatible
- reg
- interrupts
- clocks
- memcpy-channels
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/mfd/dbx500-prcmu.h>
dma-controller@801C0000 {
compatible = "stericsson,db8500-dma40", "stericsson,dma40";
reg = <0x801C0000 0x1000>, <0x40010000 0x800>;
reg-names = "base", "lcpa";
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
#dma-cells = <3>;
memcpy-channels = <56 57 58 59 60>;
clocks = <&prcmu_clk PRCMU_DMACLK>;
};
...

View File

@@ -10,9 +10,6 @@ maintainers:
- Al Cooper <alcooperx@gmail.com>
- Florian Fainelli <f.fainelli@gmail.com>
allOf:
- $ref: mmc-controller.yaml#
properties:
compatible:
oneOf:
@@ -42,23 +39,46 @@ properties:
maxItems: 1
clocks:
maxItems: 1
description:
handle to core clock for the sdhci controller.
minItems: 1
items:
- description: handle to core clock for the sdhci controller
- description: handle to improved 150Mhz clock for sdhci controller (Optional clock)
clock-names:
minItems: 1
items:
- const: sw_sdio
- const: sdio_freq # Optional clock
clock-frequency:
description:
Maximum operating frequency of sdio_freq sdhci controller clock
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 100000000
maximum: 150000000
sdhci,auto-cmd12:
type: boolean
description: Specifies that controller should use auto CMD12
allOf:
- $ref: mmc-controller.yaml#
- if:
properties:
clock-names:
contains:
const: sdio_freq
then:
required:
- clock-frequency
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
unevaluatedProperties: false

View File

@@ -1,94 +0,0 @@
* Samsung Exynos specific extensions to the Synopsys Designware Mobile
Storage Host Controller
The Synopsys designware mobile storage host controller is used to interface
a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
differences between the core Synopsys dw mshc controller properties described
by synopsys-dw-mshc.txt and the properties used by the Samsung Exynos specific
extensions to the Synopsys Designware Mobile Storage Host Controller.
Required Properties:
* compatible: should be
- "samsung,exynos4210-dw-mshc": for controllers with Samsung Exynos4210
specific extensions.
- "samsung,exynos4412-dw-mshc": for controllers with Samsung Exynos4412
specific extensions.
- "samsung,exynos5250-dw-mshc": for controllers with Samsung Exynos5250
specific extensions.
- "samsung,exynos5420-dw-mshc": for controllers with Samsung Exynos5420
specific extensions.
- "samsung,exynos7-dw-mshc": for controllers with Samsung Exynos7
specific extensions.
- "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
specific extensions having an SMU.
- "axis,artpec8-dw-mshc": for controllers with ARTPEC-8 specific
extensions.
* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
* samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
in transmit mode and CIU clock phase shift value in receive mode for single
data rate mode operation. Refer notes below for the order of the cells and the
valid values.
* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock phase shift value
in transmit mode and CIU clock phase shift value in receive mode for double
data rate mode operation. Refer notes below for the order of the cells and the
valid values.
* samsung,dw-mshc-hs400-timing: Specifies the value of CIU TX and RX clock phase
shift value for hs400 mode operation.
Notes for the sdr-timing and ddr-timing values:
The order of the cells should be
- First Cell: CIU clock phase shift value for tx mode.
- Second Cell: CIU clock phase shift value for rx mode.
Valid values for SDR and DDR CIU clock timing for Exynos5250:
- valid value for tx phase shift and rx phase shift is 0 to 7.
- when CIU clock divider value is set to 3, all possible 8 phase shift
values can be used.
- if CIU clock divider value is 0 (that is divide by 1), both tx and rx
phase shift clocks should be 0.
* samsung,read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
(Latency value for delay line in Read path)
Required properties for a slot (Deprecated - Recommend to use one slot per host):
* gpios: specifies a list of gpios used for command, clock and data bus. The
first gpio is the command line and the second gpio is the clock line. The
rest of the gpios (depending on the bus-width property) are the data lines in
no particular order. The format of the gpio specifier depends on the gpio
controller.
(Deprecated - Refer to Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt)
Example:
The MSHC controller node can be split into two portions, SoC specific and
board specific portions as listed below.
dwmmc0@12200000 {
compatible = "samsung,exynos5250-dw-mshc";
reg = <0x12200000 0x1000>;
interrupts = <0 75 0>;
#address-cells = <1>;
#size-cells = <0>;
};
dwmmc0@12200000 {
cap-mmc-highspeed;
cap-sd-highspeed;
broken-cd;
fifo-depth = <0x80>;
card-detect-delay = <200>;
samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <2 3>;
samsung,dw-mshc-ddr-timing = <1 2>;
samsung,dw-mshc-hs400-timing = <0 2>;
samsung,read-strobe-delay = <90>;
bus-width = <8>;
};

View File

@@ -1,29 +0,0 @@
MMC/SD/SDIO slot directly connected to a SPI bus
This file documents differences between the core properties described
by mmc.txt and the properties used by the mmc_spi driver.
Required properties:
- spi-max-frequency : maximum frequency for this device (Hz).
Optional properties:
- voltage-ranges : two cells are required, first cell specifies minimum
slot voltage (mV), second cell specifies maximum slot voltage (mV).
Several ranges could be specified. If not provided, 3.2v..3.4v is assumed.
- gpios : may specify GPIOs in this order: Card-Detect GPIO,
Write-Protect GPIO. Note that this does not follow the
binding from mmc.txt, for historical reasons.
Example:
mmc-slot@0 {
compatible = "fsl,mpc8323rdb-mmc-slot",
"mmc-spi-slot";
reg = <0>;
gpios = <&qe_pio_d 14 1
&qe_pio_d 15 0>;
voltage-ranges = <3300 3300>;
spi-max-frequency = <50000000>;
interrupts = <42>;
interrupt-parent = <&PIC>;
};

View File

@@ -0,0 +1,77 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/mmc-spi-slot.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MMC/SD/SDIO slot directly connected to a SPI bus
maintainers:
- Ulf Hansson <ulf.hansson@linaro.org>
allOf:
- $ref: "mmc-controller.yaml"
- $ref: /schemas/spi/spi-peripheral-props.yaml
description: |
The extra properties used by an mmc connected via SPI.
properties:
compatible:
const: mmc-spi-slot
reg:
maxItems: 1
spi-max-frequency: true
interrupts:
maxItems: 1
voltage-ranges:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: |
Two cells are required, first cell specifies minimum slot voltage (mV),
second cell specifies maximum slot voltage (mV).
items:
- description: |
value for minimum slot voltage in mV
default: 3200
- description: |
value for maximum slot voltage in mV
default: 3400
gpios:
description: |
For historical reasons, this does not follow the generic mmc-controller
binding.
minItems: 1
items:
- description: Card-Detect GPIO
- description: Write-Protect GPIO
required:
- compatible
- reg
- spi-max-frequency
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
mmc@0 {
compatible = "mmc-spi-slot";
reg = <0>;
gpios = <&gpio 14 GPIO_ACTIVE_LOW>, <&gpio 15 GPIO_ACTIVE_HIGH>;
voltage-ranges = <3300 3300>;
spi-max-frequency = <50000000>;
interrupts = <42>;
interrupt-parent = <&PIC>;
};
};
...

View File

@@ -30,13 +30,11 @@ properties:
- const: mediatek,mt7623-mmc
- const: mediatek,mt2701-mmc
- items:
- const: mediatek,mt8186-mmc
- const: mediatek,mt8183-mmc
- items:
- const: mediatek,mt8192-mmc
- const: mediatek,mt8183-mmc
- items:
- const: mediatek,mt8195-mmc
- enum:
- mediatek,mt8186-mmc
- mediatek,mt8188-mmc
- mediatek,mt8192-mmc
- mediatek,mt8195-mmc
- const: mediatek,mt8183-mmc
reg:
@@ -72,12 +70,27 @@ properties:
- const: ahb_cg
interrupts:
maxItems: 1
description:
Should at least contain MSDC GIC interrupt. To support SDIO in-band wakeup, an extended
interrupt is required and be configured as wakeup source irq.
minItems: 1
maxItems: 2
interrupt-names:
items:
- const: msdc
- const: sdio_wakeup
pinctrl-names:
description:
Should at least contain default and state_uhs. To support SDIO in-band wakeup, dat1 pin
will be switched between GPIO mode and SDIO DAT1 mode, state_eint is mandatory in this
scenario.
minItems: 2
items:
- const: default
- const: state_uhs
- const: state_eint
pinctrl-0:
description:
@@ -89,6 +102,11 @@ properties:
should contain uhs mode pin ctrl.
maxItems: 1
pinctrl-2:
description:
should switch dat1 pin to GPIO mode.
maxItems: 1
assigned-clocks:
description:
PLL of the source clock.
@@ -208,4 +226,32 @@ examples:
mediatek,hs400-cmd-resp-sel-rising;
};
mmc3: mmc@11260000 {
compatible = "mediatek,mt8173-mmc";
reg = <0x11260000 0x1000>;
clock-names = "source", "hclk";
clocks = <&pericfg CLK_PERI_MSDC30_3>,
<&topckgen CLK_TOP_MSDC50_2_H_SEL>;
interrupt-names = "msdc", "sdio_wakeup";
interrupts-extended = <&gic GIC_SPI 74 IRQ_TYPE_LEVEL_LOW 0>,
<&pio 23 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default", "state_uhs", "state_eint";
pinctrl-0 = <&mmc2_pins_default>;
pinctrl-1 = <&mmc2_pins_uhs>;
pinctrl-2 = <&mmc2_pins_eint>;
bus-width = <4>;
max-frequency = <200000000>;
cap-sd-highspeed;
sd-uhs-sdr104;
keep-power-in-suspend;
wakeup-source;
cap-sdio-irq;
no-mmc;
no-sd;
non-removable;
vmmc-supply = <&sdio_fixed_3v3>;
vqmmc-supply = <&mt6397_vgp3_reg>;
mmc-pwrseq = <&wifi_pwrseq>;
};
...

View File

@@ -56,11 +56,15 @@ properties:
- renesas,sdhi-r8a77980 # R-Car V3H
- renesas,sdhi-r8a77990 # R-Car E3
- renesas,sdhi-r8a77995 # R-Car D3
- renesas,sdhi-r8a779a0 # R-Car V3U
- renesas,sdhi-r9a07g043 # RZ/G2UL
- renesas,sdhi-r9a07g044 # RZ/G2{L,LC}
- renesas,sdhi-r9a07g054 # RZ/V2L
- const: renesas,rcar-gen3-sdhi # R-Car Gen3 or RZ/G2
- items:
- enum:
- renesas,sdhi-r8a779a0 # R-Car V3U
- renesas,sdhi-r8a779f0 # R-Car S4-8
- const: renesas,rcar-gen4-sdhi # R-Car Gen4
reg:
maxItems: 1
@@ -141,6 +145,7 @@ allOf:
enum:
- renesas,rcar-gen2-sdhi
- renesas,rcar-gen3-sdhi
- renesas,rcar-gen4-sdhi
then:
properties:
clocks:

View File

@@ -39,6 +39,7 @@ properties:
- rockchip,rk3399-dw-mshc
- rockchip,rk3568-dw-mshc
- rockchip,rv1108-dw-mshc
- rockchip,rv1126-dw-mshc
- const: rockchip,rk3288-dw-mshc
reg:

View File

@@ -0,0 +1,160 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/samsung,exynos-dw-mshc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title:
Samsung Exynos SoC specific extensions to the Synopsys Designware Mobile
Storage Host Controller
maintainers:
- Jaehoon Chung <jh80.chung@samsung.com>
- Krzysztof Kozlowski <krzk@kernel.org>
properties:
compatible:
enum:
- samsung,exynos4210-dw-mshc
- samsung,exynos4412-dw-mshc
- samsung,exynos5250-dw-mshc
- samsung,exynos5420-dw-mshc
- samsung,exynos5420-dw-mshc-smu
- samsung,exynos7-dw-mshc
- samsung,exynos7-dw-mshc-smu
- axis,artpec8-dw-mshc
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 2
description:
Handle to "biu" and "ciu" clocks for the
bus interface unit clock and the card interface unit clock.
clock-names:
items:
- const: biu
- const: ciu
samsung,dw-mshc-ciu-div:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
description:
The divider value for the card interface unit (ciu) clock.
samsung,dw-mshc-ddr-timing:
$ref: /schemas/types.yaml#/definitions/uint32-array
items:
- description: CIU clock phase shift value for tx mode
minimum: 0
maximum: 7
- description: CIU clock phase shift value for rx mode
minimum: 0
maximum: 7
description:
The value of CUI clock phase shift value in transmit mode and CIU clock
phase shift value in receive mode for double data rate mode operation.
See also samsung,dw-mshc-hs400-timing property.
samsung,dw-mshc-hs400-timing:
$ref: /schemas/types.yaml#/definitions/uint32-array
items:
- description: CIU clock phase shift value for tx mode
minimum: 0
maximum: 7
- description: CIU clock phase shift value for rx mode
minimum: 0
maximum: 7
description: |
The value of CIU TX and RX clock phase shift value for HS400 mode
operation.
Valid values for SDR and DDR CIU clock timing::
- valid value for tx phase shift and rx phase shift is 0 to 7.
- when CIU clock divider value is set to 3, all possible 8 phase shift
values can be used.
- if CIU clock divider value is 0 (that is divide by 1), both tx and rx
phase shift clocks should be 0.
If missing, values from samsung,dw-mshc-ddr-timing property are used.
samsung,dw-mshc-sdr-timing:
$ref: /schemas/types.yaml#/definitions/uint32-array
items:
- description: CIU clock phase shift value for tx mode
minimum: 0
maximum: 7
- description: CIU clock phase shift value for rx mode
minimum: 0
maximum: 7
description:
The value of CIU clock phase shift value in transmit mode and CIU clock
phase shift value in receive mode for single data rate mode operation.
See also samsung,dw-mshc-hs400-timing property.
samsung,read-strobe-delay:
$ref: /schemas/types.yaml#/definitions/uint32
description:
RCLK (Data strobe) delay to control HS400 mode (Latency value for delay
line in Read path). If missing, default from hardware is used.
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- samsung,dw-mshc-ddr-timing
- samsung,dw-mshc-sdr-timing
allOf:
- $ref: "synopsys-dw-mshc-common.yaml#"
- if:
properties:
compatible:
contains:
enum:
- samsung,exynos5250-dw-mshc
- samsung,exynos5420-dw-mshc
- samsung,exynos7-dw-mshc
- samsung,exynos7-dw-mshc-smu
- axis,artpec8-dw-mshc
then:
required:
- samsung,dw-mshc-ciu-div
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/exynos5420.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
mmc@12220000 {
compatible = "samsung,exynos5420-dw-mshc";
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
reg = <0x12220000 0x1000>;
clocks = <&clock CLK_MMC2>, <&clock CLK_SCLK_MMC2>;
clock-names = "biu", "ciu";
fifo-depth = <0x40>;
card-detect-delay = <200>;
samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <0 4>;
samsung,dw-mshc-ddr-timing = <0 2>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_wp &sd2_bus1 &sd2_bus4>;
bus-width = <4>;
cap-sd-highspeed;
max-frequency = <200000000>;
vmmc-supply = <&ldo19_reg>;
vqmmc-supply = <&ldo13_reg>;
sd-uhs-sdr50;
sd-uhs-sdr104;
sd-uhs-ddr50;
};

View File

@@ -0,0 +1,81 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/samsung,s3c6410-sdhci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung SoC SDHCI Controller
maintainers:
- Jaehoon Chung <jh80.chung@samsung.com>
- Krzysztof Kozlowski <krzk@kernel.org>
properties:
compatible:
enum:
- samsung,s3c6410-sdhci
- samsung,exynos4210-sdhci
reg:
maxItems: 1
clocks:
minItems: 2
maxItems: 5
clock-names:
minItems: 2
items:
- const: hsmmc
- pattern: "^mmc_busclk.[0-3]$"
- pattern: "^mmc_busclk.[0-3]$"
- pattern: "^mmc_busclk.[0-3]$"
- pattern: "^mmc_busclk.[0-3]$"
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
allOf:
- $ref: mmc-controller.yaml#
- if:
properties:
compatible:
contains:
enum:
- samsung,exynos4210-sdhci
then:
properties:
clocks:
maxItems: 2
clock-names:
items:
- const: hsmmc
- const: mmc_busclk.2
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/exynos4.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
mmc@12510000 {
compatible = "samsung,exynos4210-sdhci";
reg = <0x12510000 0x100>;
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clock CLK_SDMMC0>, <&clock CLK_SCLK_MMC0>;
clock-names = "hsmmc", "mmc_busclk.2";
bus-width = <4>;
cd-gpios = <&gpx3 4 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sdhci2_cd>;
pinctrl-names = "default";
vmmc-supply = <&ldo21_reg>;
};

View File

@@ -1,32 +0,0 @@
* Samsung's SDHCI Controller device tree bindings
Samsung's SDHCI controller is used as a connectivity interface with external
MMC, SD and eMMC storage mediums. This file documents differences between the
core mmc properties described by mmc.txt and the properties used by the
Samsung implementation of the SDHCI controller.
Required SoC Specific Properties:
- compatible: should be one of the following
- "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci
controller.
- "samsung,exynos4210-sdhci": For controllers compatible with Exynos4 sdhci
controller.
Required Board Specific Properties:
- pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default".
Example:
sdhci@12530000 {
compatible = "samsung,exynos4210-sdhci";
reg = <0x12530000 0x100>;
interrupts = <0 75 0>;
bus-width = <4>;
cd-gpios = <&gpk2 2 0>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>;
};
Note: This example shows both SoC specific and board specific properties
in a single device node. The properties can be actually be separated
into SoC specific node and board specific node.

View File

@@ -17,6 +17,9 @@ description:
properties:
compatible:
oneOf:
- enum:
- qcom,sdhci-msm-v4
deprecated: true
- items:
- enum:
- qcom,apq8084-sdhci
@@ -27,6 +30,10 @@ properties:
- qcom,msm8992-sdhci
- qcom,msm8994-sdhci
- qcom,msm8996-sdhci
- qcom,msm8998-sdhci
- const: qcom,sdhci-msm-v4 # for sdcc versions less than 5.0
- items:
- enum:
- qcom,qcs404-sdhci
- qcom,sc7180-sdhci
- qcom,sc7280-sdhci
@@ -38,20 +45,16 @@ properties:
- qcom,sm6350-sdhci
- qcom,sm8150-sdhci
- qcom,sm8250-sdhci
- enum:
- qcom,sdhci-msm-v4 # for sdcc versions less than 5.0
- qcom,sdhci-msm-v5 # for sdcc version 5.0
- items:
- const: qcom,sdhci-msm-v4 # Deprecated (only for backward compatibility)
# for sdcc versions less than 5.0
- qcom,sm8450-sdhci
- const: qcom,sdhci-msm-v5 # for sdcc version 5.0
reg:
minItems: 1
items:
- description: Host controller register map
- description: SD Core register map
- description: CQE register map
- description: Inline Crypto Engine register map
maxItems: 4
reg-names:
minItems: 1
maxItems: 4
clocks:
minItems: 3
@@ -93,6 +96,9 @@ properties:
description:
Should specify pin control groups used for this controller.
resets:
maxItems: 1
qcom,ddr-config:
$ref: /schemas/types.yaml#/definitions/uint32
description: platform specific settings for DDR_CONFIG reg.
@@ -121,6 +127,16 @@ 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
patternProperties:
'^opp-table(-[a-z0-9]+)?$':
if:
@@ -140,7 +156,47 @@ required:
- clock-names
- interrupts
additionalProperties: true
allOf:
- $ref: mmc-controller.yaml#
- if:
properties:
compatible:
contains:
enum:
- qcom,sdhci-msm-v4
then:
properties:
reg:
minItems: 2
items:
- description: Host controller register map
- description: SD Core register map
- description: CQE register map
- description: Inline Crypto Engine register map
reg-names:
minItems: 2
items:
- const: hc
- const: core
- const: cqhci
- const: ice
else:
properties:
reg:
minItems: 1
items:
- description: Host controller register map
- description: CQE register map
- description: Inline Crypto Engine register map
reg-names:
minItems: 1
items:
- const: hc
- const: cqhci
- const: ice
unevaluatedProperties: false
examples:
- |
@@ -149,7 +205,7 @@ examples:
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/power/qcom-rpmpd.h>
sdhc_2: sdhci@8804000 {
sdhc_2: mmc@8804000 {
compatible = "qcom,sm8250-sdhci", "qcom,sdhci-msm-v5";
reg = <0 0x08804000 0 0x1000>;

View File

@@ -162,16 +162,6 @@ Currently, the types available are:
- The device is able to do memory to memory copies
- - DMA_MEMCPY_SG
- The device supports memory to memory scatter-gather transfers.
- Even though a plain memcpy can look like a particular case of a
scatter-gather transfer, with a single chunk to copy, it's a distinct
transaction type in the mem2mem transfer case. This is because some very
simple devices might be able to do contiguous single-chunk memory copies,
but have no support for more complex SG transfers.
- No matter what the overall size of the combined chunks for source and
destination is, only as many bytes as the smallest of the two will be
transmitted. That means the number and size of the scatter-gather buffers in

View File

@@ -1851,6 +1851,7 @@ T: git https://github.com/AsahiLinux/linux.git
F: Documentation/devicetree/bindings/arm/apple.yaml
F: Documentation/devicetree/bindings/arm/apple/*
F: Documentation/devicetree/bindings/clock/apple,nco.yaml
F: Documentation/devicetree/bindings/dma/apple,admac.yaml
F: Documentation/devicetree/bindings/i2c/apple,i2c.yaml
F: Documentation/devicetree/bindings/interrupt-controller/apple,*
F: Documentation/devicetree/bindings/iommu/apple,dart.yaml
@@ -1864,6 +1865,7 @@ F: Documentation/devicetree/bindings/power/apple*
F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
F: arch/arm64/boot/dts/apple/
F: drivers/clk/clk-apple-nco.c
F: drivers/dma/apple-admac.c
F: drivers/i2c/busses/i2c-pasemi-core.c
F: drivers/i2c/busses/i2c-pasemi-platform.c
F: drivers/iommu/apple-dart.c
@@ -6102,6 +6104,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git
F: Documentation/devicetree/bindings/dma/
F: Documentation/driver-api/dmaengine/
F: drivers/dma/
F: include/dt-bindings/dma/
F: include/linux/dma/
F: include/linux/dmaengine.h
F: include/linux/of_dma.h
@@ -10195,7 +10198,8 @@ S: Supported
Q: https://patchwork.kernel.org/project/linux-dmaengine/list/
F: drivers/dma/ioat*
INTEL IADX DRIVER
INTEL IDXD DRIVER
M: Fenghua Yu <fenghua.yu@intel.com>
M: Dave Jiang <dave.jiang@intel.com>
L: dmaengine@vger.kernel.org
S: Supported

View File

@@ -85,6 +85,14 @@ config AMCC_PPC440SPE_ADMA
help
Enable support for the AMCC PPC440SPe RAID engines.
config APPLE_ADMAC
tristate "Apple ADMAC support"
depends on ARCH_APPLE || COMPILE_TEST
select DMA_ENGINE
default ARCH_APPLE
help
Enable support for Audio DMA Controller found on Apple Silicon SoCs.
config AT_HDMAC
tristate "Atmel AHB DMA support"
depends on ARCH_AT91

View File

@@ -17,6 +17,7 @@ obj-$(CONFIG_ALTERA_MSGDMA) += altera-msgdma.o
obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
obj-$(CONFIG_AMD_PTDMA) += ptdma/
obj-$(CONFIG_APPLE_ADMAC) += apple-admac.o
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
obj-$(CONFIG_AT_XDMAC) += at_xdmac.o
obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o

View File

@@ -749,7 +749,7 @@ static irqreturn_t msgdma_irq_handler(int irq, void *data)
}
/**
* msgdma_chan_remove - Channel remove function
* msgdma_dev_remove() - Device remove function
* @mdev: Pointer to the Altera mSGDMA device structure
*/
static void msgdma_dev_remove(struct msgdma_device *mdev)
@@ -918,7 +918,7 @@ fail:
}
/**
* msgdma_dma_remove - Driver remove function
* msgdma_remove() - Driver remove function
* @pdev: Pointer to the platform_device structure
*
* Return: Always '0'

View File

@@ -231,7 +231,7 @@ enum pl08x_dma_chan_state {
/**
* struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
* @vc: wrappped virtual channel
* @vc: wrapped virtual channel
* @phychan: the physical channel utilized by this channel, if there is one
* @name: name of channel
* @cd: channel platform data

818
drivers/dma/apple-admac.c Normal file
View File

@@ -0,0 +1,818 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Audio DMA Controller (ADMAC) on t8103 (M1) and other Apple chips
*
* Copyright (C) The Asahi Linux Contributors
*/
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include "dmaengine.h"
#define NCHANNELS_MAX 64
#define IRQ_NOUTPUTS 4
#define RING_WRITE_SLOT GENMASK(1, 0)
#define RING_READ_SLOT GENMASK(5, 4)
#define RING_FULL BIT(9)
#define RING_EMPTY BIT(8)
#define RING_ERR BIT(10)
#define STATUS_DESC_DONE BIT(0)
#define STATUS_ERR BIT(6)
#define FLAG_DESC_NOTIFY BIT(16)
#define REG_TX_START 0x0000
#define REG_TX_STOP 0x0004
#define REG_RX_START 0x0008
#define REG_RX_STOP 0x000c
#define REG_CHAN_CTL(ch) (0x8000 + (ch) * 0x200)
#define REG_CHAN_CTL_RST_RINGS BIT(0)
#define REG_DESC_RING(ch) (0x8070 + (ch) * 0x200)
#define REG_REPORT_RING(ch) (0x8074 + (ch) * 0x200)
#define REG_RESIDUE(ch) (0x8064 + (ch) * 0x200)
#define REG_BUS_WIDTH(ch) (0x8040 + (ch) * 0x200)
#define BUS_WIDTH_8BIT 0x00
#define BUS_WIDTH_16BIT 0x01
#define BUS_WIDTH_32BIT 0x02
#define BUS_WIDTH_FRAME_2_WORDS 0x10
#define BUS_WIDTH_FRAME_4_WORDS 0x20
#define CHAN_BUFSIZE 0x8000
#define REG_CHAN_FIFOCTL(ch) (0x8054 + (ch) * 0x200)
#define CHAN_FIFOCTL_LIMIT GENMASK(31, 16)
#define CHAN_FIFOCTL_THRESHOLD GENMASK(15, 0)
#define REG_DESC_WRITE(ch) (0x10000 + ((ch) / 2) * 0x4 + ((ch) & 1) * 0x4000)
#define REG_REPORT_READ(ch) (0x10100 + ((ch) / 2) * 0x4 + ((ch) & 1) * 0x4000)
#define REG_TX_INTSTATE(idx) (0x0030 + (idx) * 4)
#define REG_RX_INTSTATE(idx) (0x0040 + (idx) * 4)
#define REG_CHAN_INTSTATUS(ch, idx) (0x8010 + (ch) * 0x200 + (idx) * 4)
#define REG_CHAN_INTMASK(ch, idx) (0x8020 + (ch) * 0x200 + (idx) * 4)
struct admac_data;
struct admac_tx;
struct admac_chan {
unsigned int no;
struct admac_data *host;
struct dma_chan chan;
struct tasklet_struct tasklet;
spinlock_t lock;
struct admac_tx *current_tx;
int nperiod_acks;
/*
* We maintain a 'submitted' and 'issued' list mainly for interface
* correctness. Typical use of the driver (per channel) will be
* prepping, submitting and issuing a single cyclic transaction which
* will stay current until terminate_all is called.
*/
struct list_head submitted;
struct list_head issued;
struct list_head to_free;
};
struct admac_data {
struct dma_device dma;
struct device *dev;
__iomem void *base;
int irq_index;
int nchannels;
struct admac_chan channels[];
};
struct admac_tx {
struct dma_async_tx_descriptor tx;
bool cyclic;
dma_addr_t buf_addr;
dma_addr_t buf_end;
size_t buf_len;
size_t period_len;
size_t submitted_pos;
size_t reclaimed_pos;
struct list_head node;
};
static void admac_modify(struct admac_data *ad, int reg, u32 mask, u32 val)
{
void __iomem *addr = ad->base + reg;
u32 curr = readl_relaxed(addr);
writel_relaxed((curr & ~mask) | (val & mask), addr);
}
static struct admac_chan *to_admac_chan(struct dma_chan *chan)
{
return container_of(chan, struct admac_chan, chan);
}
static struct admac_tx *to_admac_tx(struct dma_async_tx_descriptor *tx)
{
return container_of(tx, struct admac_tx, tx);
}
static enum dma_transfer_direction admac_chan_direction(int channo)
{
/* Channel directions are hardwired */
return (channo & 1) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
}
static dma_cookie_t admac_tx_submit(struct dma_async_tx_descriptor *tx)
{
struct admac_tx *adtx = to_admac_tx(tx);
struct admac_chan *adchan = to_admac_chan(tx->chan);
unsigned long flags;
dma_cookie_t cookie;
spin_lock_irqsave(&adchan->lock, flags);
cookie = dma_cookie_assign(tx);
list_add_tail(&adtx->node, &adchan->submitted);
spin_unlock_irqrestore(&adchan->lock, flags);
return cookie;
}
static int admac_desc_free(struct dma_async_tx_descriptor *tx)
{
kfree(to_admac_tx(tx));
return 0;
}
static struct dma_async_tx_descriptor *admac_prep_dma_cyclic(
struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
size_t period_len, enum dma_transfer_direction direction,
unsigned long flags)
{
struct admac_chan *adchan = container_of(chan, struct admac_chan, chan);
struct admac_tx *adtx;
if (direction != admac_chan_direction(adchan->no))
return NULL;
adtx = kzalloc(sizeof(*adtx), GFP_NOWAIT);
if (!adtx)
return NULL;
adtx->cyclic = true;
adtx->buf_addr = buf_addr;
adtx->buf_len = buf_len;
adtx->buf_end = buf_addr + buf_len;
adtx->period_len = period_len;
adtx->submitted_pos = 0;
adtx->reclaimed_pos = 0;
dma_async_tx_descriptor_init(&adtx->tx, chan);
adtx->tx.tx_submit = admac_tx_submit;
adtx->tx.desc_free = admac_desc_free;
return &adtx->tx;
}
/*
* Write one hardware descriptor for a dmaengine cyclic transaction.
*/
static void admac_cyclic_write_one_desc(struct admac_data *ad, int channo,
struct admac_tx *tx)
{
dma_addr_t addr;
addr = tx->buf_addr + (tx->submitted_pos % tx->buf_len);
/* If happens means we have buggy code */
WARN_ON_ONCE(addr + tx->period_len > tx->buf_end);
dev_dbg(ad->dev, "ch%d descriptor: addr=0x%pad len=0x%zx flags=0x%lx\n",
channo, &addr, tx->period_len, FLAG_DESC_NOTIFY);
writel_relaxed(lower_32_bits(addr), ad->base + REG_DESC_WRITE(channo));
writel_relaxed(upper_32_bits(addr), ad->base + REG_DESC_WRITE(channo));
writel_relaxed(tx->period_len, ad->base + REG_DESC_WRITE(channo));
writel_relaxed(FLAG_DESC_NOTIFY, ad->base + REG_DESC_WRITE(channo));
tx->submitted_pos += tx->period_len;
tx->submitted_pos %= 2 * tx->buf_len;
}
/*
* Write all the hardware descriptors for a dmaengine cyclic
* transaction there is space for.
*/
static void admac_cyclic_write_desc(struct admac_data *ad, int channo,
struct admac_tx *tx)
{
int i;
for (i = 0; i < 4; i++) {
if (readl_relaxed(ad->base + REG_DESC_RING(channo)) & RING_FULL)
break;
admac_cyclic_write_one_desc(ad, channo, tx);
}
}
static int admac_ring_noccupied_slots(int ringval)
{
int wrslot = FIELD_GET(RING_WRITE_SLOT, ringval);
int rdslot = FIELD_GET(RING_READ_SLOT, ringval);
if (wrslot != rdslot) {
return (wrslot + 4 - rdslot) % 4;
} else {
WARN_ON((ringval & (RING_FULL | RING_EMPTY)) == 0);
if (ringval & RING_FULL)
return 4;
else
return 0;
}
}
/*
* Read from hardware the residue of a cyclic dmaengine transaction.
*/
static u32 admac_cyclic_read_residue(struct admac_data *ad, int channo,
struct admac_tx *adtx)
{
u32 ring1, ring2;
u32 residue1, residue2;
int nreports;
size_t pos;
ring1 = readl_relaxed(ad->base + REG_REPORT_RING(channo));
residue1 = readl_relaxed(ad->base + REG_RESIDUE(channo));
ring2 = readl_relaxed(ad->base + REG_REPORT_RING(channo));
residue2 = readl_relaxed(ad->base + REG_RESIDUE(channo));
if (residue2 > residue1) {
/*
* Controller must have loaded next descriptor between
* the two residue reads
*/
nreports = admac_ring_noccupied_slots(ring1) + 1;
} else {
/* No descriptor load between the two reads, ring2 is safe to use */
nreports = admac_ring_noccupied_slots(ring2);
}
pos = adtx->reclaimed_pos + adtx->period_len * (nreports + 1) - residue2;
return adtx->buf_len - pos % adtx->buf_len;
}
static enum dma_status admac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
struct admac_chan *adchan = to_admac_chan(chan);
struct admac_data *ad = adchan->host;
struct admac_tx *adtx;
enum dma_status ret;
size_t residue;
unsigned long flags;
ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_COMPLETE || !txstate)
return ret;
spin_lock_irqsave(&adchan->lock, flags);
adtx = adchan->current_tx;
if (adtx && adtx->tx.cookie == cookie) {
ret = DMA_IN_PROGRESS;
residue = admac_cyclic_read_residue(ad, adchan->no, adtx);
} else {
ret = DMA_IN_PROGRESS;
residue = 0;
list_for_each_entry(adtx, &adchan->issued, node) {
if (adtx->tx.cookie == cookie) {
residue = adtx->buf_len;
break;
}
}
}
spin_unlock_irqrestore(&adchan->lock, flags);
dma_set_residue(txstate, residue);
return ret;
}
static void admac_start_chan(struct admac_chan *adchan)
{
struct admac_data *ad = adchan->host;
u32 startbit = 1 << (adchan->no / 2);
writel_relaxed(STATUS_DESC_DONE | STATUS_ERR,
ad->base + REG_CHAN_INTSTATUS(adchan->no, ad->irq_index));
writel_relaxed(STATUS_DESC_DONE | STATUS_ERR,
ad->base + REG_CHAN_INTMASK(adchan->no, ad->irq_index));
switch (admac_chan_direction(adchan->no)) {
case DMA_MEM_TO_DEV:
writel_relaxed(startbit, ad->base + REG_TX_START);
break;
case DMA_DEV_TO_MEM:
writel_relaxed(startbit, ad->base + REG_RX_START);
break;
default:
break;
}
dev_dbg(adchan->host->dev, "ch%d start\n", adchan->no);
}
static void admac_stop_chan(struct admac_chan *adchan)
{
struct admac_data *ad = adchan->host;
u32 stopbit = 1 << (adchan->no / 2);
switch (admac_chan_direction(adchan->no)) {
case DMA_MEM_TO_DEV:
writel_relaxed(stopbit, ad->base + REG_TX_STOP);
break;
case DMA_DEV_TO_MEM:
writel_relaxed(stopbit, ad->base + REG_RX_STOP);
break;
default:
break;
}
dev_dbg(adchan->host->dev, "ch%d stop\n", adchan->no);
}
static void admac_reset_rings(struct admac_chan *adchan)
{
struct admac_data *ad = adchan->host;
writel_relaxed(REG_CHAN_CTL_RST_RINGS,
ad->base + REG_CHAN_CTL(adchan->no));
writel_relaxed(0, ad->base + REG_CHAN_CTL(adchan->no));
}
static void admac_start_current_tx(struct admac_chan *adchan)
{
struct admac_data *ad = adchan->host;
int ch = adchan->no;
admac_reset_rings(adchan);
writel_relaxed(0, ad->base + REG_CHAN_CTL(ch));
admac_cyclic_write_one_desc(ad, ch, adchan->current_tx);
admac_start_chan(adchan);
admac_cyclic_write_desc(ad, ch, adchan->current_tx);
}
static void admac_issue_pending(struct dma_chan *chan)
{
struct admac_chan *adchan = to_admac_chan(chan);
struct admac_tx *tx;
unsigned long flags;
spin_lock_irqsave(&adchan->lock, flags);
list_splice_tail_init(&adchan->submitted, &adchan->issued);
if (!list_empty(&adchan->issued) && !adchan->current_tx) {
tx = list_first_entry(&adchan->issued, struct admac_tx, node);
list_del(&tx->node);
adchan->current_tx = tx;
adchan->nperiod_acks = 0;
admac_start_current_tx(adchan);
}
spin_unlock_irqrestore(&adchan->lock, flags);
}
static int admac_pause(struct dma_chan *chan)
{
struct admac_chan *adchan = to_admac_chan(chan);
admac_stop_chan(adchan);
return 0;
}
static int admac_resume(struct dma_chan *chan)
{
struct admac_chan *adchan = to_admac_chan(chan);
admac_start_chan(adchan);
return 0;
}
static int admac_terminate_all(struct dma_chan *chan)
{
struct admac_chan *adchan = to_admac_chan(chan);
unsigned long flags;
spin_lock_irqsave(&adchan->lock, flags);
admac_stop_chan(adchan);
admac_reset_rings(adchan);
adchan->current_tx = NULL;
/*
* Descriptors can only be freed after the tasklet
* has been killed (in admac_synchronize).
*/
list_splice_tail_init(&adchan->submitted, &adchan->to_free);
list_splice_tail_init(&adchan->issued, &adchan->to_free);
spin_unlock_irqrestore(&adchan->lock, flags);
return 0;
}
static void admac_synchronize(struct dma_chan *chan)
{
struct admac_chan *adchan = to_admac_chan(chan);
struct admac_tx *adtx, *_adtx;
unsigned long flags;
LIST_HEAD(head);
spin_lock_irqsave(&adchan->lock, flags);
list_splice_tail_init(&adchan->to_free, &head);
spin_unlock_irqrestore(&adchan->lock, flags);
tasklet_kill(&adchan->tasklet);
list_for_each_entry_safe(adtx, _adtx, &head, node) {
list_del(&adtx->node);
admac_desc_free(&adtx->tx);
}
}
static int admac_alloc_chan_resources(struct dma_chan *chan)
{
struct admac_chan *adchan = to_admac_chan(chan);
dma_cookie_init(&adchan->chan);
return 0;
}
static void admac_free_chan_resources(struct dma_chan *chan)
{
admac_terminate_all(chan);
admac_synchronize(chan);
}
static struct dma_chan *admac_dma_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct admac_data *ad = (struct admac_data *) ofdma->of_dma_data;
unsigned int index;
if (dma_spec->args_count != 1)
return NULL;
index = dma_spec->args[0];
if (index >= ad->nchannels) {
dev_err(ad->dev, "channel index %u out of bounds\n", index);
return NULL;
}
return &ad->channels[index].chan;
}
static int admac_drain_reports(struct admac_data *ad, int channo)
{
int count;
for (count = 0; count < 4; count++) {
u32 countval_hi, countval_lo, unk1, flags;
if (readl_relaxed(ad->base + REG_REPORT_RING(channo)) & RING_EMPTY)
break;
countval_lo = readl_relaxed(ad->base + REG_REPORT_READ(channo));
countval_hi = readl_relaxed(ad->base + REG_REPORT_READ(channo));
unk1 = readl_relaxed(ad->base + REG_REPORT_READ(channo));
flags = readl_relaxed(ad->base + REG_REPORT_READ(channo));
dev_dbg(ad->dev, "ch%d report: countval=0x%llx unk1=0x%x flags=0x%x\n",
channo, ((u64) countval_hi) << 32 | countval_lo, unk1, flags);
}
return count;
}
static void admac_handle_status_err(struct admac_data *ad, int channo)
{
bool handled = false;
if (readl_relaxed(ad->base + REG_DESC_RING(channo)) & RING_ERR) {
writel_relaxed(RING_ERR, ad->base + REG_DESC_RING(channo));
dev_err_ratelimited(ad->dev, "ch%d descriptor ring error\n", channo);
handled = true;
}
if (readl_relaxed(ad->base + REG_REPORT_RING(channo)) & RING_ERR) {
writel_relaxed(RING_ERR, ad->base + REG_REPORT_RING(channo));
dev_err_ratelimited(ad->dev, "ch%d report ring error\n", channo);
handled = true;
}
if (unlikely(!handled)) {
dev_err(ad->dev, "ch%d unknown error, masking errors as cause of IRQs\n", channo);
admac_modify(ad, REG_CHAN_INTMASK(channo, ad->irq_index),
STATUS_ERR, 0);
}
}
static void admac_handle_status_desc_done(struct admac_data *ad, int channo)
{
struct admac_chan *adchan = &ad->channels[channo];
unsigned long flags;
int nreports;
writel_relaxed(STATUS_DESC_DONE,
ad->base + REG_CHAN_INTSTATUS(channo, ad->irq_index));
spin_lock_irqsave(&adchan->lock, flags);
nreports = admac_drain_reports(ad, channo);
if (adchan->current_tx) {
struct admac_tx *tx = adchan->current_tx;
adchan->nperiod_acks += nreports;
tx->reclaimed_pos += nreports * tx->period_len;
tx->reclaimed_pos %= 2 * tx->buf_len;
admac_cyclic_write_desc(ad, channo, tx);
tasklet_schedule(&adchan->tasklet);
}
spin_unlock_irqrestore(&adchan->lock, flags);
}
static void admac_handle_chan_int(struct admac_data *ad, int no)
{
u32 cause = readl_relaxed(ad->base + REG_CHAN_INTSTATUS(no, ad->irq_index));
if (cause & STATUS_ERR)
admac_handle_status_err(ad, no);
if (cause & STATUS_DESC_DONE)
admac_handle_status_desc_done(ad, no);
}
static irqreturn_t admac_interrupt(int irq, void *devid)
{
struct admac_data *ad = devid;
u32 rx_intstate, tx_intstate;
int i;
rx_intstate = readl_relaxed(ad->base + REG_RX_INTSTATE(ad->irq_index));
tx_intstate = readl_relaxed(ad->base + REG_TX_INTSTATE(ad->irq_index));
if (!tx_intstate && !rx_intstate)
return IRQ_NONE;
for (i = 0; i < ad->nchannels; i += 2) {
if (tx_intstate & 1)
admac_handle_chan_int(ad, i);
tx_intstate >>= 1;
}
for (i = 1; i < ad->nchannels; i += 2) {
if (rx_intstate & 1)
admac_handle_chan_int(ad, i);
rx_intstate >>= 1;
}
return IRQ_HANDLED;
}
static void admac_chan_tasklet(struct tasklet_struct *t)
{
struct admac_chan *adchan = from_tasklet(adchan, t, tasklet);
struct admac_tx *adtx;
struct dmaengine_desc_callback cb;
struct dmaengine_result tx_result;
int nacks;
spin_lock_irq(&adchan->lock);
adtx = adchan->current_tx;
nacks = adchan->nperiod_acks;
adchan->nperiod_acks = 0;
spin_unlock_irq(&adchan->lock);
if (!adtx || !nacks)
return;
tx_result.result = DMA_TRANS_NOERROR;
tx_result.residue = 0;
dmaengine_desc_get_callback(&adtx->tx, &cb);
while (nacks--)
dmaengine_desc_callback_invoke(&cb, &tx_result);
}
static int admac_device_config(struct dma_chan *chan,
struct dma_slave_config *config)
{
struct admac_chan *adchan = to_admac_chan(chan);
struct admac_data *ad = adchan->host;
bool is_tx = admac_chan_direction(adchan->no) == DMA_MEM_TO_DEV;
int wordsize = 0;
u32 bus_width = 0;
switch (is_tx ? config->dst_addr_width : config->src_addr_width) {
case DMA_SLAVE_BUSWIDTH_1_BYTE:
wordsize = 1;
bus_width |= BUS_WIDTH_8BIT;
break;
case DMA_SLAVE_BUSWIDTH_2_BYTES:
wordsize = 2;
bus_width |= BUS_WIDTH_16BIT;
break;
case DMA_SLAVE_BUSWIDTH_4_BYTES:
wordsize = 4;
bus_width |= BUS_WIDTH_32BIT;
break;
default:
return -EINVAL;
}
/*
* We take port_window_size to be the number of words in a frame.
*
* The controller has some means of out-of-band signalling, to the peripheral,
* of words position in a frame. That's where the importance of this control
* comes from.
*/
switch (is_tx ? config->dst_port_window_size : config->src_port_window_size) {
case 0 ... 1:
break;
case 2:
bus_width |= BUS_WIDTH_FRAME_2_WORDS;
break;
case 4:
bus_width |= BUS_WIDTH_FRAME_4_WORDS;
break;
default:
return -EINVAL;
}
writel_relaxed(bus_width, ad->base + REG_BUS_WIDTH(adchan->no));
/*
* By FIFOCTL_LIMIT we seem to set the maximal number of bytes allowed to be
* held in controller's per-channel FIFO. Transfers seem to be triggered
* around the time FIFO occupancy touches FIFOCTL_THRESHOLD.
*
* The numbers we set are more or less arbitrary.
*/
writel_relaxed(FIELD_PREP(CHAN_FIFOCTL_LIMIT, 0x30 * wordsize)
| FIELD_PREP(CHAN_FIFOCTL_THRESHOLD, 0x18 * wordsize),
ad->base + REG_CHAN_FIFOCTL(adchan->no));
return 0;
}
static int admac_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct admac_data *ad;
struct dma_device *dma;
int nchannels;
int err, irq, i;
err = of_property_read_u32(np, "dma-channels", &nchannels);
if (err || nchannels > NCHANNELS_MAX) {
dev_err(&pdev->dev, "missing or invalid dma-channels property\n");
return -EINVAL;
}
ad = devm_kzalloc(&pdev->dev, struct_size(ad, channels, nchannels), GFP_KERNEL);
if (!ad)
return -ENOMEM;
platform_set_drvdata(pdev, ad);
ad->dev = &pdev->dev;
ad->nchannels = nchannels;
/*
* The controller has 4 IRQ outputs. Try them all until
* we find one we can use.
*/
for (i = 0; i < IRQ_NOUTPUTS; i++) {
irq = platform_get_irq_optional(pdev, i);
if (irq >= 0) {
ad->irq_index = i;
break;
}
}
if (irq < 0)
return dev_err_probe(&pdev->dev, irq, "no usable interrupt\n");
err = devm_request_irq(&pdev->dev, irq, admac_interrupt,
0, dev_name(&pdev->dev), ad);
if (err)
return dev_err_probe(&pdev->dev, err,
"unable to register interrupt\n");
ad->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ad->base))
return dev_err_probe(&pdev->dev, PTR_ERR(ad->base),
"unable to obtain MMIO resource\n");
dma = &ad->dma;
dma_cap_set(DMA_PRIVATE, dma->cap_mask);
dma_cap_set(DMA_CYCLIC, dma->cap_mask);
dma->dev = &pdev->dev;
dma->device_alloc_chan_resources = admac_alloc_chan_resources;
dma->device_free_chan_resources = admac_free_chan_resources;
dma->device_tx_status = admac_tx_status;
dma->device_issue_pending = admac_issue_pending;
dma->device_terminate_all = admac_terminate_all;
dma->device_synchronize = admac_synchronize;
dma->device_prep_dma_cyclic = admac_prep_dma_cyclic;
dma->device_config = admac_device_config;
dma->device_pause = admac_pause;
dma->device_resume = admac_resume;
dma->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
dma->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
INIT_LIST_HEAD(&dma->channels);
for (i = 0; i < nchannels; i++) {
struct admac_chan *adchan = &ad->channels[i];
adchan->host = ad;
adchan->no = i;
adchan->chan.device = &ad->dma;
spin_lock_init(&adchan->lock);
INIT_LIST_HEAD(&adchan->submitted);
INIT_LIST_HEAD(&adchan->issued);
INIT_LIST_HEAD(&adchan->to_free);
list_add_tail(&adchan->chan.device_node, &dma->channels);
tasklet_setup(&adchan->tasklet, admac_chan_tasklet);
}
err = dma_async_device_register(&ad->dma);
if (err)
return dev_err_probe(&pdev->dev, err, "failed to register DMA device\n");
err = of_dma_controller_register(pdev->dev.of_node, admac_dma_of_xlate, ad);
if (err) {
dma_async_device_unregister(&ad->dma);
return dev_err_probe(&pdev->dev, err, "failed to register with OF\n");
}
return 0;
}
static int admac_remove(struct platform_device *pdev)
{
struct admac_data *ad = platform_get_drvdata(pdev);
of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&ad->dma);
return 0;
}
static const struct of_device_id admac_of_match[] = {
{ .compatible = "apple,admac", },
{ }
};
MODULE_DEVICE_TABLE(of, admac_of_match);
static struct platform_driver apple_admac_driver = {
.driver = {
.name = "apple-admac",
.of_match_table = admac_of_match,
},
.probe = admac_probe,
.remove = admac_remove,
};
module_platform_driver(apple_admac_driver);
MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
MODULE_DESCRIPTION("Driver for Audio DMA Controller (ADMAC) on Apple SoCs");
MODULE_LICENSE("GPL");

View File

@@ -649,7 +649,7 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
}
/*
* Only check that maxburst and addr width values are supported by the
* Only check that maxburst and addr width values are supported by
* the controller but not that the configuration is good to perform the
* transfer since we don't know the direction at this stage.
*/

View File

@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_dma.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -55,6 +56,9 @@
#define AXI_DMAC_DMA_DST_TYPE_GET(x) FIELD_GET(AXI_DMAC_DMA_DST_TYPE_MSK, x)
#define AXI_DMAC_DMA_DST_WIDTH_MSK GENMASK(3, 0)
#define AXI_DMAC_DMA_DST_WIDTH_GET(x) FIELD_GET(AXI_DMAC_DMA_DST_WIDTH_MSK, x)
#define AXI_DMAC_REG_COHERENCY_DESC 0x14
#define AXI_DMAC_DST_COHERENT_MSK BIT(0)
#define AXI_DMAC_DST_COHERENT_GET(x) FIELD_GET(AXI_DMAC_DST_COHERENT_MSK, x)
#define AXI_DMAC_REG_IRQ_MASK 0x80
#define AXI_DMAC_REG_IRQ_PENDING 0x84
@@ -979,6 +983,18 @@ static int axi_dmac_probe(struct platform_device *pdev)
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x00);
if (of_dma_is_coherent(pdev->dev.of_node)) {
ret = axi_dmac_read(dmac, AXI_DMAC_REG_COHERENCY_DESC);
if (version < ADI_AXI_PCORE_VER(4, 4, 'a') ||
!AXI_DMAC_DST_COHERENT_GET(ret)) {
dev_err(dmac->dma_dev.dev,
"Coherent DMA not supported in hardware");
ret = -EINVAL;
goto err_clk_disable;
}
}
ret = dma_async_device_register(dma_dev);
if (ret)
goto err_clk_disable;

View File

@@ -388,7 +388,7 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg(
if (i != (sg_len - 1) &&
!(jzdma->soc_data->flags & JZ_SOC_DATA_BREAK_LINKS)) {
/* Automatically proceeed to the next descriptor. */
/* Automatically proceed to the next descriptor. */
desc->desc[i].dcm |= JZ_DMA_DCM_LINK;
/*

View File

@@ -1153,13 +1153,6 @@ int dma_async_device_register(struct dma_device *device)
return -EIO;
}
if (dma_has_cap(DMA_MEMCPY_SG, device->cap_mask) && !device->device_prep_dma_memcpy_sg) {
dev_err(device->dev,
"Device claims capability %s, but op is not defined\n",
"DMA_MEMCPY_SG");
return -EIO;
}
if (dma_has_cap(DMA_XOR, device->cap_mask) && !device->device_prep_dma_xor) {
dev_err(device->dev,
"Device claims capability %s, but op is not defined\n",

View File

@@ -22,51 +22,50 @@
#include <linux/wait.h>
static unsigned int test_buf_size = 16384;
module_param(test_buf_size, uint, S_IRUGO | S_IWUSR);
module_param(test_buf_size, uint, 0644);
MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer");
static char test_device[32];
module_param_string(device, test_device, sizeof(test_device),
S_IRUGO | S_IWUSR);
module_param_string(device, test_device, sizeof(test_device), 0644);
MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)");
static unsigned int threads_per_chan = 1;
module_param(threads_per_chan, uint, S_IRUGO | S_IWUSR);
module_param(threads_per_chan, uint, 0644);
MODULE_PARM_DESC(threads_per_chan,
"Number of threads to start per channel (default: 1)");
static unsigned int max_channels;
module_param(max_channels, uint, S_IRUGO | S_IWUSR);
module_param(max_channels, uint, 0644);
MODULE_PARM_DESC(max_channels,
"Maximum number of channels to use (default: all)");
static unsigned int iterations;
module_param(iterations, uint, S_IRUGO | S_IWUSR);
module_param(iterations, uint, 0644);
MODULE_PARM_DESC(iterations,
"Iterations before stopping test (default: infinite)");
static unsigned int dmatest;
module_param(dmatest, uint, S_IRUGO | S_IWUSR);
module_param(dmatest, uint, 0644);
MODULE_PARM_DESC(dmatest,
"dmatest 0-memcpy 1-memset (default: 0)");
static unsigned int xor_sources = 3;
module_param(xor_sources, uint, S_IRUGO | S_IWUSR);
module_param(xor_sources, uint, 0644);
MODULE_PARM_DESC(xor_sources,
"Number of xor source buffers (default: 3)");
static unsigned int pq_sources = 3;
module_param(pq_sources, uint, S_IRUGO | S_IWUSR);
module_param(pq_sources, uint, 0644);
MODULE_PARM_DESC(pq_sources,
"Number of p+q source buffers (default: 3)");
static int timeout = 3000;
module_param(timeout, int, S_IRUGO | S_IWUSR);
module_param(timeout, int, 0644);
MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
"Pass -1 for infinite timeout");
static bool noverify;
module_param(noverify, bool, S_IRUGO | S_IWUSR);
module_param(noverify, bool, 0644);
MODULE_PARM_DESC(noverify, "Disable data verification (default: verify)");
static bool norandom;
@@ -74,7 +73,7 @@ module_param(norandom, bool, 0644);
MODULE_PARM_DESC(norandom, "Disable random offset setup (default: random)");
static bool verbose;
module_param(verbose, bool, S_IRUGO | S_IWUSR);
module_param(verbose, bool, 0644);
MODULE_PARM_DESC(verbose, "Enable \"success\" result messages (default: off)");
static int alignment = -1;
@@ -86,7 +85,7 @@ module_param(transfer_size, uint, 0644);
MODULE_PARM_DESC(transfer_size, "Optional custom transfer size in bytes (default: not used (0))");
static bool polled;
module_param(polled, bool, S_IRUGO | S_IWUSR);
module_param(polled, bool, 0644);
MODULE_PARM_DESC(polled, "Use polling for completion instead of interrupts");
/**
@@ -154,7 +153,7 @@ static const struct kernel_param_ops run_ops = {
.get = dmatest_run_get,
};
static bool dmatest_run;
module_param_cb(run, &run_ops, &dmatest_run, S_IRUGO | S_IWUSR);
module_param_cb(run, &run_ops, &dmatest_run, 0644);
MODULE_PARM_DESC(run, "Run the test (default: false)");
static int dmatest_chan_set(const char *val, const struct kernel_param *kp);
@@ -290,7 +289,7 @@ static const struct kernel_param_ops wait_ops = {
.get = dmatest_wait_get,
.set = param_set_bool,
};
module_param_cb(wait, &wait_ops, &wait, S_IRUGO);
module_param_cb(wait, &wait_ops, &wait, 0444);
MODULE_PARM_DESC(wait, "Wait for tests to complete (default: false)");
static bool dmatest_match_channel(struct dmatest_params *params,
@@ -579,10 +578,10 @@ static int dmatest_func(void *data)
unsigned int total_tests = 0;
dma_cookie_t cookie;
enum dma_status status;
enum dma_ctrl_flags flags;
enum dma_ctrl_flags flags;
u8 *pq_coefs = NULL;
int ret;
unsigned int buf_size;
unsigned int buf_size;
struct dmatest_data *src;
struct dmatest_data *dst;
int i;
@@ -1095,8 +1094,8 @@ static void add_threaded_test(struct dmatest_info *info)
/* Copy test parameters */
params->buf_size = test_buf_size;
strlcpy(params->channel, strim(test_channel), sizeof(params->channel));
strlcpy(params->device, strim(test_device), sizeof(params->device));
strscpy(params->channel, strim(test_channel), sizeof(params->channel));
strscpy(params->device, strim(test_device), sizeof(params->device));
params->threads_per_chan = threads_per_chan;
params->max_channels = max_channels;
params->iterations = iterations;
@@ -1240,7 +1239,7 @@ static int dmatest_chan_set(const char *val, const struct kernel_param *kp)
dtc = list_last_entry(&info->channels,
struct dmatest_chan,
node);
strlcpy(chan_reset_val,
strscpy(chan_reset_val,
dma_chan_name(dtc->chan),
sizeof(chan_reset_val));
ret = -EBUSY;
@@ -1263,14 +1262,14 @@ static int dmatest_chan_set(const char *val, const struct kernel_param *kp)
if ((strcmp(dma_chan_name(dtc->chan), strim(test_channel)) != 0)
&& (strcmp("", strim(test_channel)) != 0)) {
ret = -EINVAL;
strlcpy(chan_reset_val, dma_chan_name(dtc->chan),
strscpy(chan_reset_val, dma_chan_name(dtc->chan),
sizeof(chan_reset_val));
goto add_chan_err;
}
} else {
/* Clear test_channel if no channels were added successfully */
strlcpy(chan_reset_val, "", sizeof(chan_reset_val));
strscpy(chan_reset_val, "", sizeof(chan_reset_val));
ret = -EBUSY;
goto add_chan_err;
}
@@ -1295,7 +1294,7 @@ static int dmatest_chan_get(char *val, const struct kernel_param *kp)
mutex_lock(&info->lock);
if (!is_threaded_test_run(info) && !is_threaded_test_pending(info)) {
stop_threaded_test(info);
strlcpy(test_channel, "", sizeof(test_channel));
strscpy(test_channel, "", sizeof(test_channel));
}
mutex_unlock(&info->lock);

View File

@@ -982,6 +982,11 @@ static int dw_axi_dma_chan_slave_config(struct dma_chan *dchan,
static void axi_chan_dump_lli(struct axi_dma_chan *chan,
struct axi_dma_hw_desc *desc)
{
if (!desc->lli) {
dev_err(dchan2dev(&chan->vc.chan), "NULL LLI\n");
return;
}
dev_err(dchan2dev(&chan->vc.chan),
"SAR: 0x%llx DAR: 0x%llx LLP: 0x%llx BTS 0x%x CTL: 0x%x:%08x",
le64_to_cpu(desc->lli->sar),
@@ -1049,6 +1054,11 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)
/* The completed descriptor currently is in the head of vc list */
vd = vchan_next_desc(&chan->vc);
if (!vd) {
dev_err(chan2dev(chan), "BUG: %s, IRQ with no descriptors\n",
axi_chan_name(chan));
goto out;
}
if (chan->cyclic) {
desc = vd_to_axi_desc(vd);
@@ -1078,6 +1088,7 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)
axi_chan_start_first_queued(chan);
}
out:
spin_unlock_irqrestore(&chan->vc.lock, flags);
}

View File

@@ -417,19 +417,11 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
SET_CH_32(dw, chan->dir, chan->id, ch_control1,
(DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
/* Linked list */
#ifdef CONFIG_64BIT
/* llp is not aligned on 64bit -> keep 32bit accesses */
SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
lower_32_bits(chunk->ll_region.paddr));
SET_CH_32(dw, chan->dir, chan->id, llp.msb,
upper_32_bits(chunk->ll_region.paddr));
#else /* CONFIG_64BIT */
SET_CH_32(dw, chan->dir, chan->id, llp.lsb,
lower_32_bits(chunk->ll_region.paddr));
SET_CH_32(dw, chan->dir, chan->id, llp.msb,
upper_32_bits(chunk->ll_region.paddr));
#endif /* CONFIG_64BIT */
}
/* Doorbell */
SET_RW_32(dw, chan->dir, doorbell,

View File

@@ -102,10 +102,12 @@ free_map:
return ERR_PTR(ret);
}
#ifdef CONFIG_OF
static const struct of_device_id rzn1_dmac_match[] = {
{ .compatible = "renesas,rzn1-dma" },
{}
};
#endif
static int rzn1_dmamux_probe(struct platform_device *pdev)
{
@@ -140,6 +142,7 @@ static const struct of_device_id rzn1_dmamux_match[] = {
{ .compatible = "renesas,rzn1-dmamux" },
{}
};
MODULE_DEVICE_TABLE(of, rzn1_dmamux_match);
static struct platform_driver rzn1_dmamux_driver = {
.driver = {

View File

@@ -1183,7 +1183,7 @@ fail:
*
* Synchronizes the DMA channel termination to the current context. When this
* function returns it is guaranteed that all transfers for previously issued
* descriptors have stopped and and it is safe to free the memory associated
* descriptors have stopped and it is safe to free the memory associated
* with them. Furthermore it is guaranteed that all complete callback functions
* for a previously submitted descriptor have finished running and it is safe to
* free resources accessed from within the complete callbacks.

View File

@@ -559,9 +559,6 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
}
for_each_sg(sgl, sg, sg_len, i) {
/* get next sg's physical address */
last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
if (direction == DMA_MEM_TO_DEV) {
src_addr = sg_dma_address(sg);
dst_addr = fsl_chan->dma_dev_addr;

View File

@@ -1047,7 +1047,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
return -ENOMEM;
imxdma->dev = &pdev->dev;
imxdma->devtype = (enum imx_dma_type)of_device_get_match_data(&pdev->dev);
imxdma->devtype = (uintptr_t)of_device_get_match_data(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
imxdma->base = devm_ioremap_resource(&pdev->dev, res);

View File

@@ -183,12 +183,14 @@
BIT(DMA_DEV_TO_DEV))
#define SDMA_WATERMARK_LEVEL_N_FIFOS GENMASK(15, 12)
#define SDMA_WATERMARK_LEVEL_OFF_FIFOS GENMASK(19, 16)
#define SDMA_WATERMARK_LEVEL_WORDS_PER_FIFO GENMASK(31, 28)
#define SDMA_WATERMARK_LEVEL_SW_DONE BIT(23)
#define SDMA_DONE0_CONFIG_DONE_SEL BIT(7)
#define SDMA_DONE0_CONFIG_DONE_DIS BIT(6)
/**
/*
* struct sdma_script_start_addrs - SDMA script start pointers
*
* start addresses of the different functions in the physical
@@ -424,6 +426,14 @@ struct sdma_desc {
* @data: specific sdma interface structure
* @bd_pool: dma_pool for bd
* @terminate_worker: used to call back into terminate work function
* @terminated: terminated list
* @is_ram_script: flag for script in ram
* @n_fifos_src: number of source device fifos
* @n_fifos_dst: number of destination device fifos
* @sw_done: software done flag
* @stride_fifos_src: stride for source device FIFOs
* @stride_fifos_dst: stride for destination device FIFOs
* @words_per_fifo: copy number of words one time for one FIFO
*/
struct sdma_channel {
struct virt_dma_chan vc;
@@ -451,6 +461,9 @@ struct sdma_channel {
bool is_ram_script;
unsigned int n_fifos_src;
unsigned int n_fifos_dst;
unsigned int stride_fifos_src;
unsigned int stride_fifos_dst;
unsigned int words_per_fifo;
bool sw_done;
};
@@ -1240,17 +1253,29 @@ static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
static void sdma_set_watermarklevel_for_sais(struct sdma_channel *sdmac)
{
unsigned int n_fifos;
unsigned int stride_fifos;
unsigned int words_per_fifo;
if (sdmac->sw_done)
sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SW_DONE;
if (sdmac->direction == DMA_DEV_TO_MEM)
if (sdmac->direction == DMA_DEV_TO_MEM) {
n_fifos = sdmac->n_fifos_src;
else
stride_fifos = sdmac->stride_fifos_src;
} else {
n_fifos = sdmac->n_fifos_dst;
stride_fifos = sdmac->stride_fifos_dst;
}
words_per_fifo = sdmac->words_per_fifo;
sdmac->watermark_level |=
FIELD_PREP(SDMA_WATERMARK_LEVEL_N_FIFOS, n_fifos);
sdmac->watermark_level |=
FIELD_PREP(SDMA_WATERMARK_LEVEL_OFF_FIFOS, stride_fifos);
if (words_per_fifo)
sdmac->watermark_level |=
FIELD_PREP(SDMA_WATERMARK_LEVEL_WORDS_PER_FIFO, (words_per_fifo - 1));
}
static int sdma_config_channel(struct dma_chan *chan)
@@ -1764,6 +1789,9 @@ static int sdma_config(struct dma_chan *chan,
}
sdmac->n_fifos_src = sdmacfg->n_fifos_src;
sdmac->n_fifos_dst = sdmacfg->n_fifos_dst;
sdmac->stride_fifos_src = sdmacfg->stride_fifos_src;
sdmac->stride_fifos_dst = sdmacfg->stride_fifos_dst;
sdmac->words_per_fifo = sdmacfg->words_per_fifo;
sdmac->sw_done = sdmacfg->sw_done;
}
@@ -2183,8 +2211,8 @@ static int sdma_probe(struct platform_device *pdev)
if (ret)
goto err_clk;
ret = devm_request_irq(&pdev->dev, irq, sdma_int_handler, 0, "sdma",
sdma);
ret = devm_request_irq(&pdev->dev, irq, sdma_int_handler, 0,
dev_name(&pdev->dev), sdma);
if (ret)
goto err_irq;

View File

@@ -373,7 +373,7 @@ static void mtk_cqdma_tasklet_cb(struct tasklet_struct *t)
/*
* free child CVD after completion.
* the parent CVD would be freeed with desc_free by user.
* the parent CVD would be freed with desc_free by user.
*/
if (cvd->parent != cvd)
kfree(cvd);

View File

@@ -138,7 +138,7 @@ struct mtk_hsdma_vdesc {
/**
* struct mtk_hsdma_cb - This is the struct holding extra info required for RX
* ring to know what relevant VD the the PD is being
* ring to know what relevant VD the PD is being
* mapped to.
* @vd: Pointer to the relevant VD.
* @flag: Flag indicating what action should be taken when VD
@@ -761,7 +761,7 @@ static void mtk_hsdma_free_active_desc(struct dma_chan *c)
/*
* Once issue_synchronize is being set, which means once the hardware
* consumes all descriptors for the channel in the ring, the
* synchronization must be be notified immediately it is completed.
* synchronization must be notified immediately it is completed.
*/
spin_lock(&hvc->vc.lock);
if (!list_empty(&hvc->desc_hw_processing)) {

View File

@@ -313,7 +313,7 @@ mv_xor_v2_tx_submit(struct dma_async_tx_descriptor *tx)
"%s sw_desc %p: async_tx %p\n",
__func__, sw_desc, &sw_desc->async_tx);
/* assign coookie */
/* assign cookie */
spin_lock_bh(&xor_dev->lock);
cookie = dma_cookie_assign(tx);

View File

@@ -193,7 +193,7 @@ struct owl_dma_pchan {
/**
* struct owl_dma_pchan - Wrapper for DMA ENGINE channel
* @vc: wrappped virtual channel
* @vc: wrapped virtual channel
* @pchan: the physical channel utilized by this channel
* @txd: active transaction on this channel
* @cfg: slave configuration for this channel

View File

@@ -202,7 +202,7 @@ struct s3c24xx_dma_phy {
* struct s3c24xx_dma_chan - this structure wraps a DMA ENGINE channel
* @id: the id of the channel
* @name: name of the channel
* @vc: wrappped virtual channel
* @vc: wrapped virtual channel
* @phy: the physical channel utilized by this channel, if there is one
* @runtime_addr: address for RX/TX according to the runtime config
* @at: active transaction on this channel

View File

@@ -52,16 +52,6 @@ static inline struct sf_pdma_desc *to_sf_pdma_desc(struct virt_dma_desc *vd)
static struct sf_pdma_desc *sf_pdma_alloc_desc(struct sf_pdma_chan *chan)
{
struct sf_pdma_desc *desc;
unsigned long flags;
spin_lock_irqsave(&chan->lock, flags);
if (chan->desc && !chan->desc->in_use) {
spin_unlock_irqrestore(&chan->lock, flags);
return chan->desc;
}
spin_unlock_irqrestore(&chan->lock, flags);
desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
if (!desc)
@@ -111,7 +101,6 @@ sf_pdma_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dest, dma_addr_t src,
desc->async_tx = vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
spin_lock_irqsave(&chan->vchan.lock, iflags);
chan->desc = desc;
sf_pdma_fill_desc(desc, dest, src, len);
spin_unlock_irqrestore(&chan->vchan.lock, iflags);
@@ -170,11 +159,17 @@ static size_t sf_pdma_desc_residue(struct sf_pdma_chan *chan,
unsigned long flags;
u64 residue = 0;
struct sf_pdma_desc *desc;
struct dma_async_tx_descriptor *tx;
struct dma_async_tx_descriptor *tx = NULL;
spin_lock_irqsave(&chan->vchan.lock, flags);
tx = &chan->desc->vdesc.tx;
list_for_each_entry(vd, &chan->vchan.desc_submitted, node)
if (vd->tx.cookie == cookie)
tx = &vd->tx;
if (!tx)
goto out;
if (cookie == tx->chan->completed_cookie)
goto out;
@@ -241,6 +236,19 @@ static void sf_pdma_enable_request(struct sf_pdma_chan *chan)
writel(v, regs->ctrl);
}
static struct sf_pdma_desc *sf_pdma_get_first_pending_desc(struct sf_pdma_chan *chan)
{
struct virt_dma_chan *vchan = &chan->vchan;
struct virt_dma_desc *vdesc;
if (list_empty(&vchan->desc_issued))
return NULL;
vdesc = list_first_entry(&vchan->desc_issued, struct virt_dma_desc, node);
return container_of(vdesc, struct sf_pdma_desc, vdesc);
}
static void sf_pdma_xfer_desc(struct sf_pdma_chan *chan)
{
struct sf_pdma_desc *desc = chan->desc;
@@ -268,8 +276,11 @@ static void sf_pdma_issue_pending(struct dma_chan *dchan)
spin_lock_irqsave(&chan->vchan.lock, flags);
if (vchan_issue_pending(&chan->vchan) && chan->desc)
if (!chan->desc && vchan_issue_pending(&chan->vchan)) {
/* vchan_issue_pending has made a check that desc in not NULL */
chan->desc = sf_pdma_get_first_pending_desc(chan);
sf_pdma_xfer_desc(chan);
}
spin_unlock_irqrestore(&chan->vchan.lock, flags);
}
@@ -298,6 +309,11 @@ static void sf_pdma_donebh_tasklet(struct tasklet_struct *t)
spin_lock_irqsave(&chan->vchan.lock, flags);
list_del(&chan->desc->vdesc.node);
vchan_cookie_complete(&chan->desc->vdesc);
chan->desc = sf_pdma_get_first_pending_desc(chan);
if (chan->desc)
sf_pdma_xfer_desc(chan);
spin_unlock_irqrestore(&chan->vchan.lock, flags);
}

View File

@@ -12,6 +12,7 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -630,6 +631,21 @@ static void rz_dmac_virt_desc_free(struct virt_dma_desc *vd)
*/
}
static void rz_dmac_device_synchronize(struct dma_chan *chan)
{
struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
struct rz_dmac *dmac = to_rz_dmac(chan->device);
u32 chstat;
int ret;
ret = read_poll_timeout(rz_dmac_ch_readl, chstat, !(chstat & CHSTAT_EN),
100, 100000, false, channel, CHSTAT, 1);
if (ret < 0)
dev_warn(dmac->dev, "DMA Timeout");
rz_dmac_set_dmars_register(dmac, channel->index, 0);
}
/*
* -----------------------------------------------------------------------------
* IRQ handling
@@ -909,6 +925,7 @@ static int rz_dmac_probe(struct platform_device *pdev)
engine->device_config = rz_dmac_config;
engine->device_terminate_all = rz_dmac_terminate_all;
engine->device_issue_pending = rz_dmac_issue_pending;
engine->device_synchronize = rz_dmac_device_synchronize;
engine->copy_align = DMAENGINE_ALIGN_1_BYTE;
dma_set_max_seg_size(engine->dev, U32_MAX);

View File

@@ -1237,11 +1237,8 @@ static int sprd_dma_remove(struct platform_device *pdev)
{
struct sprd_dma_dev *sdev = platform_get_drvdata(pdev);
struct sprd_dma_chn *c, *cn;
int ret;
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
return ret;
pm_runtime_get_sync(&pdev->dev);
/* explicitly free the irq */
if (sdev->irq > 0)

View File

@@ -1970,7 +1970,7 @@ static int d40_config_memcpy(struct d40_chan *d40c)
dma_has_cap(DMA_SLAVE, cap)) {
d40c->dma_cfg = dma40_memcpy_conf_phy;
/* Generate interrrupt at end of transfer or relink. */
/* Generate interrupt at end of transfer or relink. */
d40c->dst_def_cfg |= BIT(D40_SREG_CFG_TIM_POS);
/* Generate interrupt on error. */

View File

@@ -1328,12 +1328,7 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid)
return IRQ_NONE;
}
id = __ffs(status);
chan = &dmadev->chan[id];
if (!chan) {
dev_warn(mdma2dev(dmadev), "MDMA channel not initialized\n");
return IRQ_NONE;
}
/* Handle interrupt for the channel */
spin_lock(&chan->vchan.lock);

View File

@@ -7,6 +7,7 @@
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/interrupt.h>
@@ -122,6 +123,15 @@
SUN4I_DDMA_PARA_DST_WAIT_CYCLES(2) | \
SUN4I_DDMA_PARA_SRC_WAIT_CYCLES(2))
/*
* Normal DMA supports individual transfers (segments) up to 128k.
* Dedicated DMA supports transfers up to 16M. We can only report
* one size limit, so we have to use the smaller value.
*/
#define SUN4I_NDMA_MAX_SEG_SIZE SZ_128K
#define SUN4I_DDMA_MAX_SEG_SIZE SZ_16M
#define SUN4I_DMA_MAX_SEG_SIZE SUN4I_NDMA_MAX_SEG_SIZE
struct sun4i_dma_pchan {
/* Register base of channel */
void __iomem *base;
@@ -155,7 +165,8 @@ struct sun4i_dma_contract {
struct virt_dma_desc vd;
struct list_head demands;
struct list_head completed_demands;
int is_cyclic;
bool is_cyclic : 1;
bool use_half_int : 1;
};
struct sun4i_dma_dev {
@@ -372,7 +383,7 @@ static int __execute_vchan_pending(struct sun4i_dma_dev *priv,
if (promise) {
vchan->contract = contract;
vchan->pchan = pchan;
set_pchan_interrupt(priv, pchan, contract->is_cyclic, 1);
set_pchan_interrupt(priv, pchan, contract->use_half_int, 1);
configure_pchan(pchan, promise);
}
@@ -735,12 +746,21 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
*
* Which requires half the engine programming for the same
* functionality.
*
* This only works if two periods fit in a single promise. That will
* always be the case for dedicated DMA, where the hardware has a much
* larger maximum transfer size than advertised to clients.
*/
nr_periods = DIV_ROUND_UP(len / period_len, 2);
if (vchan->is_dedicated || period_len <= SUN4I_NDMA_MAX_SEG_SIZE / 2) {
period_len *= 2;
contract->use_half_int = 1;
}
nr_periods = DIV_ROUND_UP(len, period_len);
for (i = 0; i < nr_periods; i++) {
/* Calculate the offset in the buffer and the length needed */
offset = i * period_len * 2;
plength = min((len - offset), (period_len * 2));
offset = i * period_len;
plength = min((len - offset), period_len);
if (dir == DMA_MEM_TO_DEV)
src = buf + offset;
else
@@ -1149,6 +1169,8 @@ static int sun4i_dma_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
spin_lock_init(&priv->lock);
dma_set_max_seg_size(&pdev->dev, SUN4I_DMA_MAX_SEG_SIZE);
dma_cap_zero(priv->slave.cap_mask);
dma_cap_set(DMA_PRIVATE, priv->slave.cap_mask);
dma_cap_set(DMA_MEMCPY, priv->slave.cap_mask);

View File

@@ -157,8 +157,8 @@
* If any burst is in flight and DMA paused then this is the time to complete
* on-flight burst and update DMA status register.
*/
#define TEGRA_GPCDMA_BURST_COMPLETE_TIME 20
#define TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT 100
#define TEGRA_GPCDMA_BURST_COMPLETE_TIME 10
#define TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT 5000 /* 5 msec */
/* Channel base address offset from GPCDMA base address */
#define TEGRA_GPCDMA_CHANNEL_BASE_ADD_OFFSET 0x20000
@@ -432,6 +432,17 @@ static int tegra_dma_device_resume(struct dma_chan *dc)
return 0;
}
static inline int tegra_dma_pause_noerr(struct tegra_dma_channel *tdc)
{
/* Return 0 irrespective of PAUSE status.
* This is useful to recover channels that can exit out of flush
* state when the channel is disabled.
*/
tegra_dma_pause(tdc);
return 0;
}
static void tegra_dma_disable(struct tegra_dma_channel *tdc)
{
u32 csr, status;
@@ -1292,6 +1303,14 @@ static const struct tegra_dma_chip_data tegra194_dma_chip_data = {
.terminate = tegra_dma_pause,
};
static const struct tegra_dma_chip_data tegra234_dma_chip_data = {
.nr_channels = 31,
.channel_reg_size = SZ_64K,
.max_dma_count = SZ_1G,
.hw_support_pause = true,
.terminate = tegra_dma_pause_noerr,
};
static const struct of_device_id tegra_dma_of_match[] = {
{
.compatible = "nvidia,tegra186-gpcdma",
@@ -1299,6 +1318,9 @@ static const struct of_device_id tegra_dma_of_match[] = {
}, {
.compatible = "nvidia,tegra194-gpcdma",
.data = &tegra194_dma_chip_data,
}, {
.compatible = "nvidia,tegra234-gpcdma",
.data = &tegra234_dma_chip_data,
}, {
},
};

View File

@@ -112,6 +112,11 @@ static struct psil_ep j721s2_src_ep_map[] = {
PSIL_PDMA_XY_PKT(0x4707),
PSIL_PDMA_XY_PKT(0x4708),
PSIL_PDMA_XY_PKT(0x4709),
/* MAIN SA2UL */
PSIL_SA2UL(0x4a40, 0),
PSIL_SA2UL(0x4a41, 0),
PSIL_SA2UL(0x4a42, 0),
PSIL_SA2UL(0x4a43, 0),
/* CPSW0 */
PSIL_ETHERNET(0x7000),
/* MCU_PDMA0 (MCU_PDMA_MISC_G0) - SPI0 */
@@ -144,6 +149,9 @@ static struct psil_ep j721s2_src_ep_map[] = {
/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */
static struct psil_ep j721s2_dst_ep_map[] = {
/* MAIN SA2UL */
PSIL_SA2UL(0xca40, 1),
PSIL_SA2UL(0xca41, 1),
/* CPSW0 */
PSIL_ETHERNET(0xf000),
PSIL_ETHERNET(0xf001),

View File

@@ -2127,126 +2127,6 @@ error:
return NULL;
}
/**
* xilinx_cdma_prep_memcpy_sg - prepare descriptors for a memcpy_sg transaction
* @dchan: DMA channel
* @dst_sg: Destination scatter list
* @dst_sg_len: Number of entries in destination scatter list
* @src_sg: Source scatter list
* @src_sg_len: Number of entries in source scatter list
* @flags: transfer ack flags
*
* Return: Async transaction descriptor on success and NULL on failure
*/
static struct dma_async_tx_descriptor *xilinx_cdma_prep_memcpy_sg(
struct dma_chan *dchan, struct scatterlist *dst_sg,
unsigned int dst_sg_len, struct scatterlist *src_sg,
unsigned int src_sg_len, unsigned long flags)
{
struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
struct xilinx_dma_tx_descriptor *desc;
struct xilinx_cdma_tx_segment *segment, *prev = NULL;
struct xilinx_cdma_desc_hw *hw;
size_t len, dst_avail, src_avail;
dma_addr_t dma_dst, dma_src;
if (unlikely(dst_sg_len == 0 || src_sg_len == 0))
return NULL;
if (unlikely(!dst_sg || !src_sg))
return NULL;
desc = xilinx_dma_alloc_tx_descriptor(chan);
if (!desc)
return NULL;
dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
desc->async_tx.tx_submit = xilinx_dma_tx_submit;
dst_avail = sg_dma_len(dst_sg);
src_avail = sg_dma_len(src_sg);
/*
* loop until there is either no more source or no more destination
* scatterlist entry
*/
while (true) {
len = min_t(size_t, src_avail, dst_avail);
len = min_t(size_t, len, chan->xdev->max_buffer_len);
if (len == 0)
goto fetch;
/* Allocate the link descriptor from DMA pool */
segment = xilinx_cdma_alloc_tx_segment(chan);
if (!segment)
goto error;
dma_dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) -
dst_avail;
dma_src = sg_dma_address(src_sg) + sg_dma_len(src_sg) -
src_avail;
hw = &segment->hw;
hw->control = len;
hw->src_addr = dma_src;
hw->dest_addr = dma_dst;
if (chan->ext_addr) {
hw->src_addr_msb = upper_32_bits(dma_src);
hw->dest_addr_msb = upper_32_bits(dma_dst);
}
if (prev) {
prev->hw.next_desc = segment->phys;
if (chan->ext_addr)
prev->hw.next_desc_msb =
upper_32_bits(segment->phys);
}
prev = segment;
dst_avail -= len;
src_avail -= len;
list_add_tail(&segment->node, &desc->segments);
fetch:
/* Fetch the next dst scatterlist entry */
if (dst_avail == 0) {
if (dst_sg_len == 0)
break;
dst_sg = sg_next(dst_sg);
if (dst_sg == NULL)
break;
dst_sg_len--;
dst_avail = sg_dma_len(dst_sg);
}
/* Fetch the next src scatterlist entry */
if (src_avail == 0) {
if (src_sg_len == 0)
break;
src_sg = sg_next(src_sg);
if (src_sg == NULL)
break;
src_sg_len--;
src_avail = sg_dma_len(src_sg);
}
}
if (list_empty(&desc->segments)) {
dev_err(chan->xdev->dev,
"%s: Zero-size SG transfer requested\n", __func__);
goto error;
}
/* Link the last hardware descriptor with the first. */
segment = list_first_entry(&desc->segments,
struct xilinx_cdma_tx_segment, node);
desc->async_tx.phys = segment->phys;
prev->hw.next_desc = segment->phys;
return &desc->async_tx;
error:
xilinx_dma_free_tx_descriptor(chan, desc);
return NULL;
}
/**
* xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
* @dchan: DMA channel
@@ -3240,9 +3120,7 @@ static int xilinx_dma_probe(struct platform_device *pdev)
DMA_RESIDUE_GRANULARITY_SEGMENT;
} else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
dma_cap_set(DMA_MEMCPY, xdev->common.cap_mask);
dma_cap_set(DMA_MEMCPY_SG, xdev->common.cap_mask);
xdev->common.device_prep_dma_memcpy = xilinx_cdma_prep_memcpy;
xdev->common.device_prep_dma_memcpy_sg = xilinx_cdma_prep_memcpy_sg;
/* Residue calculation is supported by only AXI DMA and CDMA */
xdev->common.residue_granularity =
DMA_RESIDUE_GRANULARITY_SEGMENT;

View File

@@ -376,7 +376,7 @@ static ssize_t xilinx_dpdma_debugfs_read(struct file *f, char __user *buf,
if (ret < 0)
goto done;
} else {
strlcpy(kern_buff, "No testcase executed",
strscpy(kern_buff, "No testcase executed",
XILINX_DPDMA_DEBUGFS_READ_MAX_SIZE);
}
@@ -1652,10 +1652,8 @@ static int xilinx_dpdma_probe(struct platform_device *pdev)
dpdma_hw_init(xdev);
xdev->irq = platform_get_irq(pdev, 0);
if (xdev->irq < 0) {
dev_err(xdev->dev, "failed to get platform irq\n");
if (xdev->irq < 0)
return xdev->irq;
}
ret = request_irq(xdev->irq, xilinx_dpdma_irq_handler, IRQF_SHARED,
dev_name(xdev->dev), xdev);

View File

@@ -1341,17 +1341,17 @@ static int msb_ftl_initialize(struct msb_data *msb)
msb->zone_count = msb->block_count / MS_BLOCKS_IN_ZONE;
msb->logical_block_count = msb->zone_count * 496 - 2;
msb->used_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL);
msb->erased_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL);
msb->used_blocks_bitmap = bitmap_zalloc(msb->block_count, GFP_KERNEL);
msb->erased_blocks_bitmap = bitmap_zalloc(msb->block_count, GFP_KERNEL);
msb->lba_to_pba_table =
kmalloc_array(msb->logical_block_count, sizeof(u16),
GFP_KERNEL);
if (!msb->used_blocks_bitmap || !msb->lba_to_pba_table ||
!msb->erased_blocks_bitmap) {
kfree(msb->used_blocks_bitmap);
bitmap_free(msb->used_blocks_bitmap);
bitmap_free(msb->erased_blocks_bitmap);
kfree(msb->lba_to_pba_table);
kfree(msb->erased_blocks_bitmap);
return -ENOMEM;
}
@@ -1946,7 +1946,8 @@ static DEFINE_MUTEX(msb_disk_lock); /* protects against races in open/release */
static void msb_data_clear(struct msb_data *msb)
{
kfree(msb->boot_page);
kfree(msb->used_blocks_bitmap);
bitmap_free(msb->used_blocks_bitmap);
bitmap_free(msb->erased_blocks_bitmap);
kfree(msb->lba_to_pba_table);
kfree(msb->cache);
msb->card = NULL;
@@ -2243,8 +2244,8 @@ static int msb_resume(struct memstick_dev *card)
goto out;
if (msb->block_count != new_msb->block_count ||
memcmp(msb->used_blocks_bitmap, new_msb->used_blocks_bitmap,
msb->block_count / 8))
!bitmap_equal(msb->used_blocks_bitmap, new_msb->used_blocks_bitmap,
msb->block_count))
goto out;
card_dead = false;

View File

@@ -176,7 +176,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
unsigned int part_type);
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct mmc_card *card,
int disable_multi,
int recovery_mode,
struct mmc_queue *mq);
static void mmc_blk_hsq_req_done(struct mmc_request *mrq);
@@ -1302,7 +1302,7 @@ static void mmc_blk_eval_resp_error(struct mmc_blk_request *brq)
}
static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
int disable_multi, bool *do_rel_wr_p,
int recovery_mode, bool *do_rel_wr_p,
bool *do_data_tag_p)
{
struct mmc_blk_data *md = mq->blkdata;
@@ -1368,12 +1368,12 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
brq->data.blocks--;
/*
* After a read error, we redo the request one sector
* After a read error, we redo the request one (native) sector
* at a time in order to accurately determine which
* sectors can be read successfully.
*/
if (disable_multi)
brq->data.blocks = 1;
if (recovery_mode)
brq->data.blocks = queue_physical_block_size(mq->queue) >> 9;
/*
* Some controllers have HW issues while operating
@@ -1590,7 +1590,7 @@ static int mmc_blk_cqe_issue_rw_rq(struct mmc_queue *mq, struct request *req)
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct mmc_card *card,
int disable_multi,
int recovery_mode,
struct mmc_queue *mq)
{
u32 readcmd, writecmd;
@@ -1599,7 +1599,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct mmc_blk_data *md = mq->blkdata;
bool do_rel_wr, do_data_tag;
mmc_blk_data_prep(mq, mqrq, disable_multi, &do_rel_wr, &do_data_tag);
mmc_blk_data_prep(mq, mqrq, recovery_mode, &do_rel_wr, &do_data_tag);
brq->mrq.cmd = &brq->cmd;
@@ -1690,7 +1690,7 @@ static int mmc_blk_fix_state(struct mmc_card *card, struct request *req)
#define MMC_READ_SINGLE_RETRIES 2
/* Single sector read during recovery */
/* Single (native) sector read during recovery */
static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req)
{
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
@@ -1698,6 +1698,7 @@ static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req)
struct mmc_card *card = mq->card;
struct mmc_host *host = card->host;
blk_status_t error = BLK_STS_OK;
size_t bytes_per_read = queue_physical_block_size(mq->queue);
do {
u32 status;
@@ -1732,13 +1733,13 @@ static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req)
else
error = BLK_STS_OK;
} while (blk_update_request(req, error, 512));
} while (blk_update_request(req, error, bytes_per_read));
return;
error_exit:
mrq->data->bytes_xfered = 0;
blk_update_request(req, BLK_STS_IOERR, 512);
blk_update_request(req, BLK_STS_IOERR, bytes_per_read);
/* Let it try the remaining request again */
if (mqrq->retries > MMC_MAX_RETRIES - 1)
mqrq->retries = MMC_MAX_RETRIES - 1;
@@ -1879,10 +1880,9 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req)
return;
}
/* FIXME: Missing single sector read for large sector size */
if (!mmc_large_sector(card) && rq_data_dir(req) == READ &&
brq->data.blocks > 1) {
/* Read one sector at a time */
if (rq_data_dir(req) == READ && brq->data.blocks >
queue_physical_block_size(mq->queue) >> 9) {
/* Read one (native) sector at a time */
mmc_blk_read_single(mq, req);
return;
}
@@ -2988,7 +2988,7 @@ static int mmc_blk_probe(struct mmc_card *card)
* Don't enable runtime PM for SD-combo cards here. Leave that
* decision to be taken during the SDIO init sequence instead.
*/
if (card->type != MMC_TYPE_SD_COMBO) {
if (!mmc_card_sd_combo(card)) {
pm_runtime_set_active(&card->dev);
pm_runtime_enable(&card->dev);
}
@@ -3015,7 +3015,7 @@ static void mmc_blk_remove(struct mmc_card *card)
mmc_blk_part_switch(card, md->part_type);
mmc_release_host(card->host);
}
if (card->type != MMC_TYPE_SD_COMBO)
if (!mmc_card_sd_combo(card))
pm_runtime_disable(&card->dev);
pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);

View File

@@ -85,7 +85,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
return retval;
}
if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) {
if (mmc_card_sdio(card) || mmc_card_sd_combo(card)) {
retval = add_uevent_var(env, "SDIO_ID=%04X:%04X",
card->cis.vendor, card->cis.device);
if (retval)
@@ -107,7 +107,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
* SDIO (non-combo) cards are not handled by mmc_block driver and do not
* have accessible CID register which used by mmc_card_name() function.
*/
if (card->type == MMC_TYPE_SDIO)
if (mmc_card_sdio(card))
return 0;
retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));

View File

@@ -943,9 +943,11 @@ int mmc_execute_tuning(struct mmc_card *card)
}
/* Only print error when we don't check for card removal */
if (!host->detect_change)
if (!host->detect_change) {
pr_err("%s: tuning execution failed: %d\n",
mmc_hostname(host), err);
mmc_debugfs_err_stats_inc(host, MMC_ERR_TUNING);
}
return err;
}
@@ -2244,6 +2246,12 @@ void mmc_rescan(struct work_struct *work)
if (freqs[i] <= host->f_min)
break;
}
/*
* Ignore the command timeout errors observed during
* the card init as those are excepted.
*/
host->err_stats[MMC_ERR_CMD_TIMEOUT] = 0;
mmc_release_host(host);
out:

View File

@@ -223,6 +223,81 @@ static int mmc_clock_opt_set(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
"%llu\n");
static int mmc_err_state_get(void *data, u64 *val)
{
struct mmc_host *host = data;
int i;
if (!host)
return -EINVAL;
*val = 0;
for (i = 0; i < MMC_ERR_MAX; i++) {
if (host->err_stats[i]) {
*val = 1;
break;
}
}
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(mmc_err_state, mmc_err_state_get, NULL, "%llu\n");
static int mmc_err_stats_show(struct seq_file *file, void *data)
{
struct mmc_host *host = (struct mmc_host *)file->private;
const char *desc[MMC_ERR_MAX] = {
[MMC_ERR_CMD_TIMEOUT] = "Command Timeout Occurred",
[MMC_ERR_CMD_CRC] = "Command CRC Errors Occurred",
[MMC_ERR_DAT_TIMEOUT] = "Data Timeout Occurred",
[MMC_ERR_DAT_CRC] = "Data CRC Errors Occurred",
[MMC_ERR_AUTO_CMD] = "Auto-Cmd Error Occurred",
[MMC_ERR_ADMA] = "ADMA Error Occurred",
[MMC_ERR_TUNING] = "Tuning Error Occurred",
[MMC_ERR_CMDQ_RED] = "CMDQ RED Errors",
[MMC_ERR_CMDQ_GCE] = "CMDQ GCE Errors",
[MMC_ERR_CMDQ_ICCE] = "CMDQ ICCE Errors",
[MMC_ERR_REQ_TIMEOUT] = "Request Timedout",
[MMC_ERR_CMDQ_REQ_TIMEOUT] = "CMDQ Request Timedout",
[MMC_ERR_ICE_CFG] = "ICE Config Errors",
[MMC_ERR_CTRL_TIMEOUT] = "Controller Timedout errors",
[MMC_ERR_UNEXPECTED_IRQ] = "Unexpected IRQ errors",
};
int i;
for (i = 0; i < MMC_ERR_MAX; i++) {
if (desc[i])
seq_printf(file, "# %s:\t %d\n",
desc[i], host->err_stats[i]);
}
return 0;
}
static int mmc_err_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, mmc_err_stats_show, inode->i_private);
}
static ssize_t mmc_err_stats_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct mmc_host *host = filp->f_mapping->host->i_private;
pr_debug("%s: Resetting MMC error statistics\n", __func__);
memset(host->err_stats, 0, sizeof(host->err_stats));
return cnt;
}
static const struct file_operations mmc_err_stats_fops = {
.open = mmc_err_stats_open,
.read = seq_read,
.write = mmc_err_stats_write,
.release = single_release,
};
void mmc_add_host_debugfs(struct mmc_host *host)
{
struct dentry *root;
@@ -236,6 +311,11 @@ void mmc_add_host_debugfs(struct mmc_host *host)
debugfs_create_file_unsafe("clock", S_IRUSR | S_IWUSR, root, host,
&mmc_clock_fops);
debugfs_create_file_unsafe("err_state", 0600, root, host,
&mmc_err_state);
debugfs_create_file("err_stats", 0600, root, host,
&mmc_err_stats_fops);
#ifdef CONFIG_FAIL_MMC_REQUEST
if (fail_request)
setup_fault_attr(&fail_default_attr, fail_request);

View File

@@ -599,7 +599,7 @@ static int mmc_validate_host_caps(struct mmc_host *host)
}
if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) &&
!(caps & MMC_CAP_8_BIT_DATA)) {
!(caps & MMC_CAP_8_BIT_DATA) && !(caps2 & MMC_CAP2_NO_MMC)) {
dev_warn(dev, "drop HS400 support since no 8-bit bus\n");
host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400;
}

View File

@@ -163,8 +163,10 @@ static inline bool mmc_fixup_of_compatible_match(struct mmc_card *card,
struct device_node *np;
for_each_child_of_node(mmc_dev(card->host)->of_node, np) {
if (of_device_is_compatible(np, compatible))
if (of_device_is_compatible(np, compatible)) {
of_node_put(np);
return true;
}
}
return false;

View File

@@ -793,7 +793,7 @@ static umode_t sd_std_is_visible(struct kobject *kobj, struct attribute *attr,
attr == &dev_attr_info2.attr ||
attr == &dev_attr_info3.attr ||
attr == &dev_attr_info4.attr
) && card->type != MMC_TYPE_SD_COMBO)
) &&!mmc_card_sd_combo(card))
return 0;
return attr->mode;
@@ -870,7 +870,7 @@ try_again:
* the CCS bit is set as well. We deliberately deviate from the spec in
* regards to this, which allows UHS-I to be supported for SDSC cards.
*/
if (!mmc_host_is_spi(host) && rocr && (*rocr & 0x01000000)) {
if (!mmc_host_is_spi(host) && rocr && (*rocr & SD_ROCR_S18A)) {
err = mmc_set_uhs_voltage(host, pocr);
if (err == -EAGAIN) {
retries--;

View File

@@ -226,6 +226,20 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
if (data & SDIO_DRIVE_SDTD)
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTERRUPT_EXT, 0, &data);
if (ret)
goto out;
if (data & SDIO_INTERRUPT_EXT_SAI) {
data |= SDIO_INTERRUPT_EXT_EAI;
ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_INTERRUPT_EXT,
data, NULL);
if (ret)
goto out;
card->cccr.enable_async_irq = 1;
}
}
/* if no uhs mode ensure we check for high speed */
@@ -335,7 +349,7 @@ static int sdio_disable_4bit_bus(struct mmc_card *card)
{
int err;
if (card->type == MMC_TYPE_SDIO)
if (mmc_card_sdio(card))
goto out;
if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
@@ -360,7 +374,7 @@ static int sdio_enable_4bit_bus(struct mmc_card *card)
err = sdio_enable_wide(card);
if (err <= 0)
return err;
if (card->type == MMC_TYPE_SDIO)
if (mmc_card_sdio(card))
goto out;
if (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) {
@@ -415,7 +429,7 @@ static int sdio_enable_hs(struct mmc_card *card)
int ret;
ret = mmc_sdio_switch_hs(card, true);
if (ret <= 0 || card->type == MMC_TYPE_SDIO)
if (ret <= 0 || mmc_card_sdio(card))
return ret;
ret = mmc_sd_switch_hs(card);
@@ -441,7 +455,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
max_dtr = card->cis.max_dtr;
}
if (card->type == MMC_TYPE_SD_COMBO)
if (mmc_card_sd_combo(card))
max_dtr = min(max_dtr, mmc_sd_get_max_clock(card));
return max_dtr;
@@ -689,7 +703,7 @@ try_again:
mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) {
card->type = MMC_TYPE_SD_COMBO;
if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
if (oldcard && (!mmc_card_sd_combo(oldcard) ||
memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) {
err = -ENOENT;
goto mismatch;
@@ -697,7 +711,7 @@ try_again:
} else {
card->type = MMC_TYPE_SDIO;
if (oldcard && oldcard->type != MMC_TYPE_SDIO) {
if (oldcard && !mmc_card_sdio(oldcard)) {
err = -ENOENT;
goto mismatch;
}
@@ -754,7 +768,7 @@ try_again:
/*
* Read CSD, before selecting the card
*/
if (!oldcard && card->type == MMC_TYPE_SD_COMBO) {
if (!oldcard && mmc_card_sd_combo(card)) {
err = mmc_sd_get_csd(card);
if (err)
goto remove;
@@ -827,7 +841,7 @@ try_again:
mmc_fixup_device(card, sdio_fixup_methods);
if (card->type == MMC_TYPE_SD_COMBO) {
if (mmc_card_sd_combo(card)) {
err = mmc_sd_setup_card(host, card, oldcard != NULL);
/* handle as SDIO-only card if memory init failed */
if (err) {

View File

@@ -277,6 +277,7 @@ static int octeon_mmc_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "Error populating slots\n");
octeon_mmc_set_shared_power(host, 0);
of_node_put(cn);
goto error;
}
i++;

View File

@@ -142,8 +142,10 @@ static int thunder_mmc_probe(struct pci_dev *pdev,
continue;
ret = cvm_mmc_of_slot_probe(&host->slot_pdev[i]->dev, host);
if (ret)
if (ret) {
of_node_put(child_node);
goto error;
}
}
i++;
}

View File

@@ -822,8 +822,15 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error,
pr_debug("%s: cqhci: IRQ status: 0x%08x\n", mmc_hostname(mmc), status);
if ((status & (CQHCI_IS_RED | CQHCI_IS_GCE | CQHCI_IS_ICCE)) ||
cmd_error || data_error)
cmd_error || data_error) {
if (status & CQHCI_IS_RED)
mmc_debugfs_err_stats_inc(mmc, MMC_ERR_CMDQ_RED);
if (status & CQHCI_IS_GCE)
mmc_debugfs_err_stats_inc(mmc, MMC_ERR_CMDQ_GCE);
if (status & CQHCI_IS_ICCE)
mmc_debugfs_err_stats_inc(mmc, MMC_ERR_CMDQ_ICCE);
cqhci_error_irq(mmc, status, cmd_error, data_error);
}
if (status & CQHCI_IS_TCC) {
/* read TCN and complete the request */

View File

@@ -670,7 +670,9 @@ static int dw_mci_exynos_remove(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return dw_mci_pltfm_remove(pdev);
dw_mci_pltfm_remove(pdev);
return 0;
}
static const struct dev_pm_ops dw_mci_exynos_pmops = {

View File

@@ -179,7 +179,9 @@ static int dw_mci_hi3798cv200_remove(struct platform_device *pdev)
clk_disable_unprepare(priv->drive_clk);
clk_disable_unprepare(priv->sample_clk);
return dw_mci_pltfm_remove(pdev);
dw_mci_pltfm_remove(pdev);
return 0;
}
static const struct of_device_id dw_mci_hi3798cv200_match[] = {

View File

@@ -377,7 +377,9 @@ static int dw_mci_rockchip_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return dw_mci_pltfm_remove(pdev);
dw_mci_pltfm_remove(pdev);
return 0;
}
static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = {

View File

@@ -762,7 +762,7 @@ int mmci_dmae_setup(struct mmci_host *host)
/*
* If only an RX channel is specified, the driver will
* attempt to use it bidirectionally, however if it is
* attempt to use it bidirectionally, however if it
* is specified but cannot be located, DMA will be disabled.
*/
if (dmae->rx_channel && !dmae->tx_channel)

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2015 MediaTek Inc.
* Copyright (c) 2014-2015, 2022 MediaTek Inc.
* Author: Chaotian.Jing <chaotian.jing@mediatek.com>
*/
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -440,8 +441,10 @@ struct msdc_host {
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_uhs;
struct pinctrl_state *pins_eint;
struct delayed_work req_timeout;
int irq; /* host interrupt */
int eint_irq; /* interrupt from sdio device for waking up system */
struct reset_control *reset;
struct clk *src_clk; /* msdc source clock */
@@ -1521,17 +1524,46 @@ static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb)
static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
{
unsigned long flags;
struct msdc_host *host = mmc_priv(mmc);
unsigned long flags;
int ret;
spin_lock_irqsave(&host->lock, flags);
__msdc_enable_sdio_irq(host, enb);
spin_unlock_irqrestore(&host->lock, flags);
if (enb)
pm_runtime_get_noresume(host->dev);
else
pm_runtime_put_noidle(host->dev);
if (mmc_card_enable_async_irq(mmc->card) && host->pins_eint) {
if (enb) {
/*
* In dev_pm_set_dedicated_wake_irq_reverse(), eint pin will be set to
* GPIO mode. We need to restore it to SDIO DAT1 mode after that.
* Since the current pinstate is pins_uhs, to ensure pinctrl select take
* affect successfully, we change the pinstate to pins_eint firstly.
*/
pinctrl_select_state(host->pinctrl, host->pins_eint);
ret = dev_pm_set_dedicated_wake_irq_reverse(host->dev, host->eint_irq);
if (ret) {
dev_err(host->dev, "Failed to register SDIO wakeup irq!\n");
host->pins_eint = NULL;
pm_runtime_get_noresume(host->dev);
} else {
dev_dbg(host->dev, "SDIO eint irq: %d!\n", host->eint_irq);
}
pinctrl_select_state(host->pinctrl, host->pins_uhs);
} else {
dev_pm_clear_wake_irq(host->dev);
}
} else {
if (enb) {
/* Ensure host->pins_eint is NULL */
host->pins_eint = NULL;
pm_runtime_get_noresume(host->dev);
} else {
pm_runtime_put_noidle(host->dev);
}
}
}
static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts)
@@ -2319,7 +2351,7 @@ static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card
else
val = readl(host->base + PAD_DS_TUNE);
dev_info(host->dev, "Fianl PAD_DS_TUNE: 0x%x\n", val);
dev_info(host->dev, "Final PAD_DS_TUNE: 0x%x\n", val);
return 0;
@@ -2635,6 +2667,20 @@ static int msdc_drv_probe(struct platform_device *pdev)
goto host_free;
}
/* Support for SDIO eint irq ? */
if ((mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ) && (mmc->pm_caps & MMC_PM_KEEP_POWER)) {
host->eint_irq = platform_get_irq_byname(pdev, "sdio_wakeup");
if (host->eint_irq > 0) {
host->pins_eint = pinctrl_lookup_state(host->pinctrl, "state_eint");
if (IS_ERR(host->pins_eint)) {
dev_err(&pdev->dev, "Cannot find pinctrl eint!\n");
host->pins_eint = NULL;
} else {
device_init_wakeup(&pdev->dev, true);
}
}
}
msdc_of_property_parse(pdev, host);
host->dev = &pdev->dev;
@@ -2849,6 +2895,15 @@ static int __maybe_unused msdc_runtime_suspend(struct device *dev)
struct msdc_host *host = mmc_priv(mmc);
msdc_save_reg(host);
if (sdio_irq_claimed(mmc)) {
if (host->pins_eint) {
disable_irq(host->irq);
pinctrl_select_state(host->pinctrl, host->pins_eint);
}
__msdc_enable_sdio_irq(host, 0);
}
msdc_gate_clock(host);
return 0;
}
@@ -2864,12 +2919,18 @@ static int __maybe_unused msdc_runtime_resume(struct device *dev)
return ret;
msdc_restore_reg(host);
if (sdio_irq_claimed(mmc) && host->pins_eint) {
pinctrl_select_state(host->pinctrl, host->pins_uhs);
enable_irq(host->irq);
}
return 0;
}
static int __maybe_unused msdc_suspend(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct msdc_host *host = mmc_priv(mmc);
int ret;
if (mmc->caps2 & MMC_CAP2_CQE) {
@@ -2878,11 +2939,24 @@ static int __maybe_unused msdc_suspend(struct device *dev)
return ret;
}
/*
* Bump up runtime PM usage counter otherwise dev->power.needs_force_resume will
* not be marked as 1, pm_runtime_force_resume() will go out directly.
*/
if (sdio_irq_claimed(mmc) && host->pins_eint)
pm_runtime_get_noresume(dev);
return pm_runtime_force_suspend(dev);
}
static int __maybe_unused msdc_resume(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct msdc_host *host = mmc_priv(mmc);
if (sdio_irq_claimed(mmc) && host->pins_eint)
pm_runtime_put_noidle(dev);
return pm_runtime_force_resume(dev);
}

View File

@@ -923,7 +923,7 @@ static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card)
* One way to prevent this is to only allow 1-bit transfers.
*/
if (is_imx31_mmc(mxcmci) && card->type == MMC_TYPE_SDIO)
if (is_imx31_mmc(mxcmci) && mmc_card_sdio(card))
host->caps &= ~MMC_CAP_4_BIT_DATA;
else
host->caps |= MMC_CAP_4_BIT_DATA;
@@ -1025,7 +1025,7 @@ static int mxcmci_probe(struct platform_device *pdev)
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;
host->devtype = (enum mxcmci_type)of_device_get_match_data(&pdev->dev);
host->devtype = (uintptr_t)of_device_get_match_data(&pdev->dev);
/* adjust max_segs after devtype detection */
if (!is_mpc512x_mmc(host))

View File

@@ -43,6 +43,7 @@ struct renesas_sdhi_quirks {
bool hs400_4taps;
bool fixed_addr_mode;
bool dma_one_rx_only;
bool manual_tap_correction;
u32 hs400_bad_taps;
const u8 (*hs400_calib_table)[SDHI_CALIB_TABLE_MAX];
};

View File

@@ -49,9 +49,6 @@
#define HOST_MODE_GEN3_32BIT (HOST_MODE_GEN3_WMODE | HOST_MODE_GEN3_BUSWIDTH)
#define HOST_MODE_GEN3_64BIT 0
#define CTL_SDIF_MODE 0xe6
#define SDIF_MODE_HS400 BIT(0)
#define SDHI_VER_GEN2_SDR50 0x490c
#define SDHI_VER_RZ_A1 0x820b
/* very old datasheets said 0x490c for SDR104, too. They are wrong! */
@@ -383,8 +380,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);
/* Gen3 can't do automatic tap correction with HS400, so disable it */
if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC)
if (priv->quirks && priv->quirks->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));
@@ -562,23 +558,25 @@ static void renesas_sdhi_scc_reset(struct tmio_mmc_host *host, struct renesas_sd
}
/* only populated for TMIO_MMC_MIN_RCAR2 */
static void renesas_sdhi_reset(struct tmio_mmc_host *host)
static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve)
{
struct renesas_sdhi *priv = host_to_priv(host);
int ret;
u16 val;
if (priv->rstc) {
reset_control_reset(priv->rstc);
/* Unknown why but without polling reset status, it will hang */
read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
false, priv->rstc);
/* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
priv->needs_adjust_hs400 = false;
renesas_sdhi_set_clock(host, host->clk_cache);
} else if (priv->scc_ctl) {
renesas_sdhi_scc_reset(host, priv);
if (!preserve) {
if (priv->rstc) {
reset_control_reset(priv->rstc);
/* Unknown why but without polling reset status, it will hang */
read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
false, priv->rstc);
/* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
priv->needs_adjust_hs400 = false;
renesas_sdhi_set_clock(host, host->clk_cache);
} else if (priv->scc_ctl) {
renesas_sdhi_scc_reset(host, priv);
}
}
if (sd_ctrl_read16(host, CTL_VERSION) >= SDHI_VER_GEN3_SD) {
@@ -719,7 +717,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 (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC &&
if (priv->quirks && priv->quirks->manual_tap_correction &&
host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0;
/*
@@ -938,6 +936,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (IS_ERR(priv->clk_cd))
return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk_cd), "cannot get cd clock");
priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
if (IS_ERR(priv->rstc))
return PTR_ERR(priv->rstc);
priv->pinctrl = devm_pinctrl_get(&pdev->dev);
if (!IS_ERR(priv->pinctrl)) {
priv->pins_default = pinctrl_lookup_state(priv->pinctrl,
@@ -1030,10 +1032,6 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (ret)
goto efree;
priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
if (IS_ERR(priv->rstc))
return PTR_ERR(priv->rstc);
ver = sd_ctrl_read16(host, CTL_VERSION);
/* GEN2_SDR104 is first known SDHI to use 32bit block count */
if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX)

View File

@@ -170,6 +170,7 @@ static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400_one_rx = {
static const struct renesas_sdhi_quirks sdhi_quirks_4tap = {
.hs400_4taps = true,
.hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7),
.manual_tap_correction = true,
};
static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = {
@@ -182,25 +183,30 @@ static const struct renesas_sdhi_quirks sdhi_quirks_fixed_addr = {
static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps1357 = {
.hs400_bad_taps = BIT(1) | BIT(3) | BIT(5) | BIT(7),
.manual_tap_correction = true,
};
static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps2367 = {
.hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7),
.manual_tap_correction = true,
};
static const struct renesas_sdhi_quirks sdhi_quirks_r8a7796_es13 = {
.hs400_4taps = true,
.hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7),
.hs400_calib_table = r8a7796_es13_calib_table,
.manual_tap_correction = true,
};
static const struct renesas_sdhi_quirks sdhi_quirks_r8a77965 = {
.hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7),
.hs400_calib_table = r8a77965_calib_table,
.manual_tap_correction = true,
};
static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = {
.hs400_calib_table = r8a77990_calib_table,
.manual_tap_correction = true,
};
/*
@@ -268,6 +274,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, },
{ .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, },
{},
};
MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
@@ -321,7 +328,7 @@ renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host)
}
/*
* renesas_sdhi_internal_dmac_map() will be called with two difference
* renesas_sdhi_internal_dmac_map() will be called with two different
* sg pointers in two mmc_data by .pre_req(), but tmio host can have a single
* sg_ptr only. So, renesas_sdhi_internal_dmac_{un}map() should use a sg
* pointer in a mmc_data instead of host->sg_ptr.
@@ -355,7 +362,7 @@ renesas_sdhi_internal_dmac_map(struct tmio_mmc_host *host,
data->host_cookie = cookie;
/* This DMAC cannot handle if buffer is not 128-bytes alignment */
/* This DMAC needs buffers to be 128-byte aligned */
if (!IS_ALIGNED(sg_dma_address(data->sg), 128)) {
renesas_sdhi_internal_dmac_unmap(host, data, cookie);
return false;

View File

@@ -31,6 +31,8 @@
struct sdhci_brcmstb_priv {
void __iomem *cfg_regs;
unsigned int flags;
struct clk *base_clk;
u32 base_freq_hz;
};
struct brcmstb_match_priv {
@@ -250,9 +252,11 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host;
const struct of_device_id *match;
struct sdhci_brcmstb_priv *priv;
u32 actual_clock_mhz;
struct sdhci_host *host;
struct resource *iomem;
struct clk *clk;
struct clk *base_clk = NULL;
int res;
match = of_match_node(sdhci_brcm_of_match, pdev->dev.of_node);
@@ -330,6 +334,35 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
if (match_priv->flags & BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT)
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
/* Change the base clock frequency if the DT property exists */
if (device_property_read_u32(&pdev->dev, "clock-frequency",
&priv->base_freq_hz) != 0)
goto add_host;
base_clk = devm_clk_get_optional(&pdev->dev, "sdio_freq");
if (IS_ERR(base_clk)) {
dev_warn(&pdev->dev, "Clock for \"sdio_freq\" not found\n");
goto add_host;
}
res = clk_prepare_enable(base_clk);
if (res)
goto err;
/* set improved clock rate */
clk_set_rate(base_clk, priv->base_freq_hz);
actual_clock_mhz = clk_get_rate(base_clk) / 1000000;
host->caps &= ~SDHCI_CLOCK_V3_BASE_MASK;
host->caps |= (actual_clock_mhz << SDHCI_CLOCK_BASE_SHIFT);
/* Disable presets because they are now incorrect */
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
dev_dbg(&pdev->dev, "Base Clock Frequency changed to %dMHz\n",
actual_clock_mhz);
priv->base_clk = base_clk;
add_host:
res = sdhci_brcmstb_add_host(host, priv);
if (res)
goto err;
@@ -340,6 +373,7 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
err:
sdhci_pltfm_free(pdev);
err_clk:
clk_disable_unprepare(base_clk);
clk_disable_unprepare(clk);
return res;
}
@@ -351,11 +385,51 @@ static void sdhci_brcmstb_shutdown(struct platform_device *pdev)
MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
#ifdef CONFIG_PM_SLEEP
static int sdhci_brcmstb_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
clk_disable_unprepare(priv->base_clk);
return sdhci_pltfm_suspend(dev);
}
static int sdhci_brcmstb_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;
ret = sdhci_pltfm_resume(dev);
if (!ret && priv->base_freq_hz) {
ret = clk_prepare_enable(priv->base_clk);
/*
* Note: using clk_get_rate() below as clk_get_rate()
* honors CLK_GET_RATE_NOCACHE attribute, but clk_set_rate()
* may do implicit get_rate() calls that do not honor
* CLK_GET_RATE_NOCACHE.
*/
if (!ret &&
(clk_get_rate(priv->base_clk) != priv->base_freq_hz))
ret = clk_set_rate(priv->base_clk, priv->base_freq_hz);
}
return ret;
}
#endif
static const struct dev_pm_ops sdhci_brcmstb_pmops = {
SET_SYSTEM_SLEEP_PM_OPS(sdhci_brcmstb_suspend, sdhci_brcmstb_resume)
};
static struct platform_driver sdhci_brcmstb_driver = {
.driver = {
.name = "sdhci-brcmstb",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pltfm_pmops,
.pm = &sdhci_brcmstb_pmops,
.of_match_table = of_match_ptr(sdhci_brcm_of_match),
},
.probe = sdhci_brcmstb_probe,

View File

@@ -2435,33 +2435,12 @@ static const struct sdhci_msm_variant_info sdm845_sdhci_var = {
};
static const struct of_device_id sdhci_msm_dt_match[] = {
/* Following two entries are deprecated (kept only for backward compatibility) */
/*
* Do not add new variants to the driver which are compatible with
* generic ones, unless they need customization.
*/
{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
/* Add entries for sdcc versions less than 5.0 here */
{.compatible = "qcom,apq8084-sdhci", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,msm8226-sdhci", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,msm8916-sdhci", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,msm8953-sdhci", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,msm8974-sdhci", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,msm8992-sdhci", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,msm8994-sdhci", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,msm8996-sdhci", .data = &sdhci_msm_mci_var},
/*
* Add entries for sdcc version 5.0 here. For SDCC version 5.0.0,
* MCI registers are removed from SDCC interface and some registers
* are moved to HC.
*/
{.compatible = "qcom,qcs404-sdhci", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sdx55-sdhci", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sdx65-sdhci", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sdm630-sdhci", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sm6125-sdhci", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sm6350-sdhci", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sm8150-sdhci", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sm8250-sdhci", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sc7280-sdhci", .data = &sdhci_msm_v5_var},
/* Add entries where soc specific handling is required, here */
{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
{.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var},
{},

View File

@@ -1733,7 +1733,6 @@ err_pltfm_free:
static int sdhci_arasan_remove(struct platform_device *pdev)
{
int ret;
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
@@ -1747,11 +1746,11 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
sdhci_arasan_unregister_sdclk(&pdev->dev);
ret = sdhci_pltfm_unregister(pdev);
sdhci_pltfm_unregister(pdev);
clk_disable_unprepare(clk_ahb);
return ret;
return 0;
}
static struct platform_driver sdhci_arasan_driver = {

View File

@@ -100,8 +100,13 @@ static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
static void sdhci_at91_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{
if (timing == MMC_TIMING_MMC_DDR52)
sdhci_writeb(host, SDMMC_MC1R_DDR, SDMMC_MC1R);
u8 mc1r;
if (timing == MMC_TIMING_MMC_DDR52) {
mc1r = sdhci_readb(host, SDMMC_MC1R);
mc1r |= SDMMC_MC1R_DDR;
sdhci_writeb(host, mc1r, SDMMC_MC1R);
}
sdhci_set_uhs_signaling(host, timing);
}

View File

@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/sizes.h>
#include "sdhci-pltfm.h"
@@ -30,6 +31,7 @@
/* Offset inside the vendor area 1 */
#define DWCMSHC_HOST_CTRL3 0x8
#define DWCMSHC_EMMC_CONTROL 0x2c
#define DWCMSHC_CARD_IS_EMMC BIT(0)
#define DWCMSHC_ENHANCED_STROBE BIT(8)
#define DWCMSHC_EMMC_ATCTRL 0x40
@@ -38,7 +40,7 @@
#define DWCMSHC_EMMC_DLL_RXCLK 0x804
#define DWCMSHC_EMMC_DLL_TXCLK 0x808
#define DWCMSHC_EMMC_DLL_STRBIN 0x80c
#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24)
#define DECMSHC_EMMC_DLL_CMDOUT 0x810
#define DWCMSHC_EMMC_DLL_STATUS0 0x840
#define DWCMSHC_EMMC_DLL_START BIT(0)
#define DWCMSHC_EMMC_DLL_LOCKED BIT(8)
@@ -47,22 +49,39 @@
#define DWCMSHC_EMMC_DLL_START_POINT 16
#define DWCMSHC_EMMC_DLL_INC 8
#define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
#define DLL_TXCLK_TAPNUM_DEFAULT 0x8
#define DLL_STRBIN_TAPNUM_DEFAULT 0x8
#define DLL_TXCLK_TAPNUM_DEFAULT 0x10
#define DLL_TXCLK_TAPNUM_90_DEGREES 0xA
#define DLL_TXCLK_TAPNUM_FROM_SW BIT(24)
#define DLL_STRBIN_TAPNUM_DEFAULT 0x8
#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24)
#define DLL_STRBIN_DELAY_NUM_SEL BIT(26)
#define DLL_STRBIN_DELAY_NUM_OFFSET 16
#define DLL_STRBIN_DELAY_NUM_DEFAULT 0x16
#define DLL_RXCLK_NO_INVERTER 1
#define DLL_RXCLK_INVERTER 0
#define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8
#define DLL_CMDOUT_TAPNUM_FROM_SW BIT(24)
#define DLL_CMDOUT_SRC_CLK_NEG BIT(28)
#define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29)
#define DLL_LOCK_WO_TMOUT(x) \
((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
(((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
#define RK3568_MAX_CLKS 3
#define RK35xx_MAX_CLKS 3
#define BOUNDARY_OK(addr, len) \
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
struct rk3568_priv {
enum dwcmshc_rk_type {
DWCMSHC_RK3568,
DWCMSHC_RK3588,
};
struct rk35xx_priv {
/* Rockchip specified optional clocks */
struct clk_bulk_data rockchip_clks[RK3568_MAX_CLKS];
struct clk_bulk_data rockchip_clks[RK35xx_MAX_CLKS];
struct reset_control *reset;
enum dwcmshc_rk_type devtype;
u8 txclk_tapnum;
};
@@ -131,7 +150,9 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq)
static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{
u16 ctrl_2;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
u16 ctrl, ctrl_2;
ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
/* Select Bus Speed Mode for host */
@@ -149,8 +170,15 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
else if ((timing == MMC_TIMING_UHS_DDR50) ||
(timing == MMC_TIMING_MMC_DDR52))
ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
else if (timing == MMC_TIMING_MMC_HS400)
else if (timing == MMC_TIMING_MMC_HS400) {
/* set CARD_IS_EMMC bit to enable Data Strobe for HS400 */
ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
ctrl |= DWCMSHC_CARD_IS_EMMC;
sdhci_writew(host, ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
ctrl_2 |= DWCMSHC_CTRL_HS400;
}
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
}
@@ -176,24 +204,18 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
struct rk3568_priv *priv = dwc_priv->priv;
struct rk35xx_priv *priv = dwc_priv->priv;
u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
u32 extra, reg;
int err;
host->mmc->actual_clock = 0;
/*
* DO NOT TOUCH THIS SETTING. RX clk inverter unit is enabled
* by default, but it shouldn't be enabled. We should anyway
* disable it before issuing any cmds.
*/
extra = DWCMSHC_EMMC_DLL_DLYENA |
DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
if (clock == 0)
if (clock == 0) {
/* Disable interface clock at initial state. */
sdhci_set_clock(host, clock);
return;
}
/* Rockchip platform only support 375KHz for identify mode */
if (clock <= 400000)
@@ -211,9 +233,21 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
extra &= ~BIT(0);
sdhci_writel(host, extra, reg);
if (clock <= 400000) {
/* Disable DLL to reset sample clock */
if (clock <= 52000000) {
/* Disable DLL and reset both of sample and drive clock */
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_RXCLK);
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT);
/*
* Before switching to hs400es mode, the driver will enable
* enhanced strobe first. PHY needs to configure the parameters
* of enhanced strobe first.
*/
extra = DWCMSHC_EMMC_DLL_DLYENA |
DLL_STRBIN_DELAY_NUM_SEL |
DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
return;
}
@@ -222,6 +256,15 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
udelay(1);
sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL);
/*
* We shouldn't set DLL_RXCLK_NO_INVERTER for identify mode but
* we must set it in higher speed mode.
*/
extra = DWCMSHC_EMMC_DLL_DLYENA;
if (priv->devtype == DWCMSHC_RK3568)
extra |= DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
/* Init DLL settings */
extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
0x2 << DWCMSHC_EMMC_DLL_INC |
@@ -244,8 +287,20 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
host->mmc->ios.timing == MMC_TIMING_MMC_HS400)
txclk_tapnum = priv->txclk_tapnum;
if ((priv->devtype == DWCMSHC_RK3588) && host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES;
extra = DLL_CMDOUT_SRC_CLK_NEG |
DLL_CMDOUT_EN_SRC_CLK_NEG |
DWCMSHC_EMMC_DLL_DLYENA |
DLL_CMDOUT_TAPNUM_90_DEGREES |
DLL_CMDOUT_TAPNUM_FROM_SW;
sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
}
extra = DWCMSHC_EMMC_DLL_DLYENA |
DLL_TXCLK_TAPNUM_FROM_SW |
DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL |
txclk_tapnum;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
@@ -255,6 +310,21 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
}
static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
struct rk35xx_priv *priv = dwc_priv->priv;
if (mask & SDHCI_RESET_ALL && priv->reset) {
reset_control_assert(priv->reset);
udelay(1);
reset_control_deassert(priv->reset);
}
sdhci_reset(host, mask);
}
static const struct sdhci_ops sdhci_dwcmshc_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
@@ -264,12 +334,12 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = {
.adma_write_desc = dwcmshc_adma_write_desc,
};
static const struct sdhci_ops sdhci_dwcmshc_rk3568_ops = {
static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
.set_clock = dwcmshc_rk3568_set_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = dwcmshc_set_uhs_signaling,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.reset = sdhci_reset,
.reset = rk35xx_sdhci_reset,
.adma_write_desc = dwcmshc_adma_write_desc,
};
@@ -279,30 +349,37 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
};
static const struct sdhci_pltfm_data sdhci_dwcmshc_rk3568_pdata = {
.ops = &sdhci_dwcmshc_rk3568_ops,
static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
.ops = &sdhci_dwcmshc_rk35xx_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
};
static int dwcmshc_rk3568_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
{
int err;
struct rk3568_priv *priv = dwc_priv->priv;
struct rk35xx_priv *priv = dwc_priv->priv;
priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc));
if (IS_ERR(priv->reset)) {
err = PTR_ERR(priv->reset);
dev_err(mmc_dev(host->mmc), "failed to get reset control %d\n", err);
return err;
}
priv->rockchip_clks[0].id = "axi";
priv->rockchip_clks[1].id = "block";
priv->rockchip_clks[2].id = "timer";
err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK3568_MAX_CLKS,
err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK35xx_MAX_CLKS,
priv->rockchip_clks);
if (err) {
dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err);
return err;
}
err = clk_bulk_prepare_enable(RK3568_MAX_CLKS, priv->rockchip_clks);
err = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, priv->rockchip_clks);
if (err) {
dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err);
return err;
@@ -321,10 +398,28 @@ static int dwcmshc_rk3568_init(struct sdhci_host *host, struct dwcmshc_priv *dwc
return 0;
}
static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
{
/*
* Don't support highspeed bus mode with low clk speed as we
* cannot use DLL for this condition.
*/
if (host->mmc->f_max <= 52000000) {
dev_info(mmc_dev(host->mmc), "Disabling HS200/HS400, frequency too low (%d)\n",
host->mmc->f_max);
host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400);
host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR);
}
}
static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
{
.compatible = "rockchip,rk3588-dwcmshc",
.data = &sdhci_dwcmshc_rk35xx_pdata,
},
{
.compatible = "rockchip,rk3568-dwcmshc",
.data = &sdhci_dwcmshc_rk3568_pdata,
.data = &sdhci_dwcmshc_rk35xx_pdata,
},
{
.compatible = "snps,dwcmshc-sdhci",
@@ -347,7 +442,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_host *host;
struct dwcmshc_priv *priv;
struct rk3568_priv *rk_priv = NULL;
struct rk35xx_priv *rk_priv = NULL;
const struct sdhci_pltfm_data *pltfm_data;
int err;
u32 extra;
@@ -402,33 +497,47 @@ static int dwcmshc_probe(struct platform_device *pdev)
host->mmc_host_ops.request = dwcmshc_request;
host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
if (pltfm_data == &sdhci_dwcmshc_rk3568_pdata) {
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk3568_priv), GFP_KERNEL);
if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) {
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL);
if (!rk_priv) {
err = -ENOMEM;
goto err_clk;
}
if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3588-dwcmshc"))
rk_priv->devtype = DWCMSHC_RK3588;
else
rk_priv->devtype = DWCMSHC_RK3568;
priv->priv = rk_priv;
err = dwcmshc_rk3568_init(host, priv);
err = dwcmshc_rk35xx_init(host, priv);
if (err)
goto err_clk;
}
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
err = sdhci_add_host(host);
err = sdhci_setup_host(host);
if (err)
goto err_clk;
if (rk_priv)
dwcmshc_rk35xx_postinit(host, priv);
err = __sdhci_add_host(host);
if (err)
goto err_setup_host;
return 0;
err_setup_host:
sdhci_cleanup_host(host);
err_clk:
clk_disable_unprepare(pltfm_host->clk);
clk_disable_unprepare(priv->bus_clk);
if (rk_priv)
clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
rk_priv->rockchip_clks);
free_pltfm:
sdhci_pltfm_free(pdev);
@@ -440,14 +549,14 @@ static int dwcmshc_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
struct rk3568_priv *rk_priv = priv->priv;
struct rk35xx_priv *rk_priv = priv->priv;
sdhci_remove_host(host, 0);
clk_disable_unprepare(pltfm_host->clk);
clk_disable_unprepare(priv->bus_clk);
if (rk_priv)
clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
rk_priv->rockchip_clks);
sdhci_pltfm_free(pdev);
@@ -460,7 +569,7 @@ static int dwcmshc_suspend(struct device *dev)
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
struct rk3568_priv *rk_priv = priv->priv;
struct rk35xx_priv *rk_priv = priv->priv;
int ret;
ret = sdhci_suspend_host(host);
@@ -472,7 +581,7 @@ static int dwcmshc_suspend(struct device *dev)
clk_disable_unprepare(priv->bus_clk);
if (rk_priv)
clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
rk_priv->rockchip_clks);
return ret;
@@ -483,7 +592,7 @@ static int dwcmshc_resume(struct device *dev)
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
struct rk3568_priv *rk_priv = priv->priv;
struct rk35xx_priv *rk_priv = priv->priv;
int ret;
ret = clk_prepare_enable(pltfm_host->clk);
@@ -497,7 +606,7 @@ static int dwcmshc_resume(struct device *dev)
}
if (rk_priv) {
ret = clk_bulk_prepare_enable(RK3568_MAX_CLKS,
ret = clk_bulk_prepare_enable(RK35xx_MAX_CLKS,
rk_priv->rockchip_clks);
if (ret)
return ret;

View File

@@ -904,6 +904,7 @@ static int esdhc_signal_voltage_switch(struct mmc_host *mmc,
scfg_node = of_find_matching_node(NULL, scfg_device_ids);
if (scfg_node)
scfg_base = of_iomap(scfg_node, 0);
of_node_put(scfg_node);
if (scfg_base) {
sdhciovselcr = SDHCIOVSELCR_TGLEN |
SDHCIOVSELCR_VSELVAL;
@@ -1418,7 +1419,7 @@ static int esdhc_hs400_prepare_ddr(struct mmc_host *mmc)
static int sdhci_esdhc_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct device_node *np;
struct device_node *np, *tp;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_esdhc *esdhc;
int ret;
@@ -1463,7 +1464,9 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
if (esdhc->vendor_ver > VENDOR_V_22)
host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) {
tp = of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc");
if (tp) {
of_node_put(tp);
host->quirks |= SDHCI_QUIRK_RESET_AFTER_REQUEST;
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
}

View File

@@ -95,6 +95,9 @@
#define PCIE_GLI_9763E_SCR 0x8E0
#define GLI_9763E_SCR_AXI_REQ BIT(9)
#define PCIE_GLI_9763E_CFG 0x8A0
#define GLI_9763E_CFG_LPSN_DIS BIT(12)
#define PCIE_GLI_9763E_CFG2 0x8A4
#define GLI_9763E_CFG2_L1DLY GENMASK(28, 19)
#define GLI_9763E_CFG2_L1DLY_MID 0x54
@@ -963,12 +966,40 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
}
#ifdef CONFIG_PM
static void gl9763e_set_low_power_negotiation(struct sdhci_pci_slot *slot, bool enable)
{
struct pci_dev *pdev = slot->chip->pdev;
u32 value;
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
value &= ~GLI_9763E_VHS_REV;
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W);
pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG, &value);
if (enable)
value &= ~GLI_9763E_CFG_LPSN_DIS;
else
value |= GLI_9763E_CFG_LPSN_DIS;
pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG, value);
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
value &= ~GLI_9763E_VHS_REV;
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
}
static int gl9763e_runtime_suspend(struct sdhci_pci_chip *chip)
{
struct sdhci_pci_slot *slot = chip->slots[0];
struct sdhci_host *host = slot->host;
u16 clock;
/* Enable LPM negotiation to allow entering L1 state */
gl9763e_set_low_power_negotiation(slot, true);
clock = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clock &= ~(SDHCI_CLOCK_PLL_EN | SDHCI_CLOCK_CARD_EN);
sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL);
@@ -1002,6 +1033,9 @@ static int gl9763e_runtime_resume(struct sdhci_pci_chip *chip)
clock |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL);
/* Disable LPM negotiation to avoid entering L1 state. */
gl9763e_set_low_power_negotiation(slot, false);
return 0;
}
#endif

View File

@@ -440,15 +440,14 @@ static int sdhci_st_remove(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
struct reset_control *rstc = pdata->rstc;
int ret;
ret = sdhci_pltfm_unregister(pdev);
sdhci_pltfm_unregister(pdev);
clk_disable_unprepare(pdata->icnclk);
reset_control_assert(rstc);
return ret;
return 0;
}
#ifdef CONFIG_PM_SLEEP

View File

@@ -224,6 +224,7 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
if (timedout) {
pr_err("%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
sdhci_err_stats_inc(host, CTRL_TIMEOUT);
sdhci_dumpregs(host);
return;
}
@@ -1716,6 +1717,7 @@ static bool sdhci_send_command_retry(struct sdhci_host *host,
if (!timeout--) {
pr_err("%s: Controller never released inhibit bit(s).\n",
mmc_hostname(host->mmc));
sdhci_err_stats_inc(host, CTRL_TIMEOUT);
sdhci_dumpregs(host);
cmd->error = -EIO;
return false;
@@ -1965,6 +1967,7 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
if (timedout) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
sdhci_err_stats_inc(host, CTRL_TIMEOUT);
sdhci_dumpregs(host);
return;
}
@@ -1987,6 +1990,7 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
if (timedout) {
pr_err("%s: PLL clock never stabilised.\n",
mmc_hostname(host->mmc));
sdhci_err_stats_inc(host, CTRL_TIMEOUT);
sdhci_dumpregs(host);
return;
}
@@ -3161,6 +3165,7 @@ static void sdhci_timeout_timer(struct timer_list *t)
if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
pr_err("%s: Timeout waiting for hardware cmd interrupt.\n",
mmc_hostname(host->mmc));
sdhci_err_stats_inc(host, REQ_TIMEOUT);
sdhci_dumpregs(host);
host->cmd->error = -ETIMEDOUT;
@@ -3183,6 +3188,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t)
(host->cmd && sdhci_data_line_cmd(host->cmd))) {
pr_err("%s: Timeout waiting for hardware interrupt.\n",
mmc_hostname(host->mmc));
sdhci_err_stats_inc(host, REQ_TIMEOUT);
sdhci_dumpregs(host);
if (host->data) {
@@ -3234,17 +3240,21 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
return;
pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n",
mmc_hostname(host->mmc), (unsigned)intmask);
sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
sdhci_dumpregs(host);
return;
}
if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC |
SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) {
if (intmask & SDHCI_INT_TIMEOUT)
if (intmask & SDHCI_INT_TIMEOUT) {
host->cmd->error = -ETIMEDOUT;
else
sdhci_err_stats_inc(host, CMD_TIMEOUT);
} else {
host->cmd->error = -EILSEQ;
if (!mmc_op_tuning(host->cmd->opcode))
sdhci_err_stats_inc(host, CMD_CRC);
}
/* Treat data command CRC error the same as data CRC error */
if (host->cmd->data &&
(intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) ==
@@ -3266,6 +3276,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
-ETIMEDOUT :
-EILSEQ;
sdhci_err_stats_inc(host, AUTO_CMD);
if (sdhci_auto_cmd23(host, mrq)) {
mrq->sbc->error = err;
__sdhci_finish_mrq(host, mrq);
@@ -3342,6 +3354,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (intmask & SDHCI_INT_DATA_TIMEOUT) {
host->data_cmd = NULL;
data_cmd->error = -ETIMEDOUT;
sdhci_err_stats_inc(host, CMD_TIMEOUT);
__sdhci_finish_mrq(host, data_cmd->mrq);
return;
}
@@ -3370,23 +3383,30 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
mmc_hostname(host->mmc), (unsigned)intmask);
sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
sdhci_dumpregs(host);
return;
}
if (intmask & SDHCI_INT_DATA_TIMEOUT)
if (intmask & SDHCI_INT_DATA_TIMEOUT) {
host->data->error = -ETIMEDOUT;
else if (intmask & SDHCI_INT_DATA_END_BIT)
sdhci_err_stats_inc(host, DAT_TIMEOUT);
} else if (intmask & SDHCI_INT_DATA_END_BIT) {
host->data->error = -EILSEQ;
else if ((intmask & SDHCI_INT_DATA_CRC) &&
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
sdhci_err_stats_inc(host, DAT_CRC);
} else if ((intmask & SDHCI_INT_DATA_CRC) &&
SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
!= MMC_BUS_TEST_R)
!= MMC_BUS_TEST_R) {
host->data->error = -EILSEQ;
else if (intmask & SDHCI_INT_ADMA_ERROR) {
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
sdhci_err_stats_inc(host, DAT_CRC);
} else if (intmask & SDHCI_INT_ADMA_ERROR) {
pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
intmask);
sdhci_adma_show_error(host);
sdhci_err_stats_inc(host, ADMA);
host->data->error = -EIO;
if (host->ops->adma_workaround)
host->ops->adma_workaround(host, intmask);
@@ -3584,6 +3604,7 @@ out:
if (unexpected) {
pr_err("%s: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), unexpected);
sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
sdhci_dumpregs(host);
}
@@ -3905,20 +3926,27 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
if (!host->cqe_on)
return false;
if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC))
if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC)) {
*cmd_error = -EILSEQ;
else if (intmask & SDHCI_INT_TIMEOUT)
if (!mmc_op_tuning(host->cmd->opcode))
sdhci_err_stats_inc(host, CMD_CRC);
} else if (intmask & SDHCI_INT_TIMEOUT) {
*cmd_error = -ETIMEDOUT;
else
sdhci_err_stats_inc(host, CMD_TIMEOUT);
} else
*cmd_error = 0;
if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC))
if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
*data_error = -EILSEQ;
else if (intmask & SDHCI_INT_DATA_TIMEOUT)
if (!mmc_op_tuning(host->cmd->opcode))
sdhci_err_stats_inc(host, DAT_CRC);
} else if (intmask & SDHCI_INT_DATA_TIMEOUT) {
*data_error = -ETIMEDOUT;
else if (intmask & SDHCI_INT_ADMA_ERROR)
sdhci_err_stats_inc(host, DAT_TIMEOUT);
} else if (intmask & SDHCI_INT_ADMA_ERROR) {
*data_error = -EIO;
else
sdhci_err_stats_inc(host, ADMA);
} else
*data_error = 0;
/* Clear selected interrupts. */
@@ -3934,6 +3962,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
sdhci_writel(host, intmask, SDHCI_INT_STATUS);
pr_err("%s: CQE: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), intmask);
sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
sdhci_dumpregs(host);
}

View File

@@ -356,6 +356,9 @@ struct sdhci_adma2_64_desc {
*/
#define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */
#define sdhci_err_stats_inc(host, err_name) \
mmc_debugfs_err_stats_inc((host)->mmc, MMC_ERR_##err_name)
enum sdhci_cookie {
COOKIE_UNMAPPED,
COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */

View File

@@ -75,7 +75,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
tmio_mmc_clk_start(host);
}
static void tmio_mmc_reset(struct tmio_mmc_host *host)
static void tmio_mmc_reset(struct tmio_mmc_host *host, bool preserve)
{
sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
usleep_range(10000, 11000);

View File

@@ -42,6 +42,7 @@
#define CTL_DMA_ENABLE 0xd8
#define CTL_RESET_SD 0xe0
#define CTL_VERSION 0xe2
#define CTL_SDIF_MODE 0xe6 /* only known on R-Car 2+ */
/* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
#define TMIO_STOP_STP BIT(0)
@@ -98,6 +99,9 @@
/* Definitions for values the CTL_DMA_ENABLE register can take */
#define DMA_ENABLE_DMASDRW BIT(1)
/* Definitions for values the CTL_SDIF_MODE register can take */
#define SDIF_MODE_HS400 BIT(0) /* only known on R-Car 2+ */
/* Define some IRQ masks */
/* This is the mask used at reset by the chip */
#define TMIO_MASK_ALL 0x837f031d
@@ -181,7 +185,7 @@ struct tmio_mmc_host {
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
void (*reset)(struct tmio_mmc_host *host);
void (*reset)(struct tmio_mmc_host *host, bool preserve);
bool (*check_retune)(struct tmio_mmc_host *host, struct mmc_request *mrq);
void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq);
unsigned int (*get_timeout_cycles)(struct tmio_mmc_host *host);

View File

@@ -179,8 +179,17 @@ static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, reg);
}
static void tmio_mmc_reset(struct tmio_mmc_host *host)
static void tmio_mmc_reset(struct tmio_mmc_host *host, bool preserve)
{
u16 card_opt, clk_ctrl, sdif_mode;
if (preserve) {
card_opt = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
clk_ctrl = sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL);
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
sdif_mode = sd_ctrl_read16(host, CTL_SDIF_MODE);
}
/* FIXME - should we set stop clock reg here */
sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
usleep_range(10000, 11000);
@@ -190,7 +199,7 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
tmio_mmc_abort_dma(host);
if (host->reset)
host->reset(host);
host->reset(host, preserve);
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask_all);
host->sdcard_irq_mask = host->sdcard_irq_mask_all;
@@ -206,6 +215,13 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
}
if (preserve) {
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, card_opt);
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk_ctrl);
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
sd_ctrl_write16(host, CTL_SDIF_MODE, sdif_mode);
}
if (host->mmc->card)
mmc_retune_needed(host->mmc);
}
@@ -248,7 +264,7 @@ static void tmio_mmc_reset_work(struct work_struct *work)
spin_unlock_irqrestore(&host->lock, flags);
tmio_mmc_reset(host);
tmio_mmc_reset(host, true);
/* Ready for new calls */
host->mrq = NULL;
@@ -961,7 +977,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
tmio_mmc_power_off(host);
/* For R-Car Gen2+, we need to reset SDHI specific SCC */
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
tmio_mmc_reset(host);
tmio_mmc_reset(host, false);
host->set_clock(host, 0);
break;
@@ -1189,7 +1205,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
_host->sdcard_irq_mask_all = TMIO_MASK_ALL;
_host->set_clock(_host, 0);
tmio_mmc_reset(_host);
tmio_mmc_reset(_host, false);
spin_lock_init(&_host->lock);
mutex_init(&_host->ios_lock);
@@ -1285,7 +1301,7 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
struct tmio_mmc_host *host = dev_get_drvdata(dev);
tmio_mmc_clk_enable(host);
tmio_mmc_reset(host);
tmio_mmc_reset(host, false);
if (host->clk_cache)
host->set_clock(host, host->clk_cache);

View File

@@ -70,6 +70,16 @@ static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
* struct sdma_peripheral_config - SDMA config for audio
* @n_fifos_src: Number of FIFOs for recording
* @n_fifos_dst: Number of FIFOs for playback
* @stride_fifos_src: FIFO address stride for recording, 0 means all FIFOs are
* continuous, 1 means 1 word stride between FIFOs. All stride
* between FIFOs should be same.
* @stride_fifos_dst: FIFO address stride for playback
* @words_per_fifo: numbers of words per FIFO fetch/fill, 1 means
* one channel per FIFO, 2 means 2 channels per FIFO..
* If 'n_fifos_src = 4' and 'words_per_fifo = 2', it
* means the first two words(channels) fetch from FIFO0
* and then jump to FIFO1 for next two words, and so on
* after the last FIFO3 fetched, roll back to FIFO0.
* @sw_done: Use software done. Needed for PDM (micfil)
*
* Some i.MX Audio devices (SAI, micfil) have multiple successive FIFO
@@ -82,6 +92,9 @@ static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
struct sdma_peripheral_config {
int n_fifos_src;
int n_fifos_dst;
int stride_fifos_src;
int stride_fifos_dst;
int words_per_fifo;
bool sw_done;
};

View File

@@ -26,7 +26,7 @@ enum spi_transfer_cmd {
* @clk_div: source clock divider
* @clk_src: serial clock
* @cmd: spi cmd
* @fragmentation: keep CS assserted at end of sequence
* @fragmentation: keep CS asserted at end of sequence
* @cs: chip select toggle
* @set_config: set peripheral config
* @rx_len: receive length for buffer

View File

@@ -50,7 +50,6 @@ enum dma_status {
*/
enum dma_transaction_type {
DMA_MEMCPY,
DMA_MEMCPY_SG,
DMA_XOR,
DMA_PQ,
DMA_XOR_VAL,
@@ -887,11 +886,6 @@ struct dma_device {
struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(
struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
size_t len, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_memcpy_sg)(
struct dma_chan *chan,
struct scatterlist *dst_sg, unsigned int dst_nents,
struct scatterlist *src_sg, unsigned int src_nents,
unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_xor)(
struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src,
unsigned int src_cnt, size_t len, unsigned long flags);
@@ -1060,20 +1054,6 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy(
len, flags);
}
static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy_sg(
struct dma_chan *chan,
struct scatterlist *dst_sg, unsigned int dst_nents,
struct scatterlist *src_sg, unsigned int src_nents,
unsigned long flags)
{
if (!chan || !chan->device || !chan->device->device_prep_dma_memcpy_sg)
return NULL;
return chan->device->device_prep_dma_memcpy_sg(chan, dst_sg, dst_nents,
src_sg, src_nents,
flags);
}
static inline bool dmaengine_is_metadata_mode_supported(struct dma_chan *chan,
enum dma_desc_metadata_mode mode)
{

View File

@@ -219,7 +219,8 @@ struct sdio_cccr {
wide_bus:1,
high_power:1,
high_speed:1,
disable_cd:1;
disable_cd:1,
enable_async_irq:1;
};
struct sdio_cis {
@@ -343,10 +344,16 @@ static inline bool mmc_large_sector(struct mmc_card *card)
return card->ext_csd.data_sector_size == 4096;
}
static inline int mmc_card_enable_async_irq(struct mmc_card *card)
{
return card->cccr.enable_async_irq;
}
bool mmc_card_is_blockaddr(struct mmc_card *card);
#define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC)
#define mmc_card_sd(c) ((c)->type == MMC_TYPE_SD)
#define mmc_card_sdio(c) ((c)->type == MMC_TYPE_SDIO)
#define mmc_card_sd_combo(c) ((c)->type == MMC_TYPE_SD_COMBO)
#endif /* LINUX_MMC_CARD_H */

View File

@@ -93,6 +93,25 @@ struct mmc_clk_phase_map {
struct mmc_host;
enum mmc_err_stat {
MMC_ERR_CMD_TIMEOUT,
MMC_ERR_CMD_CRC,
MMC_ERR_DAT_TIMEOUT,
MMC_ERR_DAT_CRC,
MMC_ERR_AUTO_CMD,
MMC_ERR_ADMA,
MMC_ERR_TUNING,
MMC_ERR_CMDQ_RED,
MMC_ERR_CMDQ_GCE,
MMC_ERR_CMDQ_ICCE,
MMC_ERR_REQ_TIMEOUT,
MMC_ERR_CMDQ_REQ_TIMEOUT,
MMC_ERR_ICE_CFG,
MMC_ERR_CTRL_TIMEOUT,
MMC_ERR_UNEXPECTED_IRQ,
MMC_ERR_MAX,
};
struct mmc_host_ops {
/*
* It is optional for the host to implement pre_req and post_req in
@@ -501,6 +520,7 @@ struct mmc_host {
/* Host Software Queue support */
bool hsq_enabled;
u32 err_stats[MMC_ERR_MAX];
unsigned long private[] ____cacheline_aligned;
};
@@ -635,6 +655,12 @@ static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data)
return data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
}
static inline void mmc_debugfs_err_stats_inc(struct mmc_host *host,
enum mmc_err_stat stat)
{
host->err_stats[stat] += 1;
}
int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);

View File

@@ -99,6 +99,12 @@ static inline bool mmc_op_multi(u32 opcode)
opcode == MMC_READ_MULTIPLE_BLOCK;
}
static inline bool mmc_op_tuning(u32 opcode)
{
return opcode == MMC_SEND_TUNING_BLOCK ||
opcode == MMC_SEND_TUNING_BLOCK_HS200;
}
/*
* MMC_SWITCH argument format:
*

View File

@@ -159,6 +159,11 @@
#define SDIO_DTSx_SET_TYPE_A (1 << SDIO_DRIVE_DTSx_SHIFT)
#define SDIO_DTSx_SET_TYPE_C (2 << SDIO_DRIVE_DTSx_SHIFT)
#define SDIO_DTSx_SET_TYPE_D (3 << SDIO_DRIVE_DTSx_SHIFT)
#define SDIO_CCCR_INTERRUPT_EXT 0x16
#define SDIO_INTERRUPT_EXT_SAI (1 << 0)
#define SDIO_INTERRUPT_EXT_EAI (1 << 1)
/*
* Function Basic Registers (FBR)
*/

View File

@@ -89,14 +89,14 @@ enum iax_opcode {
IAX_OPCODE_CRC64,
IAX_OPCODE_ZERO_DECOMP_32 = 0x48,
IAX_OPCODE_ZERO_DECOMP_16,
IAX_OPCODE_DECOMP_32 = 0x4c,
IAX_OPCODE_DECOMP_16,
IAX_OPCODE_ZERO_COMP_32 = 0x4c,
IAX_OPCODE_ZERO_COMP_16,
IAX_OPCODE_SCAN = 0x50,
IAX_OPCODE_SET_MEMBER,
IAX_OPCODE_EXTRACT,
IAX_OPCODE_SELECT,
IAX_OPCODE_RLE_BURST,
IAX_OPCDE_FIND_UNIQUE,
IAX_OPCODE_FIND_UNIQUE,
IAX_OPCODE_EXPAND,
};