aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuneel Garapati <suneel.garapati@xilinx.com>2015-06-09 04:53:50 -0400
committerTejun Heo <tj@kernel.org>2015-06-09 22:15:17 -0400
commita73ed35052ca85ff627cf9646760b2a7d69ec5c8 (patch)
tree1c1934e4090f29e3e54a2cafba28295caf195ddb
parent03a740fb682c5ae9bf49ebad284986e9afc63958 (diff)
drivers: ata: add support for Ceva sata host controller
Adds support for Ceva sata host controller on Xilinx Zynq UltraScale+ MPSoC. Signed-off-by: Suneel Garapati <suneel.garapati@xilinx.com> Acked-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--drivers/ata/Kconfig9
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci_ceva.c238
3 files changed, 248 insertions, 0 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index e881503fd4c6..a987d6f86f6e 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -133,6 +133,15 @@ config AHCI_IMX
133 133
134 If unsure, say N. 134 If unsure, say N.
135 135
136config AHCI_CEVA
137 tristate "CEVA AHCI SATA support"
138 depends on OF
139 help
140 This option enables support for the CEVA AHCI SATA.
141 It can be found on the Xilinx Zynq UltraScale+ MPSoC.
142
143 If unsure, say N.
144
136config AHCI_MVEBU 145config AHCI_MVEBU
137 tristate "Marvell EBU AHCI SATA support" 146 tristate "Marvell EBU AHCI SATA support"
138 depends on ARCH_MVEBU 147 depends on ARCH_MVEBU
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 5154753ade63..af70919f7dde 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
11obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o 11obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
12obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o 12obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
13obj-$(CONFIG_AHCI_BRCMSTB) += ahci_brcmstb.o libahci.o libahci_platform.o 13obj-$(CONFIG_AHCI_BRCMSTB) += ahci_brcmstb.o libahci.o libahci_platform.o
14obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o
14obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o 15obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o
15obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o 16obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
16obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o 17obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o
diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c
new file mode 100644
index 000000000000..207649d323c5
--- /dev/null
+++ b/drivers/ata/ahci_ceva.c
@@ -0,0 +1,238 @@
1/*
2 * Copyright (C) 2015 Xilinx, Inc.
3 * CEVA AHCI SATA platform driver
4 *
5 * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/ahci_platform.h>
21#include <linux/kernel.h>
22#include <linux/libata.h>
23#include <linux/module.h>
24#include <linux/of_device.h>
25#include <linux/platform_device.h>
26#include "ahci.h"
27
28/* Vendor Specific Register Offsets */
29#define AHCI_VEND_PCFG 0xA4
30#define AHCI_VEND_PPCFG 0xA8
31#define AHCI_VEND_PP2C 0xAC
32#define AHCI_VEND_PP3C 0xB0
33#define AHCI_VEND_PP4C 0xB4
34#define AHCI_VEND_PP5C 0xB8
35#define AHCI_VEND_PAXIC 0xC0
36#define AHCI_VEND_PTC 0xC8
37
38/* Vendor Specific Register bit definitions */
39#define PAXIC_ADBW_BW64 0x1
40#define PAXIC_MAWIDD (1 << 8)
41#define PAXIC_MARIDD (1 << 16)
42#define PAXIC_OTL (0x4 << 20)
43
44#define PCFG_TPSS_VAL (0x32 << 16)
45#define PCFG_TPRS_VAL (0x2 << 12)
46#define PCFG_PAD_VAL 0x2
47
48#define PPCFG_TTA 0x1FFFE
49#define PPCFG_PSSO_EN (1 << 28)
50#define PPCFG_PSS_EN (1 << 29)
51#define PPCFG_ESDF_EN (1 << 31)
52
53#define PP2C_CIBGMN 0x0F
54#define PP2C_CIBGMX (0x25 << 8)
55#define PP2C_CIBGN (0x18 << 16)
56#define PP2C_CINMP (0x29 << 24)
57
58#define PP3C_CWBGMN 0x04
59#define PP3C_CWBGMX (0x0B << 8)
60#define PP3C_CWBGN (0x08 << 16)
61#define PP3C_CWNMP (0x0F << 24)
62
63#define PP4C_BMX 0x0a
64#define PP4C_BNM (0x08 << 8)
65#define PP4C_SFD (0x4a << 16)
66#define PP4C_PTST (0x06 << 24)
67
68#define PP5C_RIT 0x60216
69#define PP5C_RCT (0x7f0 << 20)
70
71#define PTC_RX_WM_VAL 0x40
72#define PTC_RSVD (1 << 27)
73
74#define PORT0_BASE 0x100
75#define PORT1_BASE 0x180
76
77/* Port Control Register Bit Definitions */
78#define PORT_SCTL_SPD_GEN2 (0x2 << 4)
79#define PORT_SCTL_SPD_GEN1 (0x1 << 4)
80#define PORT_SCTL_IPM (0x3 << 8)
81
82#define PORT_BASE 0x100
83#define PORT_OFFSET 0x80
84#define NR_PORTS 2
85#define DRV_NAME "ahci-ceva"
86#define CEVA_FLAG_BROKEN_GEN2 1
87
88struct ceva_ahci_priv {
89 struct platform_device *ahci_pdev;
90 int flags;
91};
92
93static struct ata_port_operations ahci_ceva_ops = {
94 .inherits = &ahci_platform_ops,
95};
96
97static const struct ata_port_info ahci_ceva_port_info = {
98 .flags = AHCI_FLAG_COMMON,
99 .pio_mask = ATA_PIO4,
100 .udma_mask = ATA_UDMA6,
101 .port_ops = &ahci_ceva_ops,
102};
103
104static void ahci_ceva_setup(struct ahci_host_priv *hpriv)
105{
106 void __iomem *mmio = hpriv->mmio;
107 struct ceva_ahci_priv *cevapriv = hpriv->plat_data;
108 u32 tmp;
109 int i;
110
111 /*
112 * AXI Data bus width to 64
113 * Set Mem Addr Read, Write ID for data transfers
114 * Transfer limit to 72 DWord
115 */
116 tmp = PAXIC_ADBW_BW64 | PAXIC_MAWIDD | PAXIC_MARIDD | PAXIC_OTL;
117 writel(tmp, mmio + AHCI_VEND_PAXIC);
118
119 /* Set AHCI Enable */
120 tmp = readl(mmio + HOST_CTL);
121 tmp |= HOST_AHCI_EN;
122 writel(tmp, mmio + HOST_CTL);
123
124 for (i = 0; i < NR_PORTS; i++) {
125 /* TPSS TPRS scalars, CISE and Port Addr */
126 tmp = PCFG_TPSS_VAL | PCFG_TPRS_VAL | (PCFG_PAD_VAL + i);
127 writel(tmp, mmio + AHCI_VEND_PCFG);
128
129 /* Port Phy Cfg register enables */
130 tmp = PPCFG_TTA | PPCFG_PSS_EN | PPCFG_ESDF_EN;
131 writel(tmp, mmio + AHCI_VEND_PPCFG);
132
133 /* Phy Control OOB timing parameters COMINIT */
134 tmp = PP2C_CIBGMN | PP2C_CIBGMX | PP2C_CIBGN | PP2C_CINMP;
135 writel(tmp, mmio + AHCI_VEND_PP2C);
136
137 /* Phy Control OOB timing parameters COMWAKE */
138 tmp = PP3C_CWBGMN | PP3C_CWBGMX | PP3C_CWBGN | PP3C_CWNMP;
139 writel(tmp, mmio + AHCI_VEND_PP3C);
140
141 /* Phy Control Burst timing setting */
142 tmp = PP4C_BMX | PP4C_BNM | PP4C_SFD | PP4C_PTST;
143 writel(tmp, mmio + AHCI_VEND_PP4C);
144
145 /* Rate Change Timer and Retry Interval Timer setting */
146 tmp = PP5C_RIT | PP5C_RCT;
147 writel(tmp, mmio + AHCI_VEND_PP5C);
148
149 /* Rx Watermark setting */
150 tmp = PTC_RX_WM_VAL | PTC_RSVD;
151 writel(tmp, mmio + AHCI_VEND_PTC);
152
153 /* Default to Gen 2 Speed and Gen 1 if Gen2 is broken */
154 tmp = PORT_SCTL_SPD_GEN2 | PORT_SCTL_IPM;
155 if (cevapriv->flags & CEVA_FLAG_BROKEN_GEN2)
156 tmp = PORT_SCTL_SPD_GEN1 | PORT_SCTL_IPM;
157 writel(tmp, mmio + PORT_SCR_CTL + PORT_BASE + PORT_OFFSET * i);
158 }
159}
160
161static struct scsi_host_template ahci_platform_sht = {
162 AHCI_SHT(DRV_NAME),
163};
164
165static int ceva_ahci_probe(struct platform_device *pdev)
166{
167 struct device_node *np = pdev->dev.of_node;
168 struct device *dev = &pdev->dev;
169 struct ahci_host_priv *hpriv;
170 struct ceva_ahci_priv *cevapriv;
171 int rc;
172
173 cevapriv = devm_kzalloc(dev, sizeof(*cevapriv), GFP_KERNEL);
174 if (!cevapriv)
175 return -ENOMEM;
176
177 cevapriv->ahci_pdev = pdev;
178
179 hpriv = ahci_platform_get_resources(pdev);
180 if (IS_ERR(hpriv))
181 return PTR_ERR(hpriv);
182
183 rc = ahci_platform_enable_resources(hpriv);
184 if (rc)
185 return rc;
186
187 if (of_property_read_bool(np, "ceva,broken-gen2"))
188 cevapriv->flags = CEVA_FLAG_BROKEN_GEN2;
189
190 hpriv->plat_data = cevapriv;
191
192 /* CEVA specific initialization */
193 ahci_ceva_setup(hpriv);
194
195 rc = ahci_platform_init_host(pdev, hpriv, &ahci_ceva_port_info,
196 &ahci_platform_sht);
197 if (rc)
198 goto disable_resources;
199
200 return 0;
201
202disable_resources:
203 ahci_platform_disable_resources(hpriv);
204 return rc;
205}
206
207static int __maybe_unused ceva_ahci_suspend(struct device *dev)
208{
209 return ahci_platform_suspend_host(dev);
210}
211
212static int __maybe_unused ceva_ahci_resume(struct device *dev)
213{
214 return ahci_platform_resume_host(dev);
215}
216
217static SIMPLE_DEV_PM_OPS(ahci_ceva_pm_ops, ceva_ahci_suspend, ceva_ahci_resume);
218
219static const struct of_device_id ceva_ahci_of_match[] = {
220 { .compatible = "ceva,ahci-1v84" },
221 {},
222};
223MODULE_DEVICE_TABLE(of, ceva_ahci_of_match);
224
225static struct platform_driver ceva_ahci_driver = {
226 .probe = ceva_ahci_probe,
227 .remove = ata_platform_remove_one,
228 .driver = {
229 .name = DRV_NAME,
230 .of_match_table = ceva_ahci_of_match,
231 .pm = &ahci_ceva_pm_ops,
232 },
233};
234module_platform_driver(ceva_ahci_driver);
235
236MODULE_DESCRIPTION("CEVA AHCI SATA platform driver");
237MODULE_AUTHOR("Xilinx Inc.");
238MODULE_LICENSE("GPL v2");