Commit | Line | Data |
---|---|---|
a73ed350 SG |
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 | ||
88 | struct ceva_ahci_priv { | |
89 | struct platform_device *ahci_pdev; | |
90 | int flags; | |
91 | }; | |
92 | ||
93 | static struct ata_port_operations ahci_ceva_ops = { | |
94 | .inherits = &ahci_platform_ops, | |
95 | }; | |
96 | ||
97 | static 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 | ||
104 | static 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 | ||
161 | static struct scsi_host_template ahci_platform_sht = { | |
162 | AHCI_SHT(DRV_NAME), | |
163 | }; | |
164 | ||
165 | static 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 | ||
202 | disable_resources: | |
203 | ahci_platform_disable_resources(hpriv); | |
204 | return rc; | |
205 | } | |
206 | ||
207 | static int __maybe_unused ceva_ahci_suspend(struct device *dev) | |
208 | { | |
209 | return ahci_platform_suspend_host(dev); | |
210 | } | |
211 | ||
212 | static int __maybe_unused ceva_ahci_resume(struct device *dev) | |
213 | { | |
214 | return ahci_platform_resume_host(dev); | |
215 | } | |
216 | ||
217 | static SIMPLE_DEV_PM_OPS(ahci_ceva_pm_ops, ceva_ahci_suspend, ceva_ahci_resume); | |
218 | ||
219 | static const struct of_device_id ceva_ahci_of_match[] = { | |
220 | { .compatible = "ceva,ahci-1v84" }, | |
221 | {}, | |
222 | }; | |
223 | MODULE_DEVICE_TABLE(of, ceva_ahci_of_match); | |
224 | ||
225 | static 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 | }; | |
234 | module_platform_driver(ceva_ahci_driver); | |
235 | ||
236 | MODULE_DESCRIPTION("CEVA AHCI SATA platform driver"); | |
237 | MODULE_AUTHOR("Xilinx Inc."); | |
238 | MODULE_LICENSE("GPL v2"); |