aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcin Wojtas <mw@semihalf.com>2014-02-18 10:08:29 -0500
committerChris Ball <chris@printf.net>2014-03-29 12:18:19 -0400
commit5491ce3f79eed79f68fcc2dc4c10aeafe00215a6 (patch)
tree3c9f01acbd45734d0b5955b19cf7e554099cc06d
parent415b5a75da4309fe56c9b37e246faad80a97e525 (diff)
mmc: sdhci-pxav3: add support for the Armada 38x SDHCI controller
The SDHCI unit used on the Armada 380 and 385 Marvell SoC is similar to the PXAv3 unit. The only difference is that on Armada 38x, the PXAv3 unit accesses memory through MBus windows which must be configured prior to using the device. Without this, DMA would not work. In order to achieve this, the sdhci-pxav3 driver is extended with an additional compatible string "marvell,armada-380-sdhci". When this compatible string is used, the MBus windows are initialized in a way that is identical to what all other DMA-capable drivers for Marvell EBU platforms do. Signed-off-by: Marcin Wojtas <mw@semihalf.com> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Signed-off-by: Chris Ball <chris@printf.net>
-rw-r--r--Documentation/devicetree/bindings/mmc/sdhci-pxa.txt17
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c68
2 files changed, 84 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
index dbe98a3c183a..86223c3eda90 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
@@ -4,7 +4,14 @@ This file documents differences between the core properties in mmc.txt
4and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers. 4and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
5 5
6Required properties: 6Required properties:
7- compatible: Should be "mrvl,pxav2-mmc" or "mrvl,pxav3-mmc". 7- compatible: Should be "mrvl,pxav2-mmc", "mrvl,pxav3-mmc" or
8 "marvell,armada-380-sdhci".
9- reg:
10 * for "mrvl,pxav2-mmc" and "mrvl,pxav3-mmc", one register area for
11 the SDHCI registers.
12 * for "marvell,armada-380-sdhci", two register areas. The first one
13 for the SDHCI registers themselves, and the second one for the
14 AXI/Mbus bridge registers of the SDHCI unit.
8 15
9Optional properties: 16Optional properties:
10- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning. 17- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
@@ -19,3 +26,11 @@ sdhci@d4280800 {
19 non-removable; 26 non-removable;
20 mrvl,clk-delay-cycles = <31>; 27 mrvl,clk-delay-cycles = <31>;
21}; 28};
29
30sdhci@d8000 {
31 compatible = "marvell,armada-380-sdhci";
32 reg = <0xd8000 0x1000>, <0xdc000 0x100>;
33 interrupts = <0 25 0x4>;
34 clocks = <&gateclk 17>;
35 mrvl,clk-delay-cycles = <0x1F>;
36};
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index 793dacd3b841..2fd73b38c303 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -34,6 +34,7 @@
34#include <linux/of_gpio.h> 34#include <linux/of_gpio.h>
35#include <linux/pm.h> 35#include <linux/pm.h>
36#include <linux/pm_runtime.h> 36#include <linux/pm_runtime.h>
37#include <linux/mbus.h>
37 38
38#include "sdhci.h" 39#include "sdhci.h"
39#include "sdhci-pltfm.h" 40#include "sdhci-pltfm.h"
@@ -57,6 +58,60 @@
57#define SDCE_MISC_INT (1<<2) 58#define SDCE_MISC_INT (1<<2)
58#define SDCE_MISC_INT_EN (1<<1) 59#define SDCE_MISC_INT_EN (1<<1)
59 60
61/*
62 * These registers are relative to the second register region, for the
63 * MBus bridge.
64 */
65#define SDHCI_WINDOW_CTRL(i) (0x80 + ((i) << 3))
66#define SDHCI_WINDOW_BASE(i) (0x84 + ((i) << 3))
67#define SDHCI_MAX_WIN_NUM 8
68
69static int mv_conf_mbus_windows(struct platform_device *pdev,
70 const struct mbus_dram_target_info *dram)
71{
72 int i;
73 void __iomem *regs;
74 struct resource *res;
75
76 if (!dram) {
77 dev_err(&pdev->dev, "no mbus dram info\n");
78 return -EINVAL;
79 }
80
81 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
82 if (!res) {
83 dev_err(&pdev->dev, "cannot get mbus registers\n");
84 return -EINVAL;
85 }
86
87 regs = ioremap(res->start, resource_size(res));
88 if (!regs) {
89 dev_err(&pdev->dev, "cannot map mbus registers\n");
90 return -ENOMEM;
91 }
92
93 for (i = 0; i < SDHCI_MAX_WIN_NUM; i++) {
94 writel(0, regs + SDHCI_WINDOW_CTRL(i));
95 writel(0, regs + SDHCI_WINDOW_BASE(i));
96 }
97
98 for (i = 0; i < dram->num_cs; i++) {
99 const struct mbus_dram_window *cs = dram->cs + i;
100
101 /* Write size, attributes and target id to control register */
102 writel(((cs->size - 1) & 0xffff0000) |
103 (cs->mbus_attr << 8) |
104 (dram->mbus_dram_target_id << 4) | 1,
105 regs + SDHCI_WINDOW_CTRL(i));
106 /* Write base address to base register */
107 writel(cs->base, regs + SDHCI_WINDOW_BASE(i));
108 }
109
110 iounmap(regs);
111
112 return 0;
113}
114
60static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask) 115static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask)
61{ 116{
62 struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); 117 struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
@@ -187,6 +242,9 @@ static const struct of_device_id sdhci_pxav3_of_match[] = {
187 { 242 {
188 .compatible = "mrvl,pxav3-mmc", 243 .compatible = "mrvl,pxav3-mmc",
189 }, 244 },
245 {
246 .compatible = "marvell,armada-380-sdhci",
247 },
190 {}, 248 {},
191}; 249};
192MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match); 250MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
@@ -219,6 +277,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
219 struct sdhci_pltfm_host *pltfm_host; 277 struct sdhci_pltfm_host *pltfm_host;
220 struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; 278 struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
221 struct device *dev = &pdev->dev; 279 struct device *dev = &pdev->dev;
280 struct device_node *np = pdev->dev.of_node;
222 struct sdhci_host *host = NULL; 281 struct sdhci_host *host = NULL;
223 struct sdhci_pxa *pxa = NULL; 282 struct sdhci_pxa *pxa = NULL;
224 const struct of_device_id *match; 283 const struct of_device_id *match;
@@ -235,6 +294,14 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
235 kfree(pxa); 294 kfree(pxa);
236 return PTR_ERR(host); 295 return PTR_ERR(host);
237 } 296 }
297
298 if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) {
299 ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info());
300 if (ret < 0)
301 goto err_mbus_win;
302 }
303
304
238 pltfm_host = sdhci_priv(host); 305 pltfm_host = sdhci_priv(host);
239 pltfm_host->priv = pxa; 306 pltfm_host->priv = pxa;
240 307
@@ -321,6 +388,7 @@ err_add_host:
321 clk_disable_unprepare(clk); 388 clk_disable_unprepare(clk);
322 clk_put(clk); 389 clk_put(clk);
323err_clk_get: 390err_clk_get:
391err_mbus_win:
324 sdhci_pltfm_free(pdev); 392 sdhci_pltfm_free(pdev);
325 kfree(pxa); 393 kfree(pxa);
326 return ret; 394 return ret;