Date   

[isar-cip-core PATCH v2 0/4] Add rzg2m support

Quirin Gylstorff
 

From: Quirin Gylstorff <quirin.gylstorff@...>

Add the rzg2m reference board.
Add the option to build rootfs tarballs for LAVA tests.
This option needs to be activated in the gitlab-ci.yml by
adding it to the builds for testing.

Version 2:
Change used devicetree to r8a774a1-hihope-rzg2m-ex.dtb.
The changes to fetch the cip-kernel configuration instead
of using copies stored in the repository will be a seperate
patch set.


Quirin Gylstorff (4):
kas: Increase Isar version
classes: add wic-targz-img.bbclass
hihope-rzg2m: Add board support
ci: add hihope-rzg2m to ci chain

.gitlab-ci.yml | 4 +
board-rzg2m.yml | 16 +
classes/wic-targz-img.bbclass | 13 +
conf/machine/bbb.conf | 2 +-
conf/machine/hihope-rzg2m.conf | 18 +
conf/machine/iwg20m.conf | 2 +-
conf/machine/qemu-amd64.conf | 2 +-
conf/machine/simatic-ipc227e.conf | 2 +-
kas.yml | 2 +-
opt-targz-img.yml | 20 ++
.../linux/files/hihope-rzg2m_defconfig | 330 ++++++++++++++++++
scripts/deploy-cip-core.sh | 4 +
wic/hihope-rzg2m.wks | 15 +
13 files changed, 425 insertions(+), 5 deletions(-)
create mode 100644 board-rzg2m.yml
create mode 100644 classes/wic-targz-img.bbclass
create mode 100644 conf/machine/hihope-rzg2m.conf
create mode 100644 opt-targz-img.yml
create mode 100644 recipes-kernel/linux/files/hihope-rzg2m_defconfig
create mode 100644 wic/hihope-rzg2m.wks

--
2.20.1


Re: [isar-cip-core PATCH 3/4] hihope-rzg2m: Add board support

Quirin Gylstorff
 

On 11/7/19 3:29 AM, kazuhiro3.hayashi@... wrote:
Hello Quirin,

I will look into it using the cip-kernel-config instead of using copies
in isar.
Are you planning to "fetch" required config(s) for each target from cip-kernel-config?
or, keep copies of the configs in isar-cip-core then synchronize them at the specific point?
I try to fetch the configuration for each target from cip-kernel-config.
Currently I need to patch the config as Isar doesn't allow setting CONFIG_LOCALVERSION in the kernel configuration.

Deby also has its own kernel configs (arm64 defconfig + Tiny hihope-rzg2m.config)
for HiHope RZG2M:
https://gitlab.com/cip-project/cip-core/deby/blob/cip-core-buster/meta-hihope-rzg2m/recipes-kernel/linux/linux-base_git.bbappend
but they also should be replaced by the common kernel configs in CIP.
As the first step, I would provide configs by the same way as isar-cip-core.
Best regards,
Kazu
Quirin


Re: CIP IRC weekly meeting today

SZ Lin (林上智) <SZ.Lin@...>
 

Hi Iwamatsu-san,

From: nobuhiro1.iwamatsu@...

Hi SZ,

I may be late or unable to join meeting.
Thank you for your heads up, I've listed your comments in the IRC meeting.

SZ


* Action item
1. Provide the cases to cip-testing to build up the test environment -
Iwamatsu-san
Merged by Chris. Please close this A.I. Thanks for Chris.
https://gitlab.com/cip-project/cip-testing/linux-cip-ci/merge_requests/24

2. Test LTS (pre)releases directly - patersonc 3. Ask KernelCI for
recommendations on what tests to run - patersonc 4. Create a
way/process to run LTP only for release tests - patersonc 5.
Investigate the RT test tools - Pavel 6. Combine rootfilesystem with
kselftest binary - Iwamatsu-san
This is WIP. Please keep.

7. Document a process on how to add tests to the CIP test setup -
patersonc 8. Split out non-Kernel config sections from gitlab-ci.yml -
patersonc 9. Do we want to go with the current approach where GitLab
CI is run ‘out of tree’- Kernel team
We discussion by Mail now. Some opinions come from Chris.

* Kernel maintenance updates
I reviewed v4.4.198.

Best regards,
Nobuhiro

-----Original Message-----
From: cip-dev-bounces@...
[mailto:cip-dev-bounces@...] On Behalf Of SZ Lin (林
上智)
Sent: Thursday, November 7, 2019 10:56 AM
To: cip-dev@...
Subject: [cip-dev] CIP IRC weekly meeting today

Hi all,

Kindly be reminded to attend the weekly meeting through IRC to discuss
technical topics with CIP kernel today.

*Please note that the IRC meeting was rescheduled to UTC (GMT) 09:00
starting from the first week of Apr. according to TSC meeting*
https://www.timeanddate.com/worldclock/meetingdetails.html?year=2019
&month=11&day=7&hour=9&min=0&sec=0&p1=241&p2=137&p3=179&p4=1
36&p5=37
&p6=248

US-West US-East   UK     DE     TW     JP
01:00    04:00   09:00   10:00   17:00   18:00

Channel:
* irc:chat.freenode.net:6667/cip

Last week's meeting minutes:
https://irclogs.baserock.org/meetings/cip/2019/10/cip.2019-10-24-09.
00.html

Agenda:

* Action item
1. Provide the cases to cip-testing to build up the test environment -
Iwamatsu-san 2. Test LTS (pre)releases directly - patersonc 3. Ask
KernelCI for recommendations on what tests to run - patersonc 4.
Create a way/process to run LTP only for release tests - patersonc 5.
Investigate the RT test tools - Pavel 6. Combine rootfilesystem with
kselftest binary
- Iwamatsu-san 7. Document a process on how to add tests to the CIP
test setup - patersonc 8. Split out non-Kernel config sections from
gitlab-ci.yml - patersonc 9. Do we want to go with the current
approach where GitLab CI is run ‘out of tree’- Kernel team

* Kernel maintenance updates
* Kernel testing
* CIP Core
* Software update
* AOB

The meeting will take 30 min, although it can be extended to an hour
if it makes sense and those involved in the topics can stay.
Otherwise, the topic will be taken offline or in the next meeting.

Best regards,

SZ Lin, Moxa.
_______________________________________________
cip-dev mailing list
cip-dev@...
https://lists.cip-project.org/mailman/listinfo/cip-dev


[PATCH 4.4.y-cip 83/83] ARM: dts: iwg23s-sbc: Add uSD and eMMC support

Biju Das <biju.das@...>
 

From: Fabrizio Castro <fabrizio.castro@...>

commit 9eb36b945b5c21d57c02a26cc629dd9484ced9aa upstream.

Add uSD card and eMMC support to the iwg23s single board
computer powered by the RZ/G1C SoC (a.k.a. r8a77470).

Signed-off-by: Fabrizio Castro <fabrizio.castro@...>
Reviewed-by: Biju Das <biju.das@...>
Signed-off-by: Simon Horman <horms+renesas@...>
Signed-off-by: Biju Das <biju.das@...>
---
arch/arm/boot/dts/r8a77470-iwg23s-sbc.dts | 75 +++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)

diff --git a/arch/arm/boot/dts/r8a77470-iwg23s-sbc.dts b/arch/arm/boot/dts/r8a77470-iwg23s-sbc.dts
index 273acc8..579414e 100644
--- a/arch/arm/boot/dts/r8a77470-iwg23s-sbc.dts
+++ b/arch/arm/boot/dts/r8a77470-iwg23s-sbc.dts
@@ -6,6 +6,7 @@
*/

/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
#include "r8a77470.dtsi"
/ {
model = "iWave iW-RainboW-G23S single board computer based on RZ/G1C";
@@ -25,6 +26,37 @@
device_type = "memory";
reg = <0 0x40000000 0 0x20000000>;
};
+
+ reg_1p8v: reg-1p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ reg_3p3v: reg-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vccq_sdhi2: regulator-vccq-sdhi2 {
+ compatible = "regulator-gpio";
+
+ regulator-name = "SDHI2 VccQ";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpios = <&gpio2 24 GPIO_ACTIVE_HIGH>;
+ gpios-states = <1>;
+ states = <3300000 1
+ 1800000 0>;
+ };
};

&avb {
@@ -84,6 +116,12 @@
function = "i2c3";
};

+ mmc_pins_uhs: mmc_uhs {
+ groups = "mmc_data8", "mmc_ctrl";
+ function = "mmc";
+ power-source = <1800>;
+ };
+
qspi0_pins: qspi0 {
groups = "qspi0_ctrl", "qspi0_data2";
function = "qspi0";
@@ -94,6 +132,18 @@
function = "scif1";
};

+ sdhi2_pins: sd2 {
+ groups = "sdhi2_data4", "sdhi2_ctrl";
+ function = "sdhi2";
+ power-source = <3300>;
+ };
+
+ sdhi2_pins_uhs: sd2_uhs {
+ groups = "sdhi2_data4", "sdhi2_ctrl";
+ function = "sdhi2";
+ power-source = <1800>;
+ };
+
usb0_pins: usb0 {
groups = "usb0";
function = "usb0";
@@ -133,6 +183,31 @@
status = "okay";
};

+&sdhi1 {
+ pinctrl-0 = <&mmc_pins_uhs>;
+ pinctrl-names = "state_uhs";
+
+ vmmc-supply = <&reg_3p3v>;
+ vqmmc-supply = <&reg_1p8v>;
+ bus-width = <8>;
+ mmc-hs200-1_8v;
+ non-removable;
+ fixed-emmc-driver-type = <1>;
+ status = "okay";
+};
+
+&sdhi2 {
+ pinctrl-0 = <&sdhi2_pins>;
+ pinctrl-1 = <&sdhi2_pins_uhs>;
+ pinctrl-names = "default", "state_uhs";
+
+ vmmc-supply = <&reg_3p3v>;
+ vqmmc-supply = <&vccq_sdhi2>;
+ bus-width = <4>;
+ cd-gpios = <&gpio4 20 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
&usb2_phy0 {
status = "okay";
};
--
2.7.4


[PATCH 4.4.y-cip 82/83] ARM: dts: r8a77470: Add SDHI1 support

Biju Das <biju.das@...>
 

From: Fabrizio Castro <fabrizio.castro@...>

commit 0485da788028ecd525291974c8efe2d072607476 upstream.

Althought interface SDHI1 found on the RZ/G1C SoC (a.k.a.
r8a77470) is compatible with the R-Car Gen3 ones, its OF
compatibility is restricted to the SoC specific compatible
string to avoid confusion, as from a more generic perspective
the RZ/G1C is sharing the most similarities with the R-Car
Gen2 family of SoCs, and there is a combination of R-Car
Gen2 compatible SDHI IPs and R-Car Gen3 compatible SDHI IP
on this specific chip.
This patch adds the SoC specific part of SDHI1 support, and
since SDHI1 comes with internal DMA, its DT node looks fairly
different from SDHI0 and SDHI2.

Signed-off-by: Fabrizio Castro <fabrizio.castro@...>
Reviewed-by: Biju Das <biju.das@...>
Signed-off-by: Simon Horman <horms+renesas@...>
Signed-off-by: Biju Das <biju.das@...>
[ Removed reset and updated clk and power domain properties ]
---
arch/arm/boot/dts/r8a77470.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/r8a77470.dtsi b/arch/arm/boot/dts/r8a77470.dtsi
index f8fccd4..757c935 100644
--- a/arch/arm/boot/dts/r8a77470.dtsi
+++ b/arch/arm/boot/dts/r8a77470.dtsi
@@ -669,6 +669,16 @@
status = "disabled";
};

+ sdhi1: sd@ee300000 {
+ compatible = "renesas,sdhi-mmc-r8a77470";
+ reg = <0 0xee300000 0 0x2000>;
+ interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp3_clks R8A77470_CLK_SDHI1>;
+ max-frequency = <156000000>;
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
sdhi2: sd@ee160000 {
compatible = "renesas,sdhi-r8a77470",
"renesas,rcar-gen2-sdhi";
--
2.7.4


[PATCH 4.4.y-cip 81/83] ARM: dts: r8a77470: Add SDHI0 support

Biju Das <biju.das@...>
 

From: Fabrizio Castro <fabrizio.castro@...>

commit 15aa5a95e820e8183aa34535131e7c97789b8504 upstream.

RZ/G1C comes with two different types of IP for the SDHI
interfaces, SDHI0 and SDHI2 share the same IP type, and
such an IP is also compatible with the one found in R-Car
Gen2. SDHI1 IP on the other hand is compatible with R-Car
Gen3 with internal DMA.
This patch completes the SDHI support of the R-Car Gen2
compatible IPs, including fixing the max-frequency
definition of SDHI2, as it turns out there is a bug in
Section 1.3.9 of the RZ/G1C Hardware User's Manual (Rev.
1.00 Oct. 2017).

Signed-off-by: Fabrizio Castro <fabrizio.castro@...>
Reviewed-by: Biju Das <biju.das@...>
Signed-off-by: Simon Horman <horms+renesas@...>
Signed-off-by: Biju Das <biju.das@...>
[ Removed reset and updated clk and power domain properties ]
---
arch/arm/boot/dts/r8a77470.dtsi | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/r8a77470.dtsi b/arch/arm/boot/dts/r8a77470.dtsi
index fd9d92c..f8fccd4 100644
--- a/arch/arm/boot/dts/r8a77470.dtsi
+++ b/arch/arm/boot/dts/r8a77470.dtsi
@@ -655,6 +655,20 @@
status = "disabled";
};

+ sdhi0: sd@ee100000 {
+ compatible = "renesas,sdhi-r8a77470",
+ "renesas,rcar-gen2-sdhi";
+ reg = <0 0xee100000 0 0x328>;
+ interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp3_clks R8A77470_CLK_SDHI0>;
+ dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+ <&dmac1 0xcd>, <&dmac1 0xce>;
+ dma-names = "tx", "rx", "tx", "rx";
+ max-frequency = <156000000>;
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
sdhi2: sd@ee160000 {
compatible = "renesas,sdhi-r8a77470",
"renesas,rcar-gen2-sdhi";
@@ -664,7 +678,7 @@
dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
<&dmac1 0xd3>, <&dmac1 0xd4>;
dma-names = "tx", "rx", "tx", "rx";
- max-frequency = <97500000>;
+ max-frequency = <78000000>;
power-domains = <&cpg_clocks>;
status = "disabled";
};
--
2.7.4


[PATCH 4.4.y-cip 80/83] ARM: dts: r8a77470: Add SDHI2 support

Biju Das <biju.das@...>
 

From: Fabrizio Castro <fabrizio.castro@...>

commit f068cc816015f8a6af494b584978aa7df96d80fe upstream.

Add SoC specific device tree definitions for the SDHI2 interface.

Signed-off-by: Fabrizio Castro <fabrizio.castro@...>
Reviewed-by: Biju Das <biju.das@...>
Acked-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Simon Horman <horms+renesas@...>
Signed-off-by: Biju Das <biju.das@...>
[ Removed reset and updated clk and power domain properties ]
---
arch/arm/boot/dts/r8a77470.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/r8a77470.dtsi b/arch/arm/boot/dts/r8a77470.dtsi
index 568f650..fd9d92c 100644
--- a/arch/arm/boot/dts/r8a77470.dtsi
+++ b/arch/arm/boot/dts/r8a77470.dtsi
@@ -655,6 +655,20 @@
status = "disabled";
};

