This source file includes following definitions.
- sunxi_clrbits
- sunxi_setbits
- sunxi_clrsetbits
- sunxi_getbits
- ahci_sunxi_phy_init
- ahci_sunxi_start_engine
- ahci_sunxi_probe
- ahci_sunxi_resume
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/ahci_platform.h>
13 #include <linux/clk.h>
14 #include <linux/errno.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/of_device.h>
18 #include <linux/platform_device.h>
19 #include <linux/regulator/consumer.h>
20 #include "ahci.h"
21
22 #define DRV_NAME "ahci-sunxi"
23
24
25 static bool enable_pmp;
26 module_param(enable_pmp, bool, 0);
27 MODULE_PARM_DESC(enable_pmp,
28 "Enable support for sata port multipliers, only use if you use a pmp!");
29
30 #define AHCI_BISTAFR 0x00a0
31 #define AHCI_BISTCR 0x00a4
32 #define AHCI_BISTFCTR 0x00a8
33 #define AHCI_BISTSR 0x00ac
34 #define AHCI_BISTDECR 0x00b0
35 #define AHCI_DIAGNR0 0x00b4
36 #define AHCI_DIAGNR1 0x00b8
37 #define AHCI_OOBR 0x00bc
38 #define AHCI_PHYCS0R 0x00c0
39 #define AHCI_PHYCS1R 0x00c4
40 #define AHCI_PHYCS2R 0x00c8
41 #define AHCI_TIMER1MS 0x00e0
42 #define AHCI_GPARAM1R 0x00e8
43 #define AHCI_GPARAM2R 0x00ec
44 #define AHCI_PPARAMR 0x00f0
45 #define AHCI_TESTR 0x00f4
46 #define AHCI_VERSIONR 0x00f8
47 #define AHCI_IDR 0x00fc
48 #define AHCI_RWCR 0x00fc
49 #define AHCI_P0DMACR 0x0170
50 #define AHCI_P0PHYCR 0x0178
51 #define AHCI_P0PHYSR 0x017c
52
53 static void sunxi_clrbits(void __iomem *reg, u32 clr_val)
54 {
55 u32 reg_val;
56
57 reg_val = readl(reg);
58 reg_val &= ~(clr_val);
59 writel(reg_val, reg);
60 }
61
62 static void sunxi_setbits(void __iomem *reg, u32 set_val)
63 {
64 u32 reg_val;
65
66 reg_val = readl(reg);
67 reg_val |= set_val;
68 writel(reg_val, reg);
69 }
70
71 static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val)
72 {
73 u32 reg_val;
74
75 reg_val = readl(reg);
76 reg_val &= ~(clr_val);
77 reg_val |= set_val;
78 writel(reg_val, reg);
79 }
80
81 static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift)
82 {
83 return (readl(reg) >> shift) & mask;
84 }
85
86 static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
87 {
88 u32 reg_val;
89 int timeout;
90
91
92 writel(0, reg_base + AHCI_RWCR);
93 msleep(5);
94
95 sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
96 sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
97 (0x7 << 24),
98 (0x5 << 24) | BIT(23) | BIT(18));
99 sunxi_clrsetbits(reg_base + AHCI_PHYCS1R,
100 (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
101 (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
102 sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15));
103 sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19));
104 sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
105 (0x7 << 20), (0x3 << 20));
106 sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
107 (0x1f << 5), (0x19 << 5));
108 msleep(5);
109
110 sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
111
112 timeout = 250;
113 do {
114 reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
115 if (reg_val == 0x02)
116 break;
117
118 if (--timeout == 0) {
119 dev_err(dev, "PHY power up failed.\n");
120 return -EIO;
121 }
122 udelay(1);
123 } while (1);
124
125 sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24));
126
127 timeout = 100;
128 do {
129 reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
130 if (reg_val == 0x00)
131 break;
132
133 if (--timeout == 0) {
134 dev_err(dev, "PHY calibration failed.\n");
135 return -EIO;
136 }
137 udelay(1);
138 } while (1);
139
140 msleep(15);
141
142 writel(0x7, reg_base + AHCI_RWCR);
143
144 return 0;
145 }
146
147 static void ahci_sunxi_start_engine(struct ata_port *ap)
148 {
149 void __iomem *port_mmio = ahci_port_base(ap);
150 struct ahci_host_priv *hpriv = ap->host->private_data;
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196 sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ffff, 0x00004433);
197
198
199 sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
200 }
201
202 static const struct ata_port_info ahci_sunxi_port_info = {
203 .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
204 .pio_mask = ATA_PIO4,
205 .udma_mask = ATA_UDMA6,
206 .port_ops = &ahci_platform_ops,
207 };
208
209 static struct scsi_host_template ahci_platform_sht = {
210 AHCI_SHT(DRV_NAME),
211 };
212
213 static int ahci_sunxi_probe(struct platform_device *pdev)
214 {
215 struct device *dev = &pdev->dev;
216 struct ahci_host_priv *hpriv;
217 int rc;
218
219 hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS);
220 if (IS_ERR(hpriv))
221 return PTR_ERR(hpriv);
222
223 hpriv->start_engine = ahci_sunxi_start_engine;
224
225 rc = ahci_platform_enable_resources(hpriv);
226 if (rc)
227 return rc;
228
229 rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
230 if (rc)
231 goto disable_resources;
232
233 hpriv->flags = AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
234 AHCI_HFLAG_YES_NCQ;
235
236
237
238
239
240
241 if (!enable_pmp)
242 hpriv->flags |= AHCI_HFLAG_NO_PMP;
243
244 rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info,
245 &ahci_platform_sht);
246 if (rc)
247 goto disable_resources;
248
249 return 0;
250
251 disable_resources:
252 ahci_platform_disable_resources(hpriv);
253 return rc;
254 }
255
256 #ifdef CONFIG_PM_SLEEP
257 static int ahci_sunxi_resume(struct device *dev)
258 {
259 struct ata_host *host = dev_get_drvdata(dev);
260 struct ahci_host_priv *hpriv = host->private_data;
261 int rc;
262
263 rc = ahci_platform_enable_resources(hpriv);
264 if (rc)
265 return rc;
266
267 rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
268 if (rc)
269 goto disable_resources;
270
271 rc = ahci_platform_resume_host(dev);
272 if (rc)
273 goto disable_resources;
274
275 return 0;
276
277 disable_resources:
278 ahci_platform_disable_resources(hpriv);
279 return rc;
280 }
281 #endif
282
283 static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
284 ahci_sunxi_resume);
285
286 static const struct of_device_id ahci_sunxi_of_match[] = {
287 { .compatible = "allwinner,sun4i-a10-ahci", },
288 { .compatible = "allwinner,sun8i-r40-ahci", },
289 { },
290 };
291 MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
292
293 static struct platform_driver ahci_sunxi_driver = {
294 .probe = ahci_sunxi_probe,
295 .remove = ata_platform_remove_one,
296 .driver = {
297 .name = DRV_NAME,
298 .of_match_table = ahci_sunxi_of_match,
299 .pm = &ahci_sunxi_pm_ops,
300 },
301 };
302 module_platform_driver(ahci_sunxi_driver);
303
304 MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver");
305 MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>");
306 MODULE_LICENSE("GPL");