+ sdhi2: sd@ee160000 {
+ compatible = "renesas,sdhi-r8a77470",
+ "renesas,rcar-gen2-sdhi";
+ reg = <0 0xee160000 0 0x328>;
+ interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp3_clks R8A77470_CLK_SDHI2>;
+ dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
+ <&dmac1 0xd3>, <&dmac1 0xd4>;
+ dma-names = "tx", "rx", "tx", "rx";
+ max-frequency = <97500000>;
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
gic: interrupt-controller@f1001000 {
compatible = "arm,gic-400";
#interrupt-cells = <3>;
--
2.7.4


[PATCH 4.4.y-cip 79/83] mmc: renesas_sdhi: Add r8a77470 SDHI1 support

Biju Das <biju.das@...>
 

From: Fabrizio Castro <fabrizio.castro@...>

commit 60ab43ba6b6e0f888aab3ce0f84a8aaf15d15079 upstream.

The RZ/G1C (a.k.a. R8A77470) comes with three SDHI interfaces,
SDHI0 and SDHI2 are compatible with the R-Car Gen2 SDHIs, SDHI1
is compatible with R-Car Gen3 SDHIs and it can be used as
eMMC as well. This patch adds driver compatibility, and makes
sure both drivers get compiled for the R8A77470.

Signed-off-by: Fabrizio Castro <fabrizio.castro@...>
Reviewed-by: Biju Das <biju.das@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
[ Removed reset and updated clk and power domain properties ]
---
drivers/mmc/host/Kconfig | 4 ++--
drivers/mmc/host/renesas_sdhi_internal_dmac.c | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 7b947ce..359ec493 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -578,9 +578,9 @@ config MMC_SDHI_SYS_DMAC

config MMC_SDHI_INTERNAL_DMAC
tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
- depends on ARM64 || COMPILE_TEST
+ depends on ARM64 || ARCH_R8A77470 || COMPILE_TEST
depends on MMC_SDHI
- default MMC_SDHI if ARM64
+ default MMC_SDHI if (ARM64 || ARCH_R8A77470)
help
This provides DMA support for SDHI SD/SDIO controllers
using on-chip bus mastering. This supports the controllers
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index d41ff35..8056325 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -84,6 +84,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
};

static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
+ { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
{},
};
MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
--
2.7.4


[PATCH 4.4.y-cip 78/83] dt-bindings: mmc: renesas_sdhi: Add r8a77470 support

Biju Das <biju.das@...>
 

From: Fabrizio Castro <fabrizio.castro@...>

commit be6f8db406a49511a8d213f9443ae79fe5b086c3 upstream.

The RZ/G1C (a.k.a. R8A77470) comes with three SDHI interfaces,
SDHI0 and SDHI2 are compatible with R-Car Gen2 SDHIs, and
SDHI1 is compatible with R-Car Gen3 SDHIs, as it comes with an
internal DMAC, therefore SDHI1 is fully compatible with driver
renesas_sdhi_internal_dmac driver. As a result, the compatible
strings for the R8A77470 SDHI interfaces are a little bit special.
Document SDHI support for the RZ/G1C SoC.

Signed-off-by: Fabrizio Castro <fabrizio.castro@...>
Reviewed-by: Biju Das <biju.das@...>
Reviewed-by: Geert Uytterhoeven <geert+renesas@...>
Reviewed-by: Simon Horman <horms+renesas@...>
Reviewed-by: Rob Herring <robh@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
[ Removed R-Car Gen3 devices ]
---
Documentation/devicetree/bindings/mmc/tmio_mmc.txt | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
index 25f06e6..cbce1e6 100644
--- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
@@ -17,6 +17,8 @@ Required properties:
"renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
"renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC
"renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC
+ "renesas,sdhi-r8a77470" - SDHI IP on R8A77470 SoC
+ "renesas,sdhi-mmc-r8a77470" - SDHI/MMC IP on R8A77470 SoC
"renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
"renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC
"renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC
@@ -25,8 +27,8 @@ Required properties:
"renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
"renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
- "renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 or RZ/G1
- SDHI controller
+ "renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 and RZ/G1 SDHI
+ (not SDHI/MMC) controller

When compatible with the generic version, nodes must list
the SoC-specific version corresponding to the platform
--
2.7.4


[PATCH 4.4.y-cip 77/83] mmc: renesas_sdhi: implement R-Car Gen[123] fallback compatibility strings

Biju Das <biju.das@...>
 

From: Simon Horman <horms+renesas@...>

commit d6dc425ae595e14026beac3720e43edd70215dc8 upstream.

Implement fallback compatibility strings for R-Car Gen 1, 2 and 3.

In the case of Renesas R-Car hardware we know that there are generations of
SoCs, f.e. Gen 1 and 2. But beyond that its not clear what the relationship
between IP blocks might be. For example, I believe that r8a7790 is older
than r8a7791 but that doesn't imply that the latter is a descendant of the
former or vice versa.

We can, however, by examining the documentation and behaviour of the
hardware at run-time observe that the current driver implementation appears
to be compatible with the IP blocks on SoCs within a given generation.

For the above reasons and convenience when enabling new SoCs a
per-generation fallback compatibility string scheme is being adopted for
drivers for Renesas SoCs.

Also, improve readability by listing the shmobile fallback compatibility
string after the more-specific compatibility strings they provide a
fallback for.

Signed-off-by: Simon Horman <horms+renesas@...>
Reviewed-by: Geert Uytterhoeven <geert+renesas@...>
Acked-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
[ Removed R-Car Gen3 devices ]
---
drivers/mmc/host/renesas_sdhi_sys_dmac.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index 84bb945..77f3af4 100644
--- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -75,7 +75,6 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
};

static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
- { .compatible = "renesas,sdhi-shmobile" },
{ .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
{ .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
{ .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
@@ -88,6 +87,9 @@ static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,rcar-gen1-sdhi", .data = &of_rcar_gen1_compatible, },
+ { .compatible = "renesas,rcar-gen2-sdhi", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-shmobile" },
{},
};
MODULE_DEVICE_TABLE(of, renesas_sdhi_sys_dmac_of_match);
--
2.7.4


[PATCH 4.4.y-cip 76/83] dt-bindings: mmc: renesas_sdhi: add R-Car Gen[123] fallback compatibility strings

Biju Das <biju.das@...>
 

From: Simon Horman <horms+renesas@...>

commit 54839d012d5f98cde2fa102fdcd22e1da661d138 upstream.

Add fallback compatibility strings for R-Car Gen 1, 2 and 3.

In the case of Renesas R-Car hardware we know that there are generations of
SoCs, f.e. Gen 1 and 2. But beyond that its not clear what the relationship
between IP blocks might be. For example, I believe that r8a7790 is older
than r8a7791 but that doesn't imply that the latter is a descendant of the
former or vice versa.

We can, however, by examining the documentation and behaviour of the
hardware at run-time observe that the current driver implementation appears
to be compatible with the IP blocks on SoCs within a given generation.

For the above reasons and convenience when enabling new SoCs a
per-generation fallback compatibility string scheme is being adopted for
drivers for Renesas SoCs.

Signed-off-by: Simon Horman <horms+renesas@...>
Reviewed-by: Geert Uytterhoeven <geert+renesas@...>
Acked-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
Documentation/devicetree/bindings/mmc/tmio_mmc.txt | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
index 1d23a43..25f06e6 100644
--- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
@@ -24,6 +24,13 @@ Required properties:
"renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC
"renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
+ "renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
+ "renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 or RZ/G1
+ SDHI controller
+
+ When compatible with the generic version, nodes must list
+ the SoC-specific version corresponding to the platform
+ first followed by the generic version.

Optional properties:
- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
--
2.7.4


[PATCH 4.4.y-cip 75/83] mmc: renesas_sdhi: consolidate DMAC CONFIG options

Biju Das <biju.das@...>
 

From: Masahiro Yamada <yamada.masahiro@...>

commit c813e10a6bbad9ef56bc115c64d48c5a7d0a7dd5 upstream.

The description in the Makefile is odd. Fix the CONFIG selection
in a cleaner way.

Signed-off-by: Masahiro Yamada <yamada.masahiro@...>
Acked-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/Kconfig | 4 ++--
drivers/mmc/host/Makefile | 8 ++------
2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 54d98ee..7b947ce 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -563,8 +563,6 @@ config MMC_SDHI
depends on SUPERH || ARM
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
select MMC_TMIO_CORE
- select MMC_SDHI_SYS_DMAC if (SUPERH || ARM)
- select MMC_SDHI_INTERNAL_DMAC if ARM64
help
This provides support for the SDHI SD/SDIO controller found in
Renesas SuperH, ARM and ARM64 based SoCs
@@ -572,6 +570,7 @@ config MMC_SDHI
config MMC_SDHI_SYS_DMAC
tristate "DMA for SDHI SD/SDIO controllers using SYS-DMAC"
depends on MMC_SDHI
+ default MMC_SDHI if (SUPERH || ARM)
help
This provides DMA support for SDHI SD/SDIO controllers
using SYS-DMAC via DMA Engine. This supports the controllers
@@ -581,6 +580,7 @@ config MMC_SDHI_INTERNAL_DMAC
tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
depends on ARM64 || COMPILE_TEST
depends on MMC_SDHI
+ default MMC_SDHI if ARM64
help
This provides DMA support for SDHI SD/SDIO controllers
using on-chip bus mastering. This supports the controllers
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index f10bb0c..5de0c72 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -37,12 +37,8 @@ obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o
-ifeq ($(subst m,y,$(CONFIG_MMC_SDHI_SYS_DMAC)),y)
-obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_sys_dmac.o
-endif
-ifeq ($(subst m,y,$(CONFIG_MMC_SDHI_INTERNAL_DMAC)),y)
-obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_internal_dmac.o
-endif
+obj-$(CONFIG_MMC_SDHI_SYS_DMAC) += renesas_sdhi_sys_dmac.o
+obj-$(CONFIG_MMC_SDHI_INTERNAL_DMAC) += renesas_sdhi_internal_dmac.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
--
2.7.4


[PATCH 4.4.y-cip 74/83] mmc: tmio-mmc: fix bad pointer math

Biju Das <biju.das@...>
 

From: Chris Brandt <chris.brandt@...>

commit b5dd7985e8d3357ff9537c0be231190ab1a131fe upstream.

commit 9c284c41c0886f09e75c323a16278b6d353b0b4a upstream.

The existing code gives an incorrect pointer value.
The buffer pointer 'buf' was of type unsigned short *, and 'count' was a
number in bytes. A cast of buf should have been used.

However, instead of casting, just change the code to use u32 pointers.

Reported-by: Dan Carpenter <dan.carpenter@...>
Fixes: 8185e51f358a: ("mmc: tmio-mmc: add support for 32bit data port")
Signed-off-by: Chris Brandt <chris.brandt@...>
Reviewed-by: Geert Uytterhoeven <geert+renesas@...>
Acked-by: Wolfram Sang <wsa+renesas@...>
Cc: <stable@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc_core.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 43209ea28..b6500a6 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -446,30 +446,29 @@ static void tmio_mmc_transfer_data(struct tmio_mmc_host *host,
* Transfer the data
*/
if (host->pdata->flags & TMIO_MMC_32BIT_DATA_PORT) {
- u8 data[4] = { };
+ u32 data = 0;
+ u32 *buf32 = (u32 *)buf;

if (is_read)
- sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, (u32 *)buf,
+ sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, buf32,
count >> 2);
else
- sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, (u32 *)buf,
+ sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, buf32,
count >> 2);

/* if count was multiple of 4 */
if (!(count & 0x3))
return;

- buf8 = (u8 *)(buf + (count >> 2));
+ buf32 += count >> 2;
count %= 4;

if (is_read) {
- sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT,
- (u32 *)data, 1);
- memcpy(buf8, data, count);
+ sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, &data, 1);
+ memcpy(buf32, &data, count);
} else {
- memcpy(data, buf8, count);
- sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT,
- (u32 *)data, 1);
+ memcpy(&data, buf32, count);
+ sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, &data, 1);
}

return;
--
2.7.4


[PATCH 4.4.y-cip 73/83] mmc: renesas-sdhi: add support for R-Car Gen3 SDHI DMAC

Biju Das <biju.das@...>
 

From: Simon Horman <horms+renesas@...>

commit 2a68ea7896e3277d875c5d5e7f34cf2937cb55c3 upstream.

Add a new variant of the SDHI driver to support R-Car Gen3 with DMA via
on-chip bus mastering. Since the DMAC is in a part of the SDHI module it
is not suitable to be used via DMA Engine.

Clearing of DM_CM_INFO1 after DMA thanks to Dirk Behme

Cc: Dirk Behme <dirk.behme@...>
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@...>
Signed-off-by: Ai Kyuse <ai.kyuse.uw@...>
Signed-off-by: Simon Horman <horms+renesas@...>
Reviewed-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/Kconfig | 19 ++
drivers/mmc/host/Makefile | 8 +-
drivers/mmc/host/renesas_sdhi_internal_dmac.c | 272 ++++++++++++++++++++++++++
drivers/mmc/host/renesas_sdhi_sys_dmac.c | 2 +-
drivers/mmc/host/tmio_mmc.h | 1 +
5 files changed, 300 insertions(+), 2 deletions(-)
create mode 100644 drivers/mmc/host/renesas_sdhi_internal_dmac.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index eaf40ec..54d98ee 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -563,10 +563,29 @@ config MMC_SDHI
depends on SUPERH || ARM
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
select MMC_TMIO_CORE
+ select MMC_SDHI_SYS_DMAC if (SUPERH || ARM)
+ select MMC_SDHI_INTERNAL_DMAC if ARM64
help
This provides support for the SDHI SD/SDIO controller found in
Renesas SuperH, ARM and ARM64 based SoCs

+config MMC_SDHI_SYS_DMAC
+ tristate "DMA for SDHI SD/SDIO controllers using SYS-DMAC"
+ depends on MMC_SDHI
+ help
+ This provides DMA support for SDHI SD/SDIO controllers
+ using SYS-DMAC via DMA Engine. This supports the controllers
+ found in SuperH and Renesas ARM based SoCs.
+
+config MMC_SDHI_INTERNAL_DMAC
+ tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
+ depends on ARM64 || COMPILE_TEST
+ depends on MMC_SDHI
+ help
+ This provides DMA support for SDHI SD/SDIO controllers
+ using on-chip bus mastering. This supports the controllers
+ found in arm64 based SoCs.
+
config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
depends on PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index c3c85c9..f10bb0c 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -36,7 +36,13 @@ obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
-obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o renesas_sdhi_sys_dmac.o
+obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o
+ifeq ($(subst m,y,$(CONFIG_MMC_SDHI_SYS_DMAC)),y)
+obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_sys_dmac.o
+endif
+ifeq ($(subst m,y,$(CONFIG_MMC_SDHI_INTERNAL_DMAC)),y)
+obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_internal_dmac.o
+endif
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
new file mode 100644
index 0000000..d41ff35
--- /dev/null
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -0,0 +1,272 @@
+/*
+ * DMA support for Internal DMAC with SDHI SD/SDIO controller
+ *
+ * Copyright (C) 2016-17 Renesas Electronics Corporation
+ * Copyright (C) 2016-17 Horms Solutions, Simon Horman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+
+#include "renesas_sdhi.h"
+#include "tmio_mmc.h"
+
+#define DM_CM_DTRAN_MODE 0x820
+#define DM_CM_DTRAN_CTRL 0x828
+#define DM_CM_RST 0x830
+#define DM_CM_INFO1 0x840
+#define DM_CM_INFO1_MASK 0x848
+#define DM_CM_INFO2 0x850
+#define DM_CM_INFO2_MASK 0x858
+#define DM_DTRAN_ADDR 0x880
+
+/* DM_CM_DTRAN_MODE */
+#define DTRAN_MODE_CH_NUM_CH0 0 /* "downstream" = for write commands */
+#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "uptream" = for read commands */
+#define DTRAN_MODE_BUS_WID_TH (BIT(5) | BIT(4))
+#define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address */
+
+/* DM_CM_DTRAN_CTRL */
+#define DTRAN_CTRL_DM_START BIT(0)
+
+/* DM_CM_RST */
+#define RST_DTRANRST1 BIT(9)
+#define RST_DTRANRST0 BIT(8)
+#define RST_RESERVED_BITS GENMASK_ULL(32, 0)
+
+/* DM_CM_INFO1 and DM_CM_INFO1_MASK */
+#define INFO1_CLEAR 0
+#define INFO1_DTRANEND1 BIT(17)
+#define INFO1_DTRANEND0 BIT(16)
+
+/* DM_CM_INFO2 and DM_CM_INFO2_MASK */
+#define INFO2_DTRANERR1 BIT(17)
+#define INFO2_DTRANERR0 BIT(16)
+
+/*
+ * Specification of this driver:
+ * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
+ * - Since this SDHI DMAC register set has 16 but 32-bit width, we
+ * need a custom accessor.
+ */
+
+/* Definitions for sampling clocks */
+static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
+ MMC_CAP_CMD23,
+ .bus_shift = 2,
+ .scc_offset = 0x1000,
+ .taps = rcar_gen3_scc_taps,
+ .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
+ /* Gen3 SDHI DMAC can handle 0xffffffff blk count, but seg = 1 */
+ .max_blk_count = 0xffffffff,
+ .max_segs = 1,
+};
+
+static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
+ {},
+};
+MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
+
+static void
+renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host *host,
+ int addr, u64 val)
+{
+ writeq(val, host->ctl + addr);
+}
+
+static void
+renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable)
+{
+ if (!host->chan_tx || !host->chan_rx)
+ return;
+
+ if (!enable)
+ renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1,
+ INFO1_CLEAR);
+
+ if (host->dma->enable)
+ host->dma->enable(host, enable);
+}
+
+static void
+renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) {
+ u64 val = RST_DTRANRST1 | RST_DTRANRST0;
+
+ renesas_sdhi_internal_dmac_enable_dma(host, false);
+
+ renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
+ RST_RESERVED_BITS & ~val);
+ renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
+ RST_RESERVED_BITS | val);
+
+ renesas_sdhi_internal_dmac_enable_dma(host, true);
+}
+
+static void
+renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) {
+ tasklet_schedule(&host->dma_complete);
+}
+
+static void
+renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
+ struct mmc_data *data)
+{
+ struct scatterlist *sg = host->sg_ptr;
+ u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
+ enum dma_data_direction dir;
+ int ret;
+ u32 irq_mask;
+
+ /* This DMAC cannot handle if sg_len is not 1 */
+ WARN_ON(host->sg_len > 1);
+
+ /* This DMAC cannot handle if buffer is not 8-bytes alignment */
+ if (!IS_ALIGNED(sg->offset, 8))
+ goto force_pio;
+
+ if (data->flags & MMC_DATA_READ) {
+ dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
+ dir = DMA_FROM_DEVICE;
+ irq_mask = TMIO_STAT_RXRDY;
+ } else {
+ dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
+ dir = DMA_TO_DEVICE;
+ irq_mask = TMIO_STAT_TXRQ;
+ }
+
+ ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir);
+ if (ret == 0)
+ goto force_pio;
+
+ renesas_sdhi_internal_dmac_enable_dma(host, true);
+
+ /* disable PIO irqs to avoid "PIO IRQ in DMA mode!" */
+ tmio_mmc_disable_mmc_irqs(host, irq_mask);
+
+ /* set dma parameters */
+ renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
+ dtran_mode);
+ renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
+ sg->dma_address);
+
+ return;
+
+force_pio:
+ host->force_pio = true;
+ renesas_sdhi_internal_dmac_enable_dma(host, false);
+}
+
+static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
+{
+ struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+
+ tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
+
+ /* start the DMAC */
+ renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_CTRL,
+ DTRAN_CTRL_DM_START);
+}
+
+static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
+{
+ struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+ enum dma_data_direction dir;
+
+ spin_lock_irq(&host->lock);
+
+ if (!host->data)
+ goto out;
+
+ if (host->data->flags & MMC_DATA_READ)
+ dir = DMA_FROM_DEVICE;
+ else
+ dir = DMA_TO_DEVICE;
+
+ renesas_sdhi_internal_dmac_enable_dma(host, false);
+ dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
+
+ tmio_mmc_do_data_irq(host);
+out:
+ spin_unlock_irq(&host->lock);
+}
+
+static void
+renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
+ struct tmio_mmc_data *pdata)
+{
+ /* Each value is set to non-zero to assume "enabling" each DMA */
+ host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
+
+ tasklet_init(&host->dma_complete,
+ renesas_sdhi_internal_dmac_complete_tasklet_fn,
+ (unsigned long)host);
+ tasklet_init(&host->dma_issue,
+ renesas_sdhi_internal_dmac_issue_tasklet_fn,
+ (unsigned long)host);
+}
+
+static void
+renesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host *host)
+{
+ /* Each value is set to zero to assume "disabling" each DMA */
+ host->chan_rx = host->chan_tx = NULL;
+}
+
+static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
+ .start = renesas_sdhi_internal_dmac_start_dma,
+ .enable = renesas_sdhi_internal_dmac_enable_dma,
+ .request = renesas_sdhi_internal_dmac_request_dma,
+ .release = renesas_sdhi_internal_dmac_release_dma,
+ .abort = renesas_sdhi_internal_dmac_abort_dma,
+ .dataend = renesas_sdhi_internal_dmac_dataend_dma,
+};
+
+static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
+{
+ return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
+}
+
+static const struct dev_pm_ops renesas_sdhi_internal_dmac_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+ tmio_mmc_host_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver renesas_internal_dmac_sdhi_driver = {
+ .driver = {
+ .name = "renesas_sdhi_internal_dmac",
+ .pm = &renesas_sdhi_internal_dmac_dev_pm_ops,
+ .of_match_table = renesas_sdhi_internal_dmac_of_match,
+ },
+ .probe = renesas_sdhi_internal_dmac_probe,
+ .remove = renesas_sdhi_remove,
+};
+
+module_platform_driver(renesas_internal_dmac_sdhi_driver);
+
+MODULE_DESCRIPTION("Renesas SDHI driver for internal DMAC");
+MODULE_AUTHOR("Yoshihiro Shimoda");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index 86a81fd..84bb945 100644
--- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -1,5 +1,5 @@
/*
- * DMA function for TMIO MMC implementations
+ * DMA support use of SYS DMAC with SDHI SD/SDIO controller
*
* Copyright (C) 2010-2011 Guennadi Liakhovetski
*
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 17ea4b6..16a3064 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -150,6 +150,7 @@ struct tmio_mmc_host {
struct dma_chan *chan_rx;
struct dma_chan *chan_tx;
struct completion dma_dataend;
+ struct tasklet_struct dma_complete;
struct tasklet_struct dma_issue;
struct scatterlist bounce_sg;
u8 *bounce_buf;
--
2.7.4


[PATCH 4.4.y-cip 72/83] mmc: tmio, renesas-sdhi: add dataend to DMA ops

Biju Das <biju.das@...>
 

From: Simon Horman <horms+renesas@...>

commit 92d0f925e6344a24b12a6eeb4f1030ec0e70e8d1 upstream.

Add dataend to DMA ops to allow DMAC implementation dependent
handling of DMA data end.

Also implement the operation for SDHI.

Signed-off-by: Simon Horman <horms+renesas@...>
Reviewed-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/renesas_sdhi_sys_dmac.c | 6 ++++++
drivers/mmc/host/tmio_mmc.h | 1 +
drivers/mmc/host/tmio_mmc_core.c | 10 ++++++++--
3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index d7757dd..86a81fd 100644
--- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -114,6 +114,11 @@ static void renesas_sdhi_sys_dmac_abort_dma(struct tmio_mmc_host *host)
renesas_sdhi_sys_dmac_enable_dma(host, true);
}

+static void renesas_sdhi_sys_dmac_dataend_dma(struct tmio_mmc_host *host)
+{
+ complete(&host->dma_dataend);
+}
+
static void renesas_sdhi_sys_dmac_dma_callback(void *arg)
{
struct tmio_mmc_host *host = arg;
@@ -439,6 +444,7 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_sys_dmac_dma_ops = {
.request = renesas_sdhi_sys_dmac_request_dma,
.release = renesas_sdhi_sys_dmac_release_dma,
.abort = renesas_sdhi_sys_dmac_abort_dma,
+ .dataend = renesas_sdhi_sys_dmac_dataend_dma,
};

static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev)
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index cd5b4f3..17ea4b6 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -120,6 +120,7 @@ struct tmio_mmc_dma_ops {
struct tmio_mmc_data *pdata);
void (*release)(struct tmio_mmc_host *host);
void (*abort)(struct tmio_mmc_host *host);
+ void (*dataend)(struct tmio_mmc_host *host);
};

struct tmio_mmc_host {
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 810d2d8..43209ea28 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -86,6 +86,12 @@ static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
host->dma_ops->abort(host);
}

+static inline void tmio_mmc_dataend_dma(struct tmio_mmc_host *host)
+{
+ if (host->dma_ops)
+ host->dma_ops->dataend(host);
+}
+
void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
{
host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ);
@@ -637,11 +643,11 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat)

if (done) {
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- complete(&host->dma_dataend);
+ tmio_mmc_dataend_dma(host);
}
} else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) {
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- complete(&host->dma_dataend);
+ tmio_mmc_dataend_dma(host);
} else {
tmio_mmc_do_data_irq(host);
tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP);
--
2.7.4


[PATCH 4.4.y-cip 71/83] mmc: tmio, renesas-sdhi: add max_{segs, blk_count} to tmio_mmc_data

Biju Das <biju.das@...>
 

From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@...>

commit 603aa14d3daaa7073bab4c472025c4963030e0cc upstream.

Allow TMIO and SDHI driver implementations to provide values for
max_segs and max_blk_count.

A follow-up patch will set these values for Renesas Gen3 SoCs
the using an SDHI driver.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@...>
Signed-off-by: Ai Kyuse <ai.kyuse.uw@...>
Signed-off-by: Simon Horman <horms+renesas@...>
Reviewed-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/renesas_sdhi.h | 2 ++
drivers/mmc/host/renesas_sdhi_core.c | 2 ++
drivers/mmc/host/tmio_mmc_core.c | 6 +++---
include/linux/mfd/tmio.h | 2 ++
4 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index 781fe4c..6e33266 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -31,6 +31,8 @@ struct renesas_sdhi_of_data {
int scc_offset;
struct renesas_sdhi_scc *taps;
int taps_num;
+ unsigned int max_blk_count;
+ unsigned short max_segs;
};

int renesas_sdhi_probe(struct platform_device *pdev,
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index a64a3ba..2f8c7b8 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -502,6 +502,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
mmc_data->capabilities |= of_data->capabilities;
mmc_data->capabilities2 |= of_data->capabilities2;
mmc_data->dma_rx_offset = of_data->dma_rx_offset;
+ mmc_data->max_blk_count = of_data->max_blk_count;
+ mmc_data->max_segs = of_data->max_segs;
dma_priv->dma_buswidth = of_data->dma_buswidth;
host->bus_shift = of_data->bus_shift;
}
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 8ab58ca..810d2d8 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -1224,10 +1224,10 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,

mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;
mmc->caps2 |= pdata->capabilities2;
- mmc->max_segs = 32;
+ mmc->max_segs = pdata->max_segs ? : 32;
mmc->max_blk_size = 512;
- mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
- mmc->max_segs;
+ mmc->max_blk_count = pdata->max_blk_count ? :
+ (PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;

diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index a1520d8..662fedc 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -128,6 +128,8 @@ struct tmio_mmc_data {
unsigned int cd_gpio;
int alignment_shift;
dma_addr_t dma_rx_offset;
+ unsigned int max_blk_count;
+ unsigned short max_segs;
void (*set_pwr)(struct platform_device *host, int state);
void (*set_clk_div)(struct platform_device *host, int state);
};
--
2.7.4


[PATCH 4.4.y-cip 70/83] mmc: renesas-sdhi: improve checkpatch cleanness

Biju Das <biju.das@...>
 

From: Simon Horman <horms+renesas@...>

commit 2fe35968feccaee61413edbe54bec66bc80a67a7 upstream.

Trivial updates to improve checkpatch cleanness.

Signed-off-by: Simon Horman <horms+renesas@...>
Reviewed-by: Wolfram Sang <wsa+renesas@...>
Tested-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/renesas_sdhi.h | 2 +-
drivers/mmc/host/renesas_sdhi_core.c | 43 ++++++++++++++++----------------
drivers/mmc/host/renesas_sdhi_sys_dmac.c | 25 +++++++++++--------
3 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index eb3ea15..781fe4c 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -34,6 +34,6 @@ struct renesas_sdhi_of_data {
};

int renesas_sdhi_probe(struct platform_device *pdev,
- const struct tmio_mmc_dma_ops *dma_ops);
+ const struct tmio_mmc_dma_ops *dma_ops);
int renesas_sdhi_remove(struct platform_device *pdev);
#endif
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 36e2f61..a64a3ba 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -44,7 +44,8 @@
#define SDHI_VER_GEN3_SD 0xcc10
#define SDHI_VER_GEN3_SDMMC 0xcd10

-#define host_to_priv(host) container_of((host)->pdata, struct renesas_sdhi, mmc_data)
+#define host_to_priv(host) \
+ container_of((host)->pdata, struct renesas_sdhi, mmc_data)

struct renesas_sdhi {
struct clk *clk;
@@ -92,6 +93,7 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
struct mmc_host *mmc = host->mmc;
struct renesas_sdhi *priv = host_to_priv(host);
int ret = clk_prepare_enable(priv->clk);
+
if (ret < 0)
return ret;

@@ -117,7 +119,7 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
}

static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
- unsigned int new_clock)
+ unsigned int new_clock)
{
struct renesas_sdhi *priv = host_to_priv(host);
unsigned int freq, diff, best_freq = 0, diff_min = ~0;
@@ -166,11 +168,12 @@ static int renesas_sdhi_card_busy(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);

- return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0);
+ return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) &
+ TMIO_STAT_DAT0);
}

static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
- struct mmc_ios *ios)
+ struct mmc_ios *ios)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
struct renesas_sdhi *priv = host_to_priv(host);
@@ -276,7 +279,7 @@ static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host)
}

static void renesas_sdhi_prepare_tuning(struct tmio_mmc_host *host,
- unsigned long tap)
+ unsigned long tap)
{
struct renesas_sdhi *priv = host_to_priv(host);

@@ -309,9 +312,9 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
tap_start = 0;
tap_end = 0;
for (i = 0; i < host->tap_num * 2; i++) {
- if (test_bit(i, host->taps))
+ if (test_bit(i, host->taps)) {
ntap++;
- else {
+ } else {
if (ntap > tap_cnt) {
tap_start = i - ntap;
tap_end = i - 1;
@@ -343,7 +346,6 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
return 0;
}

-
static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
@@ -405,8 +407,7 @@ static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host)

static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
{
- switch (addr)
- {
+ switch (addr) {
case CTL_SD_CMD:
case CTL_STOP_INTERNAL_ACTION:
case CTL_XFER_BLK_COUNT:
@@ -423,7 +424,7 @@ static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
}

static int renesas_sdhi_multi_io_quirk(struct mmc_card *card,
- unsigned int direction, int blk_size)
+ unsigned int direction, int blk_size)
{
/*
* In Renesas controllers, when performing a
@@ -451,20 +452,23 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
int renesas_sdhi_probe(struct platform_device *pdev,
const struct tmio_mmc_dma_ops *dma_ops)
{
- const struct renesas_sdhi_of_data *of_data = of_device_get_match_data( &pdev->dev);
- struct renesas_sdhi *priv;
- struct tmio_mmc_data *mmc_data;
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
+ const struct renesas_sdhi_of_data *of_data;
+ struct tmio_mmc_data *mmc_data;
+ struct tmio_mmc_dma *dma_priv;
struct tmio_mmc_host *host;
+ struct renesas_sdhi *priv;
struct resource *res;
int irq, ret, i;
- struct tmio_mmc_dma *dma_priv;
+
+ of_data = of_device_get_match_data(&pdev->dev);

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;

- priv = devm_kzalloc(&pdev->dev, sizeof(struct renesas_sdhi), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct renesas_sdhi),
+ GFP_KERNEL);
if (!priv)
return -ENOMEM;

@@ -492,7 +496,6 @@ int renesas_sdhi_probe(struct platform_device *pdev,
goto eprobe;
}

-
if (of_data) {
mmc_data->flags |= of_data->tmio_flags;
mmc_data->ocr_mask = of_data->tmio_ocr_mask;
@@ -542,9 +545,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
*/
mmc_data->flags |= TMIO_MMC_SDIO_IRQ;

- /*
- * All SDHI have CMD12 controll bit
- */
+ /* All SDHI have CMD12 control bit */
mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL;

/* All SDHI have SDIO status bits which must be 1 */
@@ -590,7 +591,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
break;
i++;
ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0,
- dev_name(&pdev->dev), host);
+ dev_name(&pdev->dev), host);
if (ret)
goto eirq;
}
diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index 82a37d1..d7757dd 100644
--- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -92,7 +92,6 @@ static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
};
MODULE_DEVICE_TABLE(of, renesas_sdhi_sys_dmac_of_match);

-
static void renesas_sdhi_sys_dmac_enable_dma(struct tmio_mmc_host *host,
bool enable)
{
@@ -184,8 +183,8 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)

ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
if (ret > 0)
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_DEV_TO_MEM, DMA_CTRL_ACK);
+ desc = dmaengine_prep_slave_sg(chan, sg, ret, DMA_DEV_TO_MEM,
+ DMA_CTRL_ACK);

if (desc) {
reinit_completion(&host->dma_dataend);
@@ -253,6 +252,7 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
if (!aligned) {
unsigned long flags;
void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
+
sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
@@ -262,8 +262,8 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)

ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
if (ret > 0)
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_MEM_TO_DEV, DMA_CTRL_ACK);
+ desc = dmaengine_prep_slave_sg(chan, sg, ret, DMA_MEM_TO_DEV,
+ DMA_CTRL_ACK);

if (desc) {
reinit_completion(&host->dma_dataend);
@@ -296,7 +296,7 @@ pio:
}

static void renesas_sdhi_sys_dmac_start_dma(struct tmio_mmc_host *host,
- struct mmc_data *data)
+ struct mmc_data *data)
{
if (data->flags & MMC_DATA_READ) {
if (host->chan_rx)
@@ -334,7 +334,7 @@ static void renesas_sdhi_sys_dmac_request_dma(struct tmio_mmc_host *host,
{
/* We can only either use DMA for both Tx and Rx or not use it at all */
if (!host->dma || (!host->pdev->dev.of_node &&
- (!pdata->chan_priv_tx || !pdata->chan_priv_rx)))
+ (!pdata->chan_priv_tx || !pdata->chan_priv_rx)))
return;

if (!host->chan_tx && !host->chan_rx) {
@@ -360,7 +360,8 @@ static void renesas_sdhi_sys_dmac_request_dma(struct tmio_mmc_host *host,
return;

cfg.direction = DMA_MEM_TO_DEV;
- cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift);
+ cfg.dst_addr = res->start +
+ (CTL_SD_DATA_PORT << host->bus_shift);
cfg.dst_addr_width = host->dma->dma_buswidth;
if (!cfg.dst_addr_width)
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -416,11 +417,13 @@ static void renesas_sdhi_sys_dmac_release_dma(struct tmio_mmc_host *host)
{
if (host->chan_tx) {
struct dma_chan *chan = host->chan_tx;
+
host->chan_tx = NULL;
dma_release_channel(chan);
}
if (host->chan_rx) {
struct dma_chan *chan = host->chan_rx;
+
host->chan_rx = NULL;
dma_release_channel(chan);
}
@@ -445,10 +448,10 @@ static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev)

static const struct dev_pm_ops renesas_sdhi_sys_dmac_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
- tmio_mmc_host_runtime_resume,
- NULL)
+ tmio_mmc_host_runtime_resume,
+ NULL)
};

static struct platform_driver renesas_sys_dmac_sdhi_driver = {
--
2.7.4


[PATCH 4.4.y-cip 69/83] mmc: renesas-sdhi: make renesas_sdhi_sys_dmac main module file

Biju Das <biju.das@...>
 

From: Simon Horman <horms+renesas@...>

commit 9d08428afb722fedaea699a32aaf603a8f1ebd5a upstream.

Make renesas_sdhi_sys_dmac.c a top-level module file that makes use of
library code supplied by renesas_sdhi_core.c

This is in order to facilitate adding other variants of SDHI;
in particular SDHI using different DMA controllers.

Signed-off-by: Simon Horman <horms+renesas@...>
Acked-by: Arnd Bergmann <arnd@...>
Reviewed-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
[Arnd: Fixed module build error]
Signed-off-by: Arnd Bergmann <arnd@...>
Signed-off-by: Biju Das <biju.das@...>
[ Backported to 4.4 Kernel ]
---
drivers/mmc/host/renesas_sdhi.h | 23 +++++-
drivers/mmc/host/renesas_sdhi_core.c | 128 ++-----------------------------
drivers/mmc/host/renesas_sdhi_sys_dmac.c | 109 +++++++++++++++++++++++++-
3 files changed, 135 insertions(+), 125 deletions(-)

diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index f65d936c..eb3ea15 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -12,7 +12,28 @@
#ifndef RENESAS_SDHI_H
#define RENESAS_SDHI_H

+#include <linux/platform_device.h>
#include "tmio_mmc.h"

-const struct tmio_mmc_dma_ops *renesas_sdhi_get_dma_ops(void);
+struct renesas_sdhi_scc {
+ unsigned long clk_rate; /* clock rate for SDR104 */
+ u32 tap; /* sampling clock position for SDR104 */
+};
+
+struct renesas_sdhi_of_data {
+ unsigned long tmio_flags;
+ u32 tmio_ocr_mask;
+ unsigned long capabilities;
+ unsigned long capabilities2;
+ enum dma_slave_buswidth dma_buswidth;
+ dma_addr_t dma_rx_offset;
+ unsigned bus_shift;
+ int scc_offset;
+ struct renesas_sdhi_scc *taps;
+ int taps_num;
+};
+
+int renesas_sdhi_probe(struct platform_device *pdev,
+ const struct tmio_mmc_dma_ops *dma_ops);
+int renesas_sdhi_remove(struct platform_device *pdev);
#endif
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index ee60e90..36e2f61 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -1,5 +1,5 @@
/*
- * SuperH Mobile SDHI
+ * Renesas SDHI
*
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
* Copyright (C) 2015-16 Renesas Electronics Corporation
@@ -23,8 +23,6 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/slab.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/mmc/host.h>
@@ -48,94 +46,6 @@

#define host_to_priv(host) container_of((host)->pdata, struct renesas_sdhi, mmc_data)

-struct renesas_sdhi_scc {
- unsigned long clk_rate; /* clock rate for SDR104 */
- u32 tap; /* sampling clock position for SDR104 */
-};
-
-struct renesas_sdhi_of_data {
- unsigned long tmio_flags;
- u32 tmio_ocr_mask;
- unsigned long capabilities;
- unsigned long capabilities2;
- enum dma_slave_buswidth dma_buswidth;
- dma_addr_t dma_rx_offset;
- unsigned bus_shift;
- int scc_offset;
- struct renesas_sdhi_scc *taps;
- int taps_num;
-};
-
-static const struct renesas_sdhi_of_data of_default_cfg = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
-};
-
-static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL,
- .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
-};
-
-/* Definitions for sampling clocks */
-static struct renesas_sdhi_scc rcar_gen2_scc_taps[] = {
- {
- .clk_rate = 156000000,
- .tap = 0x00000703,
- },
- {
- .clk_rate = 0,
- .tap = 0x00000300,
- },
-};
-
-static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
- .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
- .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .dma_rx_offset = 0x2000,
- .scc_offset = 0x0300,
- .taps = rcar_gen2_scc_taps,
- .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
-};
-
-/* Definitions for sampling clocks */
-static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
- {
- .clk_rate = 0,
- .tap = 0x00000300,
- },
-};
-
-static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
- .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
- .bus_shift = 2,
- .scc_offset = 0x1000,
- .taps = rcar_gen3_scc_taps,
- .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
-};
-
-static const struct of_device_id renesas_sdhi_of_match[] = {
- { .compatible = "renesas,sdhi-shmobile" },
- { .compatible = "renesas,sdhi-sh7372" },
- { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
- { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
- { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
- { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
- { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
- { .compatible = "renesas,sdhi-r8a7743", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7745", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
- {},
-};
-MODULE_DEVICE_TABLE(of, renesas_sdhi_of_match);
-
struct renesas_sdhi {
struct clk *clk;
struct tmio_mmc_data mmc_data;
@@ -538,9 +448,10 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
renesas_sdhi_sdbuf_width(host, enable ? 32 : 16);
}

-static int renesas_sdhi_probe(struct platform_device *pdev)
+int renesas_sdhi_probe(struct platform_device *pdev,
+ const struct tmio_mmc_dma_ops *dma_ops)
{
- const struct renesas_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev);
+ const struct renesas_sdhi_of_data *of_data = of_device_get_match_data( &pdev->dev);
struct renesas_sdhi *priv;
struct tmio_mmc_data *mmc_data;
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
@@ -639,7 +550,7 @@ static int renesas_sdhi_probe(struct platform_device *pdev)
/* All SDHI have SDIO status bits which must be 1 */
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;

- ret = tmio_mmc_host_probe(host, mmc_data, renesas_sdhi_get_dma_ops());
+ ret = tmio_mmc_host_probe(host, mmc_data, dma_ops);
if (ret < 0)
goto efree;

@@ -704,8 +615,9 @@ efree:
eprobe:
return ret;
}
+EXPORT_SYMBOL_GPL(renesas_sdhi_probe);

-static int renesas_sdhi_remove(struct platform_device *pdev)
+int renesas_sdhi_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc);
@@ -714,28 +626,4 @@ static int renesas_sdhi_remove(struct platform_device *pdev)

return 0;
}
-
-static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
- tmio_mmc_host_runtime_resume,
- NULL)
-};
-
-static struct platform_driver renesas_sdhi_driver = {
- .driver = {
- .name = "sh_mobile_sdhi",
- .pm = &tmio_mmc_dev_pm_ops,
- .of_match_table = renesas_sdhi_of_match,
- },
- .probe = renesas_sdhi_probe,
- .remove = renesas_sdhi_remove,
-};
-
-module_platform_driver(renesas_sdhi_driver);
-
-MODULE_DESCRIPTION("Renesas SDHI driver");
-MODULE_AUTHOR("Magnus Damm");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sh_mobile_sdhi");
+EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index ca96e33..82a37d1 100644
--- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -13,13 +13,86 @@
#include <linux/dmaengine.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>

+#include "renesas_sdhi.h"
#include "tmio_mmc.h"

#define TMIO_MMC_MIN_DMA_LEN 8

+static const struct renesas_sdhi_of_data of_default_cfg = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+};
+
+/* Definitions for sampling clocks */
+static struct renesas_sdhi_scc rcar_gen2_scc_taps[] = {
+ {
+ .clk_rate = 156000000,
+ .tap = 0x00000703,
+ },
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+ .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .dma_rx_offset = 0x2000,
+ .scc_offset = 0x0300,
+ .taps = rcar_gen2_scc_taps,
+ .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
+};
+
+/* Definitions for sampling clocks */
+static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+ .bus_shift = 2,
+ .scc_offset = 0x1000,
+ .taps = rcar_gen3_scc_taps,
+ .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
+};
+
+static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
+ { .compatible = "renesas,sdhi-shmobile" },
+ { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
+ { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
+ { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
+ { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
+ { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
+ { .compatible = "renesas,sdhi-r8a7743", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7745", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, renesas_sdhi_sys_dmac_of_match);
+
+
static void renesas_sdhi_sys_dmac_enable_dma(struct tmio_mmc_host *host,
bool enable)
{
@@ -46,8 +119,6 @@ static void renesas_sdhi_sys_dmac_dma_callback(void *arg)
{
struct tmio_mmc_host *host = arg;

- wait_for_completion(&host->dma_dataend);
-
spin_lock_irq(&host->lock);

if (!host->data)
@@ -62,6 +133,11 @@ static void renesas_sdhi_sys_dmac_dma_callback(void *arg)
host->sg_ptr, host->sg_len,
DMA_TO_DEVICE);

+ spin_unlock_irq(&host->lock);
+
+ wait_for_completion(&host->dma_dataend);
+
+ spin_lock_irq(&host->lock);
tmio_mmc_do_data_irq(host);
out:
spin_unlock_irq(&host->lock);
@@ -362,7 +438,32 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_sys_dmac_dma_ops = {
.abort = renesas_sdhi_sys_dmac_abort_dma,
};

-const struct tmio_mmc_dma_ops *renesas_sdhi_get_dma_ops(void)
+static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev)
{
- return &renesas_sdhi_sys_dmac_dma_ops;
+ return renesas_sdhi_probe(pdev, &renesas_sdhi_sys_dmac_dma_ops);
}
+
+static const struct dev_pm_ops renesas_sdhi_sys_dmac_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+ tmio_mmc_host_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver renesas_sys_dmac_sdhi_driver = {
+ .driver = {
+ .name = "sh_mobile_sdhi",
+ .pm = &renesas_sdhi_sys_dmac_dev_pm_ops,
+ .of_match_table = renesas_sdhi_sys_dmac_of_match,
+ },
+ .probe = renesas_sdhi_sys_dmac_probe,
+ .remove = renesas_sdhi_remove,
+};
+
+module_platform_driver(renesas_sys_dmac_sdhi_driver);
+
+MODULE_DESCRIPTION("Renesas SDHI driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh_mobile_sdhi");
--
2.7.4


[PATCH 4.4.y-cip 68/83] mmc: renesas-sdhi: rename sh_mobile_sdhi.c => renesas_sdhi_core.c

Biju Das <biju.das@...>
 

From: Simon Horman <horms+renesas@...>

commit b5b6a5f4f06c0624886b2166e2e8580327f0b943 upstream.

Rename the source file SDHI. A follow-up patch will make it a library
file used by a different top-level module file.

The name "renesas" is chosen as the SDHI driver is applicable to a wider
range of SoCs than SH-Mobile it seems to be a more appropriate name.
However, the SDHI driver source itself, is left as sh_mobile_sdhi to
avoid unnecessary churn.

the name "core" was chosen to reflect the desired role of this file,
to provide core functionality to the sdhi driver. A follow-up patch will
move the file into that role.

Internal symbols have also been renamed to reflect the filename change.

The .name member of struct platform_driver and parameter to
MODULE_ALIAS() have not been changed in order to avoid the complication
of potentially breaking SH SoCs which still use platform drivers.

Signed-off-by: Simon Horman <horms+renesas@...>
Acked-by: Arnd Bergmann <arnd@...>
Reviewed-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
[ Backported to 4.4 kernel ]
---
drivers/mmc/host/Kconfig | 2 +-
drivers/mmc/host/Makefile | 2 +-
drivers/mmc/host/renesas_sdhi_core.c | 741 ++++++++++++++++++++++++++++++++++
drivers/mmc/host/sh_mobile_sdhi.c | 746 -----------------------------------
4 files changed, 743 insertions(+), 748 deletions(-)
create mode 100644 drivers/mmc/host/renesas_sdhi_core.c
delete mode 100644 drivers/mmc/host/sh_mobile_sdhi.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 2e6d2ff..eaf40ec 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -565,7 +565,7 @@ config MMC_SDHI
select MMC_TMIO_CORE
help
This provides support for the SDHI SD/SDIO controller found in
- SuperH and ARM SH-Mobile SoCs
+ Renesas SuperH, ARM and ARM64 based SoCs

config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 7ab00194..c3c85c9 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -36,7 +36,7 @@ obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
-obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o renesas_sdhi_sys_dmac.o
+obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o renesas_sdhi_sys_dmac.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
new file mode 100644
index 0000000..ee60e90
--- /dev/null
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -0,0 +1,741 @@
+/*
+ * SuperH Mobile SDHI
+ *
+ * Copyright (C) 2016 Sang Engineering, Wolfram Sang
+ * Copyright (C) 2015-16 Renesas Electronics Corporation
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on "Compaq ASIC3 support":
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ * Copyright 2004-2005 Phil Blundell
+ * Copyright 2007-2008 OpenedHand Ltd.
+ *
+ * Authors: Phil Blundell <pb@...>,
+ * Samuel Ortiz <sameo@...>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+#include <linux/mfd/tmio.h>
+#include <linux/sh_dma.h>
+#include <linux/delay.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinctrl-state.h>
+#include <linux/regulator/consumer.h>
+
+#include "renesas_sdhi.h"
+#include "tmio_mmc.h"
+
+#define EXT_ACC 0xe4
+
+#define SDHI_VER_GEN2_SDR50 0x490c
+/* very old datasheets said 0x490c for SDR104, too. They are wrong! */
+#define SDHI_VER_GEN2_SDR104 0xcb0d
+#define SDHI_VER_GEN3_SD 0xcc10
+#define SDHI_VER_GEN3_SDMMC 0xcd10
+
+#define host_to_priv(host) container_of((host)->pdata, struct renesas_sdhi, mmc_data)
+
+struct renesas_sdhi_scc {
+ unsigned long clk_rate; /* clock rate for SDR104 */
+ u32 tap; /* sampling clock position for SDR104 */
+};
+
+struct renesas_sdhi_of_data {
+ unsigned long tmio_flags;
+ u32 tmio_ocr_mask;
+ unsigned long capabilities;
+ unsigned long capabilities2;
+ enum dma_slave_buswidth dma_buswidth;
+ dma_addr_t dma_rx_offset;
+ unsigned bus_shift;
+ int scc_offset;
+ struct renesas_sdhi_scc *taps;
+ int taps_num;
+};
+
+static const struct renesas_sdhi_of_data of_default_cfg = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+};
+
+/* Definitions for sampling clocks */
+static struct renesas_sdhi_scc rcar_gen2_scc_taps[] = {
+ {
+ .clk_rate = 156000000,
+ .tap = 0x00000703,
+ },
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+ .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .dma_rx_offset = 0x2000,
+ .scc_offset = 0x0300,
+ .taps = rcar_gen2_scc_taps,
+ .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
+};
+
+/* Definitions for sampling clocks */
+static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+ .bus_shift = 2,
+ .scc_offset = 0x1000,
+ .taps = rcar_gen3_scc_taps,
+ .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
+};
+
+static const struct of_device_id renesas_sdhi_of_match[] = {
+ { .compatible = "renesas,sdhi-shmobile" },
+ { .compatible = "renesas,sdhi-sh7372" },
+ { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
+ { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
+ { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
+ { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
+ { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
+ { .compatible = "renesas,sdhi-r8a7743", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7745", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, renesas_sdhi_of_match);
+
+struct renesas_sdhi {
+ struct clk *clk;
+ struct tmio_mmc_data mmc_data;
+ struct tmio_mmc_dma dma_priv;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default, *pins_uhs;
+ void __iomem *scc_ctl;
+};
+
+static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
+{
+ u32 val;
+
+ /*
+ * see also
+ * renesas_sdhi_of_data :: dma_buswidth
+ */
+ switch (sd_ctrl_read16(host, CTL_VERSION)) {
+ case SDHI_VER_GEN2_SDR50:
+ val = (width == 32) ? 0x0001 : 0x0000;
+ break;
+ case SDHI_VER_GEN2_SDR104:
+ val = (width == 32) ? 0x0000 : 0x0001;
+ break;
+ case SDHI_VER_GEN3_SD:
+ case SDHI_VER_GEN3_SDMMC:
+ if (width == 64)
+ val = 0x0000;
+ else if (width == 32)
+ val = 0x0101;
+ else
+ val = 0x0001;
+ break;
+ default:
+ /* nothing to do */
+ return;
+ }
+
+ sd_ctrl_write16(host, EXT_ACC, val);
+}
+
+static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+ struct renesas_sdhi *priv = host_to_priv(host);
+ int ret = clk_prepare_enable(priv->clk);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The clock driver may not know what maximum frequency
+ * actually works, so it should be set with the max-frequency
+ * property which will already have been read to f_max. If it
+ * was missing, assume the current frequency is the maximum.
+ */
+ if (!mmc->f_max)
+ mmc->f_max = clk_get_rate(priv->clk);
+
+ /*
+ * Minimum frequency is the minimum input clock frequency
+ * divided by our maximum divider.
+ */
+ mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L);
+
+ /* enable 16bit data access on SDBUF as default */
+ renesas_sdhi_sdbuf_width(host, 16);
+
+ return 0;
+}
+
+static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
+ unsigned int new_clock)
+{
+ struct renesas_sdhi *priv = host_to_priv(host);
+ unsigned int freq, diff, best_freq = 0, diff_min = ~0;
+ int i, ret;
+
+ /* tested only on RCar Gen2+ currently; may work for others */
+ if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
+ return clk_get_rate(priv->clk);
+
+ /*
+ * We want the bus clock to be as close as possible to, but no
+ * greater than, new_clock. As we can divide by 1 << i for
+ * any i in [0, 9] we want the input clock to be as close as
+ * possible, but no greater than, new_clock << i.
+ */
+ for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) {
+ freq = clk_round_rate(priv->clk, new_clock << i);
+ if (freq > (new_clock << i)) {
+ /* Too fast; look for a slightly slower option */
+ freq = clk_round_rate(priv->clk,
+ (new_clock << i) / 4 * 3);
+ if (freq > (new_clock << i))
+ continue;
+ }
+
+ diff = new_clock - (freq >> i);
+ if (diff <= diff_min) {
+ best_freq = freq;
+ diff_min = diff;
+ }
+ }
+
+ ret = clk_set_rate(priv->clk, best_freq);
+
+ return ret == 0 ? best_freq : clk_get_rate(priv->clk);
+}
+
+static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host)
+{
+ struct renesas_sdhi *priv = host_to_priv(host);
+
+ clk_disable_unprepare(priv->clk);
+}
+
+static int renesas_sdhi_card_busy(struct mmc_host *mmc)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+
+ return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0);
+}
+
+static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct renesas_sdhi *priv = host_to_priv(host);
+ struct pinctrl_state *pin_state;
+ int ret;
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ pin_state = priv->pins_default;
+ break;
+ case MMC_SIGNAL_VOLTAGE_180:
+ pin_state = priv->pins_uhs;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * If anything is missing, assume signal voltage is fixed at
+ * 3.3V and succeed/fail accordingly.
+ */
+ if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state))
+ return ios->signal_voltage ==
+ MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL;
+
+ ret = mmc_regulator_set_vqmmc(host->mmc, ios);
+ if (ret)
+ return ret;
+
+ return pinctrl_select_state(priv->pinctrl, pin_state);
+}
+
+/* SCC registers */
+#define SH_MOBILE_SDHI_SCC_DTCNTL 0x000
+#define SH_MOBILE_SDHI_SCC_TAPSET 0x002
+#define SH_MOBILE_SDHI_SCC_DT2FF 0x004
+#define SH_MOBILE_SDHI_SCC_CKSEL 0x006
+#define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008
+#define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A
+
+/* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */
+#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0)
+#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16
+#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff
+
+/* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */
+#define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL BIT(0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */
+#define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */
+#define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2)
+
+static inline u32 sd_scc_read32(struct tmio_mmc_host *host,
+ struct renesas_sdhi *priv, int addr)
+{
+ return readl(priv->scc_ctl + (addr << host->bus_shift));
+}
+
+static inline void sd_scc_write32(struct tmio_mmc_host *host,
+ struct renesas_sdhi *priv,
+ int addr, u32 val)
+{
+ writel(val, priv->scc_ctl + (addr << host->bus_shift));
+}
+
+static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host)
+{
+ struct renesas_sdhi *priv;
+
+ priv = host_to_priv(host);
+
+ /* set sampling clock selection range */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
+ 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT);
+
+ /* Initialize SCC */
+ sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x0);
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
+ SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL));
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
+ SH_MOBILE_SDHI_SCC_CKSEL_DTSEL |
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
+ ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, host->scc_tappos);
+
+ /* Read TAPNUM */
+ return (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL) >>
+ SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) &
+ SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK;
+}
+
+static void renesas_sdhi_prepare_tuning(struct tmio_mmc_host *host,
+ unsigned long tap)
+{
+ struct renesas_sdhi *priv = host_to_priv(host);
+
+ /* Set sampling clock position */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap);
+}
+
+#define SH_MOBILE_SDHI_MAX_TAP 3
+
+static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
+{
+ struct renesas_sdhi *priv = host_to_priv(host);
+ unsigned long tap_cnt; /* counter of tuning success */
+ unsigned long tap_set; /* tap position */
+ unsigned long tap_start;/* start position of tuning success */
+ unsigned long tap_end; /* end position of tuning success */
+ unsigned long ntap; /* temporary counter of tuning success */
+ unsigned long i;
+
+ /* Clear SCC_RVSREQ */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+
+ /*
+ * Find the longest consecutive run of successful probes. If that
+ * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the
+ * center index as the tap.
+ */
+ tap_cnt = 0;
+ ntap = 0;
+ tap_start = 0;
+ tap_end = 0;
+ for (i = 0; i < host->tap_num * 2; i++) {
+ if (test_bit(i, host->taps))
+ ntap++;
+ else {
+ if (ntap > tap_cnt) {
+ tap_start = i - ntap;
+ tap_end = i - 1;
+ tap_cnt = ntap;
+ }
+ ntap = 0;
+ }
+ }
+
+ if (ntap > tap_cnt) {
+ tap_start = i - ntap;
+ tap_end = i - 1;
+ tap_cnt = ntap;
+ }
+
+ if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP)
+ tap_set = (tap_start + tap_end) / 2 % host->tap_num;
+ else
+ return -EIO;
+
+ /* Set SCC */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap_set);
+
+ /* Enable auto re-tuning */
+ 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));
+
+ return 0;
+}
+
+
+static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
+{
+ struct renesas_sdhi *priv = host_to_priv(host);
+
+ /* Check SCC error */
+ if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
+ SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &&
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) &
+ SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) {
+ /* Clear SCC error */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+ return true;
+ }
+
+ return false;
+}
+
+static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host)
+{
+ struct renesas_sdhi *priv;
+
+ priv = host_to_priv(host);
+
+ /* Reset SCC */
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
+ ~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
+ ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+ 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));
+}
+
+static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host)
+{
+ int timeout = 1000;
+
+ while (--timeout && !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS)
+ & TMIO_STAT_SCLKDIVEN))
+ udelay(1);
+
+ if (!timeout) {
+ dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
+{
+ switch (addr)
+ {
+ case CTL_SD_CMD:
+ case CTL_STOP_INTERNAL_ACTION:
+ case CTL_XFER_BLK_COUNT:
+ case CTL_SD_CARD_CLK_CTL:
+ case CTL_SD_XFER_LEN:
+ case CTL_SD_MEM_CARD_OPT:
+ case CTL_TRANSACTION_CTL:
+ case CTL_DMA_ENABLE:
+ case EXT_ACC:
+ return renesas_sdhi_wait_idle(host);
+ }
+
+ return 0;
+}
+
+static int renesas_sdhi_multi_io_quirk(struct mmc_card *card,
+ unsigned int direction, int blk_size)
+{
+ /*
+ * In Renesas controllers, when performing a
+ * multiple block read of one or two blocks,
+ * depending on the timing with which the
+ * response register is read, the response
+ * value may not be read properly.
+ * Use single block read for this HW bug
+ */
+ if ((direction == MMC_DATA_READ) &&
+ blk_size == 2)
+ return 1;
+
+ return blk_size;
+}
+
+static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
+{
+ sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
+
+ /* enable 32bit access if DMA mode if possibile */
+ renesas_sdhi_sdbuf_width(host, enable ? 32 : 16);
+}
+
+static int renesas_sdhi_probe(struct platform_device *pdev)
+{
+ const struct renesas_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev);
+ struct renesas_sdhi *priv;
+ struct tmio_mmc_data *mmc_data;
+ struct tmio_mmc_data *mmd = pdev->dev.platform_data;
+ struct tmio_mmc_host *host;
+ struct resource *res;
+ int irq, ret, i;
+ struct tmio_mmc_dma *dma_priv;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct renesas_sdhi), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ mmc_data = &priv->mmc_data;
+ dma_priv = &priv->dma_priv;
+
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
+ goto eprobe;
+ }
+
+ priv->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (!IS_ERR(priv->pinctrl)) {
+ priv->pins_default = pinctrl_lookup_state(priv->pinctrl,
+ PINCTRL_STATE_DEFAULT);
+ priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl,
+ "state_uhs");
+ }
+
+ host = tmio_mmc_host_alloc(pdev);
+ if (!host) {
+ ret = -ENOMEM;
+ goto eprobe;
+ }
+
+
+ if (of_data) {
+ mmc_data->flags |= of_data->tmio_flags;
+ mmc_data->ocr_mask = of_data->tmio_ocr_mask;
+ mmc_data->capabilities |= of_data->capabilities;
+ mmc_data->capabilities2 |= of_data->capabilities2;
+ mmc_data->dma_rx_offset = of_data->dma_rx_offset;
+ dma_priv->dma_buswidth = of_data->dma_buswidth;
+ host->bus_shift = of_data->bus_shift;
+ }
+
+ host->dma = dma_priv;
+ host->write16_hook = renesas_sdhi_write16_hook;
+ host->clk_enable = renesas_sdhi_clk_enable;
+ host->clk_update = renesas_sdhi_clk_update;
+ host->clk_disable = renesas_sdhi_clk_disable;
+ host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
+
+ /* SDR speeds are only available on Gen2+ */
+ if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) {
+ /* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */
+ host->card_busy = renesas_sdhi_card_busy;
+ host->start_signal_voltage_switch =
+ renesas_sdhi_start_signal_voltage_switch;
+ }
+
+ /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
+ if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */
+ host->bus_shift = 1;
+
+ if (mmd)
+ *mmc_data = *mmd;
+
+ dma_priv->filter = shdma_chan_filter;
+ dma_priv->enable = renesas_sdhi_enable_dma;
+
+ mmc_data->alignment_shift = 1; /* 2-byte alignment */
+ mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED;
+
+ /*
+ * All SDHI blocks support 2-byte and larger block sizes in 4-bit
+ * bus width mode.
+ */
+ mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES;
+
+ /*
+ * All SDHI blocks support SDIO IRQ signalling.
+ */
+ mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
+
+ /*
+ * All SDHI have CMD12 controll bit
+ */
+ mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL;
+
+ /* All SDHI have SDIO status bits which must be 1 */
+ mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
+
+ ret = tmio_mmc_host_probe(host, mmc_data, renesas_sdhi_get_dma_ops());
+ if (ret < 0)
+ goto efree;
+
+ /* Enable tuning iff we have an SCC and a supported mode */
+ if (of_data && of_data->scc_offset &&
+ (host->mmc->caps & MMC_CAP_UHS_SDR104 ||
+ host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR)) {
+ const struct renesas_sdhi_scc *taps = of_data->taps;
+ bool hit = false;
+
+ host->mmc->caps |= MMC_CAP_HW_RESET;
+
+ for (i = 0; i < of_data->taps_num; i++) {
+ if (taps[i].clk_rate == 0 ||
+ taps[i].clk_rate == host->mmc->f_max) {
+ host->scc_tappos = taps->tap;
+ hit = true;
+ break;
+ }
+ }
+
+ if (!hit)
+ dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");
+
+ priv->scc_ctl = host->ctl + of_data->scc_offset;
+ host->init_tuning = renesas_sdhi_init_tuning;
+ host->prepare_tuning = renesas_sdhi_prepare_tuning;
+ host->select_tuning = renesas_sdhi_select_tuning;
+ host->check_scc_error = renesas_sdhi_check_scc_error;
+ host->hw_reset = renesas_sdhi_hw_reset;
+ }
+
+ i = 0;
+ while (1) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ break;
+ i++;
+ ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0,
+ dev_name(&pdev->dev), host);
+ if (ret)
+ goto eirq;
+ }
+
+ /* There must be at least one IRQ source */
+ if (!i) {
+ ret = irq;
+ goto eirq;
+ }
+
+ dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n",
+ mmc_hostname(host->mmc), (unsigned long)
+ (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
+ host->mmc->f_max / 1000000);
+
+ return ret;
+
+eirq:
+ tmio_mmc_host_remove(host);
+efree:
+ tmio_mmc_host_free(host);
+eprobe:
+ return ret;
+}
+
+static int renesas_sdhi_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+
+ tmio_mmc_host_remove(host);
+
+ return 0;
+}
+
+static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+ tmio_mmc_host_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver renesas_sdhi_driver = {
+ .driver = {
+ .name = "sh_mobile_sdhi",
+ .pm = &tmio_mmc_dev_pm_ops,
+ .of_match_table = renesas_sdhi_of_match,
+ },
+ .probe = renesas_sdhi_probe,
+ .remove = renesas_sdhi_remove,
+};
+
+module_platform_driver(renesas_sdhi_driver);
+
+MODULE_DESCRIPTION("Renesas SDHI driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh_mobile_sdhi");
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
deleted file mode 100644
index 8ca9860..0000000
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ /dev/null
@@ -1,746 +0,0 @@
-/*
- * SuperH Mobile SDHI
- *
- * Copyright (C) 2016 Sang Engineering, Wolfram Sang
- * Copyright (C) 2015-16 Renesas Electronics Corporation
- * Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Based on "Compaq ASIC3 support":
- *
- * Copyright 2001 Compaq Computer Corporation.
- * Copyright 2004-2005 Phil Blundell
- * Copyright 2007-2008 OpenedHand Ltd.
- *
- * Authors: Phil Blundell <pb@...>,
- * Samuel Ortiz <sameo@...>
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/mmc/host.h>
-#include <linux/mfd/tmio.h>
-#include <linux/sh_dma.h>
-#include <linux/delay.h>
-#include <linux/pinctrl/consumer.h>
-#include <linux/pinctrl/pinctrl-state.h>
-#include <linux/regulator/consumer.h>
-
-#include "renesas_sdhi.h"
-#include "tmio_mmc.h"
-
-#define EXT_ACC 0xe4
-
-#define SDHI_VER_GEN2_SDR50 0x490c
-/* very old datasheets said 0x490c for SDR104, too. They are wrong! */
-#define SDHI_VER_GEN2_SDR104 0xcb0d
-#define SDHI_VER_GEN3_SD 0xcc10
-#define SDHI_VER_GEN3_SDMMC 0xcd10
-
-#define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data)
-
-struct sh_mobile_sdhi_scc {
- unsigned long clk_rate; /* clock rate for SDR104 */
- u32 tap; /* sampling clock position for SDR104 */
-};
-
-struct sh_mobile_sdhi_of_data {
- unsigned long tmio_flags;
- u32 tmio_ocr_mask;
- unsigned long capabilities;
- unsigned long capabilities2;
- enum dma_slave_buswidth dma_buswidth;
- dma_addr_t dma_rx_offset;
- unsigned bus_shift;
- int scc_offset;
- struct sh_mobile_sdhi_scc *taps;
- int taps_num;
-};
-
-static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
- {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
- },
-};
-
-static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL,
- .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
-};
-
-/* Definitions for sampling clocks */
-static struct sh_mobile_sdhi_scc rcar_gen2_scc_taps[] = {
- {
- .clk_rate = 156000000,
- .tap = 0x00000703,
- },
- {
- .clk_rate = 0,
- .tap = 0x00000300,
- },
-};
-
-static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
- .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
- .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .dma_rx_offset = 0x2000,
- .scc_offset = 0x0300,
- .taps = rcar_gen2_scc_taps,
- .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
-};
-
-/* Definitions for sampling clocks */
-static struct sh_mobile_sdhi_scc rcar_gen3_scc_taps[] = {
- {
- .clk_rate = 0,
- .tap = 0x00000300,
- },
-};
-
-static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
- .capabilities = MMC_CAP_SD_HIGHSPEED,
- .bus_shift = 2,
- .scc_offset = 0x1000,
- .taps = rcar_gen3_scc_taps,
- .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
-};
-
-static const struct of_device_id sh_mobile_sdhi_of_match[] = {
- { .compatible = "renesas,sdhi-shmobile" },
- { .compatible = "renesas,sdhi-sh7372" },
- { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], },
- { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], },
- { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], },
- { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
- { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
- { .compatible = "renesas,sdhi-r8a7743", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7745", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
- {},
-};
-MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
-
-struct sh_mobile_sdhi {
- struct clk *clk;
- struct tmio_mmc_data mmc_data;
- struct tmio_mmc_dma dma_priv;
- struct pinctrl *pinctrl;
- struct pinctrl_state *pins_default, *pins_uhs;
- void __iomem *scc_ctl;
-};
-
-static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
-{
- u32 val;
-
- /*
- * see also
- * sh_mobile_sdhi_of_data :: dma_buswidth
- */
- switch (sd_ctrl_read16(host, CTL_VERSION)) {
- case SDHI_VER_GEN2_SDR50:
- val = (width == 32) ? 0x0001 : 0x0000;
- break;
- case SDHI_VER_GEN2_SDR104:
- val = (width == 32) ? 0x0000 : 0x0001;
- break;
- case SDHI_VER_GEN3_SD:
- case SDHI_VER_GEN3_SDMMC:
- if (width == 64)
- val = 0x0000;
- else if (width == 32)
- val = 0x0101;
- else
- val = 0x0001;
- break;
- default:
- /* nothing to do */
- return;
- }
-
- sd_ctrl_write16(host, EXT_ACC, val);
-}
-
-static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host)
-{
- struct mmc_host *mmc = host->mmc;
- struct sh_mobile_sdhi *priv = host_to_priv(host);
- int ret = clk_prepare_enable(priv->clk);
- if (ret < 0)
- return ret;
-
- /*
- * The clock driver may not know what maximum frequency
- * actually works, so it should be set with the max-frequency
- * property which will already have been read to f_max. If it
- * was missing, assume the current frequency is the maximum.
- */
- if (!mmc->f_max)
- mmc->f_max = clk_get_rate(priv->clk);
-
- /*
- * Minimum frequency is the minimum input clock frequency
- * divided by our maximum divider.
- */
- mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L);
-
- /* enable 16bit data access on SDBUF as default */
- sh_mobile_sdhi_sdbuf_width(host, 16);
-
- return 0;
-}
-
-static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host,
- unsigned int new_clock)
-{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
- unsigned int freq, diff, best_freq = 0, diff_min = ~0;
- int i, ret;
-
- /* tested only on RCar Gen2+ currently; may work for others */
- if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
- return clk_get_rate(priv->clk);
-
- /*
- * We want the bus clock to be as close as possible to, but no
- * greater than, new_clock. As we can divide by 1 << i for
- * any i in [0, 9] we want the input clock to be as close as
- * possible, but no greater than, new_clock << i.
- */
- for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) {
- freq = clk_round_rate(priv->clk, new_clock << i);
- if (freq > (new_clock << i)) {
- /* Too fast; look for a slightly slower option */
- freq = clk_round_rate(priv->clk,
- (new_clock << i) / 4 * 3);
- if (freq > (new_clock << i))
- continue;
- }
-
- diff = new_clock - (freq >> i);
- if (diff <= diff_min) {
- best_freq = freq;
- diff_min = diff;
- }
- }
-
- ret = clk_set_rate(priv->clk, best_freq);
-
- return ret == 0 ? best_freq : clk_get_rate(priv->clk);
-}
-
-static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host)
-{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
-
- clk_disable_unprepare(priv->clk);
-}
-
-static int sh_mobile_sdhi_card_busy(struct mmc_host *mmc)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
-
- return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0);
-}
-
-static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
- struct mmc_ios *ios)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- struct sh_mobile_sdhi *priv = host_to_priv(host);
- struct pinctrl_state *pin_state;
- int ret;
-
- switch (ios->signal_voltage) {
- case MMC_SIGNAL_VOLTAGE_330:
- pin_state = priv->pins_default;
- break;
- case MMC_SIGNAL_VOLTAGE_180:
- pin_state = priv->pins_uhs;
- break;
- default:
- return -EINVAL;
- }
-
- /*
- * If anything is missing, assume signal voltage is fixed at
- * 3.3V and succeed/fail accordingly.
- */
- if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state))
- return ios->signal_voltage ==
- MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL;
-
- ret = mmc_regulator_set_vqmmc(host->mmc, ios);
- if (ret)
- return ret;
-
- ret = pinctrl_select_state(priv->pinctrl, pin_state);
- if (ret)
- return ret;
-
- return 0;
-}
-
-/* SCC registers */
-#define SH_MOBILE_SDHI_SCC_DTCNTL 0x000
-#define SH_MOBILE_SDHI_SCC_TAPSET 0x002
-#define SH_MOBILE_SDHI_SCC_DT2FF 0x004
-#define SH_MOBILE_SDHI_SCC_CKSEL 0x006
-#define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008
-#define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A
-
-/* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */
-#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0)
-#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16
-#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff
-
-/* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */
-#define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL BIT(0)
-/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */
-#define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0)
-/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */
-#define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2)
-
-static inline u32 sd_scc_read32(struct tmio_mmc_host *host,
- struct sh_mobile_sdhi *priv, int addr)
-{
- return readl(priv->scc_ctl + (addr << host->bus_shift));
-}
-
-static inline void sd_scc_write32(struct tmio_mmc_host *host,
- struct sh_mobile_sdhi *priv,
- int addr, u32 val)
-{
- writel(val, priv->scc_ctl + (addr << host->bus_shift));
-}
-
-static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host)
-{
- struct sh_mobile_sdhi *priv;
-
- priv = host_to_priv(host);
-
- /* set sampling clock selection range */
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
- 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT);
-
- /* Initialize SCC */
- sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x0);
-
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
- SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
- sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL));
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
-
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
- SH_MOBILE_SDHI_SCC_CKSEL_DTSEL |
- sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
-
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
- ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
- sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
-
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, host->scc_tappos);
-
- /* Read TAPNUM */
- return (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL) >>
- SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) &
- SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK;
-}
-
-static void sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host,
- unsigned long tap)
-{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
-
- /* Set sampling clock position */
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap);
-}
-
-#define SH_MOBILE_SDHI_MAX_TAP 3
-
-static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host)
-{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
- unsigned long tap_cnt; /* counter of tuning success */
- unsigned long tap_set; /* tap position */
- unsigned long tap_start;/* start position of tuning success */
- unsigned long tap_end; /* end position of tuning success */
- unsigned long ntap; /* temporary counter of tuning success */
- unsigned long i;
-
- /* Clear SCC_RVSREQ */
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
-
- /*
- * Find the longest consecutive run of successful probes. If that
- * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the
- * center index as the tap.
- */
- tap_cnt = 0;
- ntap = 0;
- tap_start = 0;
- tap_end = 0;
- for (i = 0; i < host->tap_num * 2; i++) {
- if (test_bit(i, host->taps))
- ntap++;
- else {
- if (ntap > tap_cnt) {
- tap_start = i - ntap;
- tap_end = i - 1;
- tap_cnt = ntap;
- }
- ntap = 0;
- }
- }
-
- if (ntap > tap_cnt) {
- tap_start = i - ntap;
- tap_end = i - 1;
- tap_cnt = ntap;
- }
-
- if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP)
- tap_set = (tap_start + tap_end) / 2 % host->tap_num;
- else
- return -EIO;
-
- /* Set SCC */
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap_set);
-
- /* Enable auto re-tuning */
- 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));
-
- return 0;
-}
-
-
-static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host)
-{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
-
- /* Check SCC error */
- if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
- SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &&
- sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) &
- SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) {
- /* Clear SCC error */
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
- return true;
- }
-
- return false;
-}
-
-static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host)
-{
- struct sh_mobile_sdhi *priv;
-
- priv = host_to_priv(host);
-
- /* Reset SCC */
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
-
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
- ~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
- sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
-
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
- ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
- sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
-
- 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));
-}
-
-static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
-{
- int timeout = 1000;
-
- while (--timeout && !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS)
- & TMIO_STAT_SCLKDIVEN))
- udelay(1);
-
- if (!timeout) {
- dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n");
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
-{
- switch (addr)
- {
- case CTL_SD_CMD:
- case CTL_STOP_INTERNAL_ACTION:
- case CTL_XFER_BLK_COUNT:
- case CTL_SD_CARD_CLK_CTL:
- case CTL_SD_XFER_LEN:
- case CTL_SD_MEM_CARD_OPT:
- case CTL_TRANSACTION_CTL:
- case CTL_DMA_ENABLE:
- return sh_mobile_sdhi_wait_idle(host);
- }
-
- return 0;
-}
-
-static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card,
- unsigned int direction, int blk_size)
-{
- /*
- * In Renesas controllers, when performing a
- * multiple block read of one or two blocks,
- * depending on the timing with which the
- * response register is read, the response
- * value may not be read properly.
- * Use single block read for this HW bug
- */
- if ((direction == MMC_DATA_READ) &&
- blk_size == 2)
- return 1;
-
- return blk_size;
-}
-
-static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
-{
- sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
-
- /* enable 32bit access if DMA mode if possibile */
- sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16);
-}
-
-static int sh_mobile_sdhi_probe(struct platform_device *pdev)
-{
- const struct sh_mobile_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev);
- struct sh_mobile_sdhi *priv;
- struct tmio_mmc_data *mmc_data;
- struct tmio_mmc_data *mmd = pdev->dev.platform_data;
- struct tmio_mmc_host *host;
- struct resource *res;
- int irq, ret, i;
- struct tmio_mmc_dma *dma_priv;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- mmc_data = &priv->mmc_data;
- dma_priv = &priv->dma_priv;
-
- priv->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(priv->clk)) {
- ret = PTR_ERR(priv->clk);
- dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
- goto eprobe;
- }
-
- priv->pinctrl = devm_pinctrl_get(&pdev->dev);
- if (!IS_ERR(priv->pinctrl)) {
- priv->pins_default = pinctrl_lookup_state(priv->pinctrl,
- PINCTRL_STATE_DEFAULT);
- priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl,
- "state_uhs");
- }
-
- host = tmio_mmc_host_alloc(pdev);
- if (!host) {
- ret = -ENOMEM;
- goto eprobe;
- }
-
-
- if (of_data) {
- mmc_data->flags |= of_data->tmio_flags;
- mmc_data->ocr_mask = of_data->tmio_ocr_mask;
- mmc_data->capabilities |= of_data->capabilities;
- mmc_data->capabilities2 |= of_data->capabilities2;
- mmc_data->dma_rx_offset = of_data->dma_rx_offset;
- dma_priv->dma_buswidth = of_data->dma_buswidth;
- host->bus_shift = of_data->bus_shift;
- }
-
- host->dma = dma_priv;
- host->write16_hook = sh_mobile_sdhi_write16_hook;
- host->clk_enable = sh_mobile_sdhi_clk_enable;
- host->clk_update = sh_mobile_sdhi_clk_update;
- host->clk_disable = sh_mobile_sdhi_clk_disable;
- host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
-
- /* SDR speeds are only available on Gen2+ */
- if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) {
- /* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */
- host->card_busy = sh_mobile_sdhi_card_busy;
- host->start_signal_voltage_switch =
- sh_mobile_sdhi_start_signal_voltage_switch;
- }
-
- /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
- if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */
- host->bus_shift = 1;
-
- if (mmd)
- *mmc_data = *mmd;
-
- dma_priv->filter = shdma_chan_filter;
- dma_priv->enable = sh_mobile_sdhi_enable_dma;
-
- mmc_data->alignment_shift = 1; /* 2-byte alignment */
- mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED;
-
- /*
- * All SDHI blocks support 2-byte and larger block sizes in 4-bit
- * bus width mode.
- */
- mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES;
-
- /*
- * All SDHI blocks support SDIO IRQ signalling.
- */
- mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
-
- /*
- * All SDHI have CMD12 controll bit
- */
- mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL;
-
- /* All SDHI have SDIO status bits which must be 1 */
- mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
-
- ret = tmio_mmc_host_probe(host, mmc_data, renesas_sdhi_get_dma_ops());
- if (ret < 0)
- goto efree;
-
- /* Enable tuning iff we have an SCC and a supported mode */
- if (of_data && of_data->scc_offset &&
- (host->mmc->caps & MMC_CAP_UHS_SDR104 ||
- host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR)) {
- const struct sh_mobile_sdhi_scc *taps = of_data->taps;
- bool hit = false;
-
- host->mmc->caps |= MMC_CAP_HW_RESET;
-
- for (i = 0; i < of_data->taps_num; i++) {
- if (taps[i].clk_rate == 0 ||
- taps[i].clk_rate == host->mmc->f_max) {
- host->scc_tappos = taps->tap;
- hit = true;
- break;
- }
- }
-
- if (!hit)
- dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");
-
- priv->scc_ctl = host->ctl + of_data->scc_offset;
- host->init_tuning = sh_mobile_sdhi_init_tuning;
- host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
- host->select_tuning = sh_mobile_sdhi_select_tuning;
- host->check_scc_error = sh_mobile_sdhi_check_scc_error;
- host->hw_reset = sh_mobile_sdhi_hw_reset;
- }
-
- i = 0;
- while (1) {
- irq = platform_get_irq(pdev, i);
- if (irq < 0)
- break;
- i++;
- ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0,
- dev_name(&pdev->dev), host);
- if (ret)
- goto eirq;
- }
-
- /* There must be at least one IRQ source */
- if (!i) {
- ret = irq;
- goto eirq;
- }
-
- dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n",
- mmc_hostname(host->mmc), (unsigned long)
- (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
- host->mmc->f_max / 1000000);
-
- return ret;
-
-eirq:
- tmio_mmc_host_remove(host);
-efree:
- tmio_mmc_host_free(host);
-eprobe:
- return ret;
-}
-
-static int sh_mobile_sdhi_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct tmio_mmc_host *host = mmc_priv(mmc);
-
- tmio_mmc_host_remove(host);
-
- return 0;
-}
-
-static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
- tmio_mmc_host_runtime_resume,
- NULL)
-};
-
-static struct platform_driver sh_mobile_sdhi_driver = {
- .driver = {
- .name = "sh_mobile_sdhi",
- .pm = &tmio_mmc_dev_pm_ops,
- .of_match_table = sh_mobile_sdhi_of_match,
- },
- .probe = sh_mobile_sdhi_probe,
- .remove = sh_mobile_sdhi_remove,
-};
-
-module_platform_driver(sh_mobile_sdhi_driver);
-
-MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
-MODULE_AUTHOR("Magnus Damm");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sh_mobile_sdhi");
--
2.7.4


[PATCH 4.4.y-cip 67/83] mmc: renesas-sdhi: rename tmio_mmc_dma.c => renesas_sdhi_sys_dmac.c

Biju Das <biju.das@...>
 

From: Simon Horman <horms+renesas@...>

commit c2a96987c76f093be50550130f5629723b091176 upstream.

Rename the source file for DMA for SDHI as a follow-up to attaching
DMA code to the SDHI driver rather than the tmio_core driver.

The name "renesas" is chosen as the SDHI driver is applicable to a wider
range of SoCs than SH-Mobile it seems to be a more appropriate name.
However, the SDHI driver source itself, is left as sh_mobile_sdhi to
avoid unnecessary churn.

The name sys_dmac was chosen to reflect the type of DMA used.

Internal symbols have also been renamed to reflect the filename change.

A follow-up patch will re-organise the SDHI driver removing
the need for renesas_sdhi_get_dma_ops().

Signed-off-by: Simon Horman <horms+renesas@...>
Acked-by: Arnd Bergmann <arnd@...>
Reviewed-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/Makefile | 2 +-
drivers/mmc/host/renesas_sdhi.h | 18 ++
drivers/mmc/host/renesas_sdhi_sys_dmac.c | 368 +++++++++++++++++++++++++++++++
drivers/mmc/host/sh_mobile_sdhi.c | 3 +-
drivers/mmc/host/tmio_mmc.h | 9 -
drivers/mmc/host/tmio_mmc_dma.c | 365 ------------------------------
6 files changed, 389 insertions(+), 376 deletions(-)
create mode 100644 drivers/mmc/host/renesas_sdhi.h
create mode 100644 drivers/mmc/host/renesas_sdhi_sys_dmac.c
delete mode 100644 drivers/mmc/host/tmio_mmc_dma.c

diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 2b75a43..7ab00194 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -36,7 +36,7 @@ obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
-obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o tmio_mmc_dma.o
+obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o renesas_sdhi_sys_dmac.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
new file mode 100644
index 0000000..f65d936c
--- /dev/null
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -0,0 +1,18 @@
+/*
+ * Renesas Mobile SDHI
+ *
+ * Copyright (C) 2017 Horms Solutions Ltd., Simon Horman
+ * Copyright (C) 2017 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RENESAS_SDHI_H
+#define RENESAS_SDHI_H
+
+#include "tmio_mmc.h"
+
+const struct tmio_mmc_dma_ops *renesas_sdhi_get_dma_ops(void);
+#endif
diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
new file mode 100644
index 0000000..ca96e33
--- /dev/null
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -0,0 +1,368 @@
+/*
+ * DMA function for TMIO MMC implementations
+ *
+ * Copyright (C) 2010-2011 Guennadi Liakhovetski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+
+#include "tmio_mmc.h"
+
+#define TMIO_MMC_MIN_DMA_LEN 8
+
+static void renesas_sdhi_sys_dmac_enable_dma(struct tmio_mmc_host *host,
+ bool enable)
+{
+ if (!host->chan_tx || !host->chan_rx)
+ return;
+
+ if (host->dma->enable)
+ host->dma->enable(host, enable);
+}
+
+static void renesas_sdhi_sys_dmac_abort_dma(struct tmio_mmc_host *host)
+{
+ renesas_sdhi_sys_dmac_enable_dma(host, false);
+
+ if (host->chan_rx)
+ dmaengine_terminate_all(host->chan_rx);
+ if (host->chan_tx)
+ dmaengine_terminate_all(host->chan_tx);
+
+ renesas_sdhi_sys_dmac_enable_dma(host, true);
+}
+
+static void renesas_sdhi_sys_dmac_dma_callback(void *arg)
+{
+ struct tmio_mmc_host *host = arg;
+
+ wait_for_completion(&host->dma_dataend);
+
+ spin_lock_irq(&host->lock);
+
+ if (!host->data)
+ goto out;
+
+ if (host->data->flags & MMC_DATA_READ)
+ dma_unmap_sg(host->chan_rx->device->dev,
+ host->sg_ptr, host->sg_len,
+ DMA_FROM_DEVICE);
+ else
+ dma_unmap_sg(host->chan_tx->device->dev,
+ host->sg_ptr, host->sg_len,
+ DMA_TO_DEVICE);
+
+ tmio_mmc_do_data_irq(host);
+out:
+ spin_unlock_irq(&host->lock);
+}
+
+static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)
+{
+ struct scatterlist *sg = host->sg_ptr, *sg_tmp;
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *chan = host->chan_rx;
+ dma_cookie_t cookie;
+ int ret, i;
+ bool aligned = true, multiple = true;
+ unsigned int align = (1 << host->pdata->alignment_shift) - 1;
+
+ for_each_sg(sg, sg_tmp, host->sg_len, i) {
+ if (sg_tmp->offset & align)
+ aligned = false;
+ if (sg_tmp->length & align) {
+ multiple = false;
+ break;
+ }
+ }
+
+ if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
+ (align & PAGE_MASK))) || !multiple) {
+ ret = -EINVAL;
+ goto pio;
+ }
+
+ if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
+ host->force_pio = true;
+ return;
+ }
+
+ tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY);
+
+ /* The only sg element can be unaligned, use our bounce buffer then */
+ if (!aligned) {
+ sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
+ host->sg_ptr = &host->bounce_sg;
+ sg = host->sg_ptr;
+ }
+
+ ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
+ if (ret > 0)
+ desc = dmaengine_prep_slave_sg(chan, sg, ret,
+ DMA_DEV_TO_MEM, DMA_CTRL_ACK);
+
+ if (desc) {
+ reinit_completion(&host->dma_dataend);
+ desc->callback = renesas_sdhi_sys_dmac_dma_callback;
+ desc->callback_param = host;
+
+ cookie = dmaengine_submit(desc);
+ if (cookie < 0) {
+ desc = NULL;
+ ret = cookie;
+ }
+ }
+pio:
+ if (!desc) {
+ /* DMA failed, fall back to PIO */
+ renesas_sdhi_sys_dmac_enable_dma(host, false);
+ if (ret >= 0)
+ ret = -EIO;
+ host->chan_rx = NULL;
+ dma_release_channel(chan);
+ /* Free the Tx channel too */
+ chan = host->chan_tx;
+ if (chan) {
+ host->chan_tx = NULL;
+ dma_release_channel(chan);
+ }
+ dev_warn(&host->pdev->dev,
+ "DMA failed: %d, falling back to PIO\n", ret);
+ }
+}
+
+static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
+{
+ struct scatterlist *sg = host->sg_ptr, *sg_tmp;
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *chan = host->chan_tx;
+ dma_cookie_t cookie;
+ int ret, i;
+ bool aligned = true, multiple = true;
+ unsigned int align = (1 << host->pdata->alignment_shift) - 1;
+
+ for_each_sg(sg, sg_tmp, host->sg_len, i) {
+ if (sg_tmp->offset & align)
+ aligned = false;
+ if (sg_tmp->length & align) {
+ multiple = false;
+ break;
+ }
+ }
+
+ if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
+ (align & PAGE_MASK))) || !multiple) {
+ ret = -EINVAL;
+ goto pio;
+ }
+
+ if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
+ host->force_pio = true;
+ return;
+ }
+
+ tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ);
+
+ /* The only sg element can be unaligned, use our bounce buffer then */
+ if (!aligned) {
+ unsigned long flags;
+ void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
+ sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
+ memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
+ tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
+ host->sg_ptr = &host->bounce_sg;
+ sg = host->sg_ptr;
+ }
+
+ ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
+ if (ret > 0)
+ desc = dmaengine_prep_slave_sg(chan, sg, ret,
+ DMA_MEM_TO_DEV, DMA_CTRL_ACK);
+
+ if (desc) {
+ reinit_completion(&host->dma_dataend);
+ desc->callback = renesas_sdhi_sys_dmac_dma_callback;
+ desc->callback_param = host;
+
+ cookie = dmaengine_submit(desc);
+ if (cookie < 0) {
+ desc = NULL;
+ ret = cookie;
+ }
+ }
+pio:
+ if (!desc) {
+ /* DMA failed, fall back to PIO */
+ renesas_sdhi_sys_dmac_enable_dma(host, false);
+ if (ret >= 0)
+ ret = -EIO;
+ host->chan_tx = NULL;
+ dma_release_channel(chan);
+ /* Free the Rx channel too */
+ chan = host->chan_rx;
+ if (chan) {
+ host->chan_rx = NULL;
+ dma_release_channel(chan);
+ }
+ dev_warn(&host->pdev->dev,
+ "DMA failed: %d, falling back to PIO\n", ret);
+ }
+}
+
+static void renesas_sdhi_sys_dmac_start_dma(struct tmio_mmc_host *host,
+ struct mmc_data *data)
+{
+ if (data->flags & MMC_DATA_READ) {
+ if (host->chan_rx)
+ renesas_sdhi_sys_dmac_start_dma_rx(host);
+ } else {
+ if (host->chan_tx)
+ renesas_sdhi_sys_dmac_start_dma_tx(host);
+ }
+}
+
+static void renesas_sdhi_sys_dmac_issue_tasklet_fn(unsigned long priv)
+{
+ struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv;
+ struct dma_chan *chan = NULL;
+
+ spin_lock_irq(&host->lock);
+
+ if (host && host->data) {
+ if (host->data->flags & MMC_DATA_READ)
+ chan = host->chan_rx;
+ else
+ chan = host->chan_tx;
+ }
+
+ spin_unlock_irq(&host->lock);
+
+ tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
+
+ if (chan)
+ dma_async_issue_pending(chan);
+}
+
+static void renesas_sdhi_sys_dmac_request_dma(struct tmio_mmc_host *host,
+ struct tmio_mmc_data *pdata)
+{
+ /* We can only either use DMA for both Tx and Rx or not use it at all */
+ if (!host->dma || (!host->pdev->dev.of_node &&
+ (!pdata->chan_priv_tx || !pdata->chan_priv_rx)))
+ return;
+
+ if (!host->chan_tx && !host->chan_rx) {
+ struct resource *res = platform_get_resource(host->pdev,
+ IORESOURCE_MEM, 0);
+ struct dma_slave_config cfg = {};
+ dma_cap_mask_t mask;
+ int ret;
+
+ if (!res)
+ return;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ host->chan_tx = dma_request_slave_channel_compat(mask,
+ host->dma->filter, pdata->chan_priv_tx,
+ &host->pdev->dev, "tx");
+ dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
+ host->chan_tx);
+
+ if (!host->chan_tx)
+ return;
+
+ cfg.direction = DMA_MEM_TO_DEV;
+ cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift);
+ cfg.dst_addr_width = host->dma->dma_buswidth;
+ if (!cfg.dst_addr_width)
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ cfg.src_addr = 0;
+ ret = dmaengine_slave_config(host->chan_tx, &cfg);
+ if (ret < 0)
+ goto ecfgtx;
+
+ host->chan_rx = dma_request_slave_channel_compat(mask,
+ host->dma->filter, pdata->chan_priv_rx,
+ &host->pdev->dev, "rx");
+ dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
+ host->chan_rx);
+
+ if (!host->chan_rx)
+ goto ereqrx;
+
+ cfg.direction = DMA_DEV_TO_MEM;
+ cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset;
+ cfg.src_addr_width = host->dma->dma_buswidth;
+ if (!cfg.src_addr_width)
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ cfg.dst_addr = 0;
+ ret = dmaengine_slave_config(host->chan_rx, &cfg);
+ if (ret < 0)
+ goto ecfgrx;
+
+ host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA);
+ if (!host->bounce_buf)
+ goto ebouncebuf;
+
+ init_completion(&host->dma_dataend);
+ tasklet_init(&host->dma_issue,
+ renesas_sdhi_sys_dmac_issue_tasklet_fn,
+ (unsigned long)host);
+ }
+
+ renesas_sdhi_sys_dmac_enable_dma(host, true);
+
+ return;
+
+ebouncebuf:
+ecfgrx:
+ dma_release_channel(host->chan_rx);
+ host->chan_rx = NULL;
+ereqrx:
+ecfgtx:
+ dma_release_channel(host->chan_tx);
+ host->chan_tx = NULL;
+}
+
+static void renesas_sdhi_sys_dmac_release_dma(struct tmio_mmc_host *host)
+{
+ if (host->chan_tx) {
+ struct dma_chan *chan = host->chan_tx;
+ host->chan_tx = NULL;
+ dma_release_channel(chan);
+ }
+ if (host->chan_rx) {
+ struct dma_chan *chan = host->chan_rx;
+ host->chan_rx = NULL;
+ dma_release_channel(chan);
+ }
+ if (host->bounce_buf) {
+ free_pages((unsigned long)host->bounce_buf, 0);
+ host->bounce_buf = NULL;
+ }
+}
+
+static const struct tmio_mmc_dma_ops renesas_sdhi_sys_dmac_dma_ops = {
+ .start = renesas_sdhi_sys_dmac_start_dma,
+ .enable = renesas_sdhi_sys_dmac_enable_dma,
+ .request = renesas_sdhi_sys_dmac_request_dma,
+ .release = renesas_sdhi_sys_dmac_release_dma,
+ .abort = renesas_sdhi_sys_dmac_abort_dma,
+};
+
+const struct tmio_mmc_dma_ops *renesas_sdhi_get_dma_ops(void)
+{
+ return &renesas_sdhi_sys_dmac_dma_ops;
+}
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 05edac3..8ca9860 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -35,6 +35,7 @@
#include <linux/pinctrl/pinctrl-state.h>
#include <linux/regulator/consumer.h>

+#include "renesas_sdhi.h"
#include "tmio_mmc.h"

#define EXT_ACC 0xe4
@@ -643,7 +644,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
/* All SDHI have SDIO status bits which must be 1 */
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;

- ret = tmio_mmc_host_probe(host, mmc_data, tmio_mmc_get_dma_ops());
+ ret = tmio_mmc_host_probe(host, mmc_data, renesas_sdhi_get_dma_ops());
if (ret < 0)
goto efree;

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 86aa49f3..cd5b4f3 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -212,15 +212,6 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
irqreturn_t tmio_mmc_irq(int irq, void *devid);

-#if IS_ENABLED(CONFIG_MMC_SDHI)
-const struct tmio_mmc_dma_ops *tmio_mmc_get_dma_ops(void);
-#else
-static inline const struct tmio_mmc_dma_ops *tmio_mmc_get_dma_ops(void)
-{
- return NULL;
-}
-#endif
-
static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
unsigned long *flags)
{
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c
deleted file mode 100644
index e743684..0000000
--- a/drivers/mmc/host/tmio_mmc_dma.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * DMA function for TMIO MMC implementations
- *
- * Copyright (C) 2010-2011 Guennadi Liakhovetski
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mmc/host.h>
-#include <linux/pagemap.h>
-#include <linux/scatterlist.h>
-
-#include "tmio_mmc.h"
-
-#define TMIO_MMC_MIN_DMA_LEN 8
-
-static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
-{
- if (!host->chan_tx || !host->chan_rx)
- return;
-
- if (host->dma->enable)
- host->dma->enable(host, enable);
-}
-
-static void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
-{
- tmio_mmc_enable_dma(host, false);
-
- if (host->chan_rx)
- dmaengine_terminate_all(host->chan_rx);
- if (host->chan_tx)
- dmaengine_terminate_all(host->chan_tx);
-
- tmio_mmc_enable_dma(host, true);
-}
-
-static void tmio_mmc_dma_callback(void *arg)
-{
- struct tmio_mmc_host *host = arg;
-
- wait_for_completion(&host->dma_dataend);
-
- spin_lock_irq(&host->lock);
-
- if (!host->data)
- goto out;
-
- if (host->data->flags & MMC_DATA_READ)
- dma_unmap_sg(host->chan_rx->device->dev,
- host->sg_ptr, host->sg_len,
- DMA_FROM_DEVICE);
- else
- dma_unmap_sg(host->chan_tx->device->dev,
- host->sg_ptr, host->sg_len,
- DMA_TO_DEVICE);
-
- tmio_mmc_do_data_irq(host);
-out:
- spin_unlock_irq(&host->lock);
-}
-
-static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
-{
- struct scatterlist *sg = host->sg_ptr, *sg_tmp;
- struct dma_async_tx_descriptor *desc = NULL;
- struct dma_chan *chan = host->chan_rx;
- dma_cookie_t cookie;
- int ret, i;
- bool aligned = true, multiple = true;
- unsigned int align = (1 << host->pdata->alignment_shift) - 1;
-
- for_each_sg(sg, sg_tmp, host->sg_len, i) {
- if (sg_tmp->offset & align)
- aligned = false;
- if (sg_tmp->length & align) {
- multiple = false;
- break;
- }
- }
-
- if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
- (align & PAGE_MASK))) || !multiple) {
- ret = -EINVAL;
- goto pio;
- }
-
- if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
- host->force_pio = true;
- return;
- }
-
- tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY);
-
- /* The only sg element can be unaligned, use our bounce buffer then */
- if (!aligned) {
- sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
- host->sg_ptr = &host->bounce_sg;
- sg = host->sg_ptr;
- }
-
- ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
- if (ret > 0)
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_DEV_TO_MEM, DMA_CTRL_ACK);
-
- if (desc) {
- reinit_completion(&host->dma_dataend);
- desc->callback = tmio_mmc_dma_callback;
- desc->callback_param = host;
-
- cookie = dmaengine_submit(desc);
- if (cookie < 0) {
- desc = NULL;
- ret = cookie;
- }
- }
-pio:
- if (!desc) {
- /* DMA failed, fall back to PIO */
- tmio_mmc_enable_dma(host, false);
- if (ret >= 0)
- ret = -EIO;
- host->chan_rx = NULL;
- dma_release_channel(chan);
- /* Free the Tx channel too */
- chan = host->chan_tx;
- if (chan) {
- host->chan_tx = NULL;
- dma_release_channel(chan);
- }
- dev_warn(&host->pdev->dev,
- "DMA failed: %d, falling back to PIO\n", ret);
- }
-}
-
-static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
-{
- struct scatterlist *sg = host->sg_ptr, *sg_tmp;
- struct dma_async_tx_descriptor *desc = NULL;
- struct dma_chan *chan = host->chan_tx;
- dma_cookie_t cookie;
- int ret, i;
- bool aligned = true, multiple = true;
- unsigned int align = (1 << host->pdata->alignment_shift) - 1;
-
- for_each_sg(sg, sg_tmp, host->sg_len, i) {
- if (sg_tmp->offset & align)
- aligned = false;
- if (sg_tmp->length & align) {
- multiple = false;
- break;
- }
- }
-
- if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
- (align & PAGE_MASK))) || !multiple) {
- ret = -EINVAL;
- goto pio;
- }
-
- if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
- host->force_pio = true;
- return;
- }
-
- tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ);
-
- /* The only sg element can be unaligned, use our bounce buffer then */
- if (!aligned) {
- unsigned long flags;
- void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
- sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
- memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
- tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
- host->sg_ptr = &host->bounce_sg;
- sg = host->sg_ptr;
- }
-
- ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
- if (ret > 0)
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_MEM_TO_DEV, DMA_CTRL_ACK);
-
- if (desc) {
- reinit_completion(&host->dma_dataend);
- desc->callback = tmio_mmc_dma_callback;
- desc->callback_param = host;
-
- cookie = dmaengine_submit(desc);
- if (cookie < 0) {
- desc = NULL;
- ret = cookie;
- }
- }
-pio:
- if (!desc) {
- /* DMA failed, fall back to PIO */
- tmio_mmc_enable_dma(host, false);
- if (ret >= 0)
- ret = -EIO;
- host->chan_tx = NULL;
- dma_release_channel(chan);
- /* Free the Rx channel too */
- chan = host->chan_rx;
- if (chan) {
- host->chan_rx = NULL;
- dma_release_channel(chan);
- }
- dev_warn(&host->pdev->dev,
- "DMA failed: %d, falling back to PIO\n", ret);
- }
-}
-
-static void tmio_mmc_start_dma(struct tmio_mmc_host *host,
- struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_READ) {
- if (host->chan_rx)
- tmio_mmc_start_dma_rx(host);
- } else {
- if (host->chan_tx)
- tmio_mmc_start_dma_tx(host);
- }
-}
-
-static void tmio_mmc_issue_tasklet_fn(unsigned long priv)
-{
- struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv;
- struct dma_chan *chan = NULL;
-
- spin_lock_irq(&host->lock);
-
- if (host && host->data) {
- if (host->data->flags & MMC_DATA_READ)
- chan = host->chan_rx;
- else
- chan = host->chan_tx;
- }
-
- spin_unlock_irq(&host->lock);
-
- tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
-
- if (chan)
- dma_async_issue_pending(chan);
-}
-
-static void tmio_mmc_request_dma(struct tmio_mmc_host *host,
- struct tmio_mmc_data *pdata)
-{
- /* We can only either use DMA for both Tx and Rx or not use it at all */
- if (!host->dma || (!host->pdev->dev.of_node &&
- (!pdata->chan_priv_tx || !pdata->chan_priv_rx)))
- return;
-
- if (!host->chan_tx && !host->chan_rx) {
- struct resource *res = platform_get_resource(host->pdev,
- IORESOURCE_MEM, 0);
- struct dma_slave_config cfg = {};
- dma_cap_mask_t mask;
- int ret;
-
- if (!res)
- return;
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- host->chan_tx = dma_request_slave_channel_compat(mask,
- host->dma->filter, pdata->chan_priv_tx,
- &host->pdev->dev, "tx");
- dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
- host->chan_tx);
-
- if (!host->chan_tx)
- return;
-
- cfg.direction = DMA_MEM_TO_DEV;
- cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift);
- cfg.dst_addr_width = host->dma->dma_buswidth;
- if (!cfg.dst_addr_width)
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
- cfg.src_addr = 0;
- ret = dmaengine_slave_config(host->chan_tx, &cfg);
- if (ret < 0)
- goto ecfgtx;
-
- host->chan_rx = dma_request_slave_channel_compat(mask,
- host->dma->filter, pdata->chan_priv_rx,
- &host->pdev->dev, "rx");
- dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
- host->chan_rx);
-
- if (!host->chan_rx)
- goto ereqrx;
-
- cfg.direction = DMA_DEV_TO_MEM;
- cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset;
- cfg.src_addr_width = host->dma->dma_buswidth;
- if (!cfg.src_addr_width)
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
- cfg.dst_addr = 0;
- ret = dmaengine_slave_config(host->chan_rx, &cfg);
- if (ret < 0)
- goto ecfgrx;
-
- host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA);
- if (!host->bounce_buf)
- goto ebouncebuf;
-
- init_completion(&host->dma_dataend);
- tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
- }
-
- tmio_mmc_enable_dma(host, true);
-
- return;
-
-ebouncebuf:
-ecfgrx:
- dma_release_channel(host->chan_rx);
- host->chan_rx = NULL;
-ereqrx:
-ecfgtx:
- dma_release_channel(host->chan_tx);
- host->chan_tx = NULL;
-}
-
-static void tmio_mmc_release_dma(struct tmio_mmc_host *host)
-{
- if (host->chan_tx) {
- struct dma_chan *chan = host->chan_tx;
- host->chan_tx = NULL;
- dma_release_channel(chan);
- }
- if (host->chan_rx) {
- struct dma_chan *chan = host->chan_rx;
- host->chan_rx = NULL;
- dma_release_channel(chan);
- }
- if (host->bounce_buf) {
- free_pages((unsigned long)host->bounce_buf, 0);
- host->bounce_buf = NULL;
- }
-}
-
-static const struct tmio_mmc_dma_ops tmio_mmc_dma_ops = {
- .start = tmio_mmc_start_dma,
- .enable = tmio_mmc_enable_dma,
- .request = tmio_mmc_request_dma,
- .release = tmio_mmc_release_dma,
- .abort = tmio_mmc_abort_dma,
-};
-
-const struct tmio_mmc_dma_ops *tmio_mmc_get_dma_ops(void)
-{
- return &tmio_mmc_dma_ops;
-}
--
2.7.4

5981 - 6000 of 9650