1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Broadcom SATA3 AHCI Controller Driver |
4 | * |
5 | * Copyright © 2009-2015 Broadcom Corporation |
6 | */ |
7 | |
8 | #include <linux/ahci_platform.h> |
9 | #include <linux/compiler.h> |
10 | #include <linux/device.h> |
11 | #include <linux/init.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/io.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/libata.h> |
16 | #include <linux/module.h> |
17 | #include <linux/of.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/reset.h> |
20 | #include <linux/string.h> |
21 | |
22 | #include "ahci.h" |
23 | |
24 | #define DRV_NAME "brcm-ahci" |
25 | |
26 | #define SATA_TOP_CTRL_VERSION 0x0 |
27 | #define SATA_TOP_CTRL_BUS_CTRL 0x4 |
28 | #define MMIO_ENDIAN_SHIFT 0 /* CPU->AHCI */ |
29 | #define DMADESC_ENDIAN_SHIFT 2 /* AHCI->DDR */ |
30 | #define DMADATA_ENDIAN_SHIFT 4 /* AHCI->DDR */ |
31 | #define PIODATA_ENDIAN_SHIFT 6 |
32 | #define ENDIAN_SWAP_NONE 0 |
33 | #define ENDIAN_SWAP_FULL 2 |
34 | #define SATA_TOP_CTRL_TP_CTRL 0x8 |
35 | #define SATA_TOP_CTRL_PHY_CTRL 0xc |
36 | #define SATA_TOP_CTRL_PHY_CTRL_1 0x0 |
37 | #define SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE BIT(14) |
38 | #define SATA_TOP_CTRL_PHY_CTRL_2 0x4 |
39 | #define SATA_TOP_CTRL_2_SW_RST_MDIOREG BIT(0) |
40 | #define SATA_TOP_CTRL_2_SW_RST_OOB BIT(1) |
41 | #define SATA_TOP_CTRL_2_SW_RST_RX BIT(2) |
42 | #define SATA_TOP_CTRL_2_SW_RST_TX BIT(3) |
43 | #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14) |
44 | #define SATA_TOP_CTRL_PHY_OFFS 0x8 |
45 | #define SATA_TOP_MAX_PHYS 2 |
46 | |
47 | #define SATA_FIRST_PORT_CTRL 0x700 |
48 | #define SATA_NEXT_PORT_CTRL_OFFSET 0x80 |
49 | #define SATA_PORT_PCTRL6(reg_base) (reg_base + 0x18) |
50 | |
51 | /* On big-endian MIPS, buses are reversed to big endian, so switch them back */ |
52 | #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN) |
53 | #define DATA_ENDIAN 2 /* AHCI->DDR inbound accesses */ |
54 | #define MMIO_ENDIAN 2 /* CPU->AHCI outbound accesses */ |
55 | #else |
56 | #define DATA_ENDIAN 0 |
57 | #define MMIO_ENDIAN 0 |
58 | #endif |
59 | |
60 | #define BUS_CTRL_ENDIAN_CONF \ |
61 | ((DATA_ENDIAN << DMADATA_ENDIAN_SHIFT) | \ |
62 | (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \ |
63 | (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT)) |
64 | |
65 | #define BUS_CTRL_ENDIAN_NSP_CONF \ |
66 | (0x02 << DMADATA_ENDIAN_SHIFT | 0x02 << DMADESC_ENDIAN_SHIFT) |
67 | |
68 | #define BUS_CTRL_ENDIAN_CONF_MASK \ |
69 | (0x3 << MMIO_ENDIAN_SHIFT | 0x3 << DMADESC_ENDIAN_SHIFT | \ |
70 | 0x3 << DMADATA_ENDIAN_SHIFT | 0x3 << PIODATA_ENDIAN_SHIFT) |
71 | |
72 | enum brcm_ahci_version { |
73 | BRCM_SATA_BCM7425 = 1, |
74 | BRCM_SATA_BCM7445, |
75 | BRCM_SATA_NSP, |
76 | BRCM_SATA_BCM7216, |
77 | }; |
78 | |
79 | enum brcm_ahci_quirks { |
80 | BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(0), |
81 | }; |
82 | |
83 | struct brcm_ahci_priv { |
84 | struct device *dev; |
85 | void __iomem *top_ctrl; |
86 | u32 port_mask; |
87 | u32 quirks; |
88 | enum brcm_ahci_version version; |
89 | struct reset_control *rcdev_rescal; |
90 | struct reset_control *rcdev_ahci; |
91 | }; |
92 | |
93 | static inline u32 brcm_sata_readreg(void __iomem *addr) |
94 | { |
95 | /* |
96 | * MIPS endianness is configured by boot strap, which also reverses all |
97 | * bus endianness (i.e., big-endian CPU + big endian bus ==> native |
98 | * endian I/O). |
99 | * |
100 | * Other architectures (e.g., ARM) either do not support big endian, or |
101 | * else leave I/O in little endian mode. |
102 | */ |
103 | if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) |
104 | return __raw_readl(addr); |
105 | else |
106 | return readl_relaxed(addr); |
107 | } |
108 | |
109 | static inline void brcm_sata_writereg(u32 val, void __iomem *addr) |
110 | { |
111 | /* See brcm_sata_readreg() comments */ |
112 | if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) |
113 | __raw_writel(val, addr); |
114 | else |
115 | writel_relaxed(val, addr); |
116 | } |
117 | |
118 | static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv) |
119 | { |
120 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
121 | u32 port_ctrl, host_caps; |
122 | int i; |
123 | |
124 | /* Enable support for ALPM */ |
125 | host_caps = readl(addr: hpriv->mmio + HOST_CAP); |
126 | if (!(host_caps & HOST_CAP_ALPM)) |
127 | hpriv->flags |= AHCI_HFLAG_YES_ALPM; |
128 | |
129 | /* |
130 | * Adjust timeout to allow PLL sufficient time to lock while waking |
131 | * up from slumber mode. |
132 | */ |
133 | for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL; |
134 | i < SATA_TOP_MAX_PHYS; |
135 | i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) { |
136 | if (priv->port_mask & BIT(i)) |
137 | writel(val: 0xff1003fc, |
138 | addr: hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl)); |
139 | } |
140 | } |
141 | |
142 | static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port) |
143 | { |
144 | void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL + |
145 | (port * SATA_TOP_CTRL_PHY_OFFS); |
146 | void __iomem *p; |
147 | u32 reg; |
148 | |
149 | if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE) |
150 | return; |
151 | |
152 | /* clear PHY_DEFAULT_POWER_STATE */ |
153 | p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1; |
154 | reg = brcm_sata_readreg(addr: p); |
155 | reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE; |
156 | brcm_sata_writereg(val: reg, addr: p); |
157 | |
158 | /* reset the PHY digital logic */ |
159 | p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2; |
160 | reg = brcm_sata_readreg(addr: p); |
161 | reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB | |
162 | SATA_TOP_CTRL_2_SW_RST_RX); |
163 | reg |= SATA_TOP_CTRL_2_SW_RST_TX; |
164 | brcm_sata_writereg(val: reg, addr: p); |
165 | reg = brcm_sata_readreg(addr: p); |
166 | reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET; |
167 | brcm_sata_writereg(val: reg, addr: p); |
168 | reg = brcm_sata_readreg(addr: p); |
169 | reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET; |
170 | brcm_sata_writereg(val: reg, addr: p); |
171 | (void)brcm_sata_readreg(addr: p); |
172 | } |
173 | |
174 | static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port) |
175 | { |
176 | void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL + |
177 | (port * SATA_TOP_CTRL_PHY_OFFS); |
178 | void __iomem *p; |
179 | u32 reg; |
180 | |
181 | if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE) |
182 | return; |
183 | |
184 | /* power-off the PHY digital logic */ |
185 | p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2; |
186 | reg = brcm_sata_readreg(addr: p); |
187 | reg |= (SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB | |
188 | SATA_TOP_CTRL_2_SW_RST_RX | SATA_TOP_CTRL_2_SW_RST_TX | |
189 | SATA_TOP_CTRL_2_PHY_GLOBAL_RESET); |
190 | brcm_sata_writereg(val: reg, addr: p); |
191 | |
192 | /* set PHY_DEFAULT_POWER_STATE */ |
193 | p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1; |
194 | reg = brcm_sata_readreg(addr: p); |
195 | reg |= SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE; |
196 | brcm_sata_writereg(val: reg, addr: p); |
197 | } |
198 | |
199 | static void brcm_sata_phys_enable(struct brcm_ahci_priv *priv) |
200 | { |
201 | int i; |
202 | |
203 | for (i = 0; i < SATA_TOP_MAX_PHYS; i++) |
204 | if (priv->port_mask & BIT(i)) |
205 | brcm_sata_phy_enable(priv, port: i); |
206 | } |
207 | |
208 | static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv) |
209 | { |
210 | int i; |
211 | |
212 | for (i = 0; i < SATA_TOP_MAX_PHYS; i++) |
213 | if (priv->port_mask & BIT(i)) |
214 | brcm_sata_phy_disable(priv, port: i); |
215 | } |
216 | |
217 | static u32 brcm_ahci_get_portmask(struct ahci_host_priv *hpriv, |
218 | struct brcm_ahci_priv *priv) |
219 | { |
220 | u32 impl; |
221 | |
222 | impl = readl(addr: hpriv->mmio + HOST_PORTS_IMPL); |
223 | |
224 | if (fls(x: impl) > SATA_TOP_MAX_PHYS) |
225 | dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n" , |
226 | impl); |
227 | else if (!impl) |
228 | dev_info(priv->dev, "no ports found\n" ); |
229 | |
230 | return impl; |
231 | } |
232 | |
233 | static void brcm_sata_init(struct brcm_ahci_priv *priv) |
234 | { |
235 | void __iomem *ctrl = priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL; |
236 | u32 data; |
237 | |
238 | /* Configure endianness */ |
239 | data = brcm_sata_readreg(addr: ctrl); |
240 | data &= ~BUS_CTRL_ENDIAN_CONF_MASK; |
241 | if (priv->version == BRCM_SATA_NSP) |
242 | data |= BUS_CTRL_ENDIAN_NSP_CONF; |
243 | else |
244 | data |= BUS_CTRL_ENDIAN_CONF; |
245 | brcm_sata_writereg(val: data, addr: ctrl); |
246 | } |
247 | |
248 | static unsigned int brcm_ahci_read_id(struct ata_device *dev, |
249 | struct ata_taskfile *tf, __le16 *id) |
250 | { |
251 | struct ata_port *ap = dev->link->ap; |
252 | struct ata_host *host = ap->host; |
253 | struct ahci_host_priv *hpriv = host->private_data; |
254 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
255 | void __iomem *mmio = hpriv->mmio; |
256 | unsigned int err_mask; |
257 | unsigned long flags; |
258 | int i, rc; |
259 | u32 ctl; |
260 | |
261 | /* Try to read the device ID and, if this fails, proceed with the |
262 | * recovery sequence below |
263 | */ |
264 | err_mask = ata_do_dev_read_id(dev, tf, id); |
265 | if (likely(!err_mask)) |
266 | return err_mask; |
267 | |
268 | /* Disable host interrupts */ |
269 | spin_lock_irqsave(&host->lock, flags); |
270 | ctl = readl(addr: mmio + HOST_CTL); |
271 | ctl &= ~HOST_IRQ_EN; |
272 | writel(val: ctl, addr: mmio + HOST_CTL); |
273 | readl(addr: mmio + HOST_CTL); /* flush */ |
274 | spin_unlock_irqrestore(lock: &host->lock, flags); |
275 | |
276 | /* Perform the SATA PHY reset sequence */ |
277 | brcm_sata_phy_disable(priv, port: ap->port_no); |
278 | |
279 | /* Reset the SATA clock */ |
280 | ahci_platform_disable_clks(hpriv); |
281 | msleep(msecs: 10); |
282 | |
283 | ahci_platform_enable_clks(hpriv); |
284 | msleep(msecs: 10); |
285 | |
286 | /* Bring the PHY back on */ |
287 | brcm_sata_phy_enable(priv, port: ap->port_no); |
288 | |
289 | /* Re-initialize and calibrate the PHY */ |
290 | for (i = 0; i < hpriv->nports; i++) { |
291 | rc = phy_init(phy: hpriv->phys[i]); |
292 | if (rc) |
293 | goto disable_phys; |
294 | |
295 | rc = phy_calibrate(phy: hpriv->phys[i]); |
296 | if (rc) { |
297 | phy_exit(phy: hpriv->phys[i]); |
298 | goto disable_phys; |
299 | } |
300 | } |
301 | |
302 | /* Re-enable host interrupts */ |
303 | spin_lock_irqsave(&host->lock, flags); |
304 | ctl = readl(addr: mmio + HOST_CTL); |
305 | ctl |= HOST_IRQ_EN; |
306 | writel(val: ctl, addr: mmio + HOST_CTL); |
307 | readl(addr: mmio + HOST_CTL); /* flush */ |
308 | spin_unlock_irqrestore(lock: &host->lock, flags); |
309 | |
310 | return ata_do_dev_read_id(dev, tf, id); |
311 | |
312 | disable_phys: |
313 | while (--i >= 0) { |
314 | phy_power_off(phy: hpriv->phys[i]); |
315 | phy_exit(phy: hpriv->phys[i]); |
316 | } |
317 | |
318 | return AC_ERR_OTHER; |
319 | } |
320 | |
321 | static void brcm_ahci_host_stop(struct ata_host *host) |
322 | { |
323 | struct ahci_host_priv *hpriv = host->private_data; |
324 | |
325 | ahci_platform_disable_resources(hpriv); |
326 | } |
327 | |
328 | static struct ata_port_operations ahci_brcm_platform_ops = { |
329 | .inherits = &ahci_ops, |
330 | .host_stop = brcm_ahci_host_stop, |
331 | .read_id = brcm_ahci_read_id, |
332 | }; |
333 | |
334 | static const struct ata_port_info ahci_brcm_port_info = { |
335 | .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM, |
336 | .link_flags = ATA_LFLAG_NO_DEBOUNCE_DELAY, |
337 | .pio_mask = ATA_PIO4, |
338 | .udma_mask = ATA_UDMA6, |
339 | .port_ops = &ahci_brcm_platform_ops, |
340 | }; |
341 | |
342 | static int brcm_ahci_suspend(struct device *dev) |
343 | { |
344 | struct ata_host *host = dev_get_drvdata(dev); |
345 | struct ahci_host_priv *hpriv = host->private_data; |
346 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
347 | int ret; |
348 | |
349 | brcm_sata_phys_disable(priv); |
350 | |
351 | if (IS_ENABLED(CONFIG_PM_SLEEP)) |
352 | ret = ahci_platform_suspend(dev); |
353 | else |
354 | ret = 0; |
355 | |
356 | reset_control_assert(rstc: priv->rcdev_ahci); |
357 | reset_control_rearm(rstc: priv->rcdev_rescal); |
358 | |
359 | return ret; |
360 | } |
361 | |
362 | static int __maybe_unused brcm_ahci_resume(struct device *dev) |
363 | { |
364 | struct ata_host *host = dev_get_drvdata(dev); |
365 | struct ahci_host_priv *hpriv = host->private_data; |
366 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
367 | int ret = 0; |
368 | |
369 | ret = reset_control_deassert(rstc: priv->rcdev_ahci); |
370 | if (ret) |
371 | return ret; |
372 | ret = reset_control_reset(rstc: priv->rcdev_rescal); |
373 | if (ret) |
374 | return ret; |
375 | |
376 | /* Make sure clocks are turned on before re-configuration */ |
377 | ret = ahci_platform_enable_clks(hpriv); |
378 | if (ret) |
379 | return ret; |
380 | |
381 | ret = ahci_platform_enable_regulators(hpriv); |
382 | if (ret) |
383 | goto out_disable_clks; |
384 | |
385 | brcm_sata_init(priv); |
386 | brcm_sata_phys_enable(priv); |
387 | brcm_sata_alpm_init(hpriv); |
388 | |
389 | /* Since we had to enable clocks earlier on, we cannot use |
390 | * ahci_platform_resume() as-is since a second call to |
391 | * ahci_platform_enable_resources() would bump up the resources |
392 | * (regulators, clocks, PHYs) count artificially so we copy the part |
393 | * after ahci_platform_enable_resources(). |
394 | */ |
395 | ret = ahci_platform_enable_phys(hpriv); |
396 | if (ret) |
397 | goto out_disable_phys; |
398 | |
399 | ret = ahci_platform_resume_host(dev); |
400 | if (ret) |
401 | goto out_disable_platform_phys; |
402 | |
403 | /* We resumed so update PM runtime state */ |
404 | pm_runtime_disable(dev); |
405 | pm_runtime_set_active(dev); |
406 | pm_runtime_enable(dev); |
407 | |
408 | return 0; |
409 | |
410 | out_disable_platform_phys: |
411 | ahci_platform_disable_phys(hpriv); |
412 | out_disable_phys: |
413 | brcm_sata_phys_disable(priv); |
414 | ahci_platform_disable_regulators(hpriv); |
415 | out_disable_clks: |
416 | ahci_platform_disable_clks(hpriv); |
417 | return ret; |
418 | } |
419 | |
420 | static const struct scsi_host_template ahci_platform_sht = { |
421 | AHCI_SHT(DRV_NAME), |
422 | }; |
423 | |
424 | static const struct of_device_id ahci_of_match[] = { |
425 | {.compatible = "brcm,bcm7425-ahci" , .data = (void *)BRCM_SATA_BCM7425}, |
426 | {.compatible = "brcm,bcm7445-ahci" , .data = (void *)BRCM_SATA_BCM7445}, |
427 | {.compatible = "brcm,bcm63138-ahci" , .data = (void *)BRCM_SATA_BCM7445}, |
428 | {.compatible = "brcm,bcm-nsp-ahci" , .data = (void *)BRCM_SATA_NSP}, |
429 | {.compatible = "brcm,bcm7216-ahci" , .data = (void *)BRCM_SATA_BCM7216}, |
430 | { /* sentinel */ } |
431 | }; |
432 | MODULE_DEVICE_TABLE(of, ahci_of_match); |
433 | |
434 | static int brcm_ahci_probe(struct platform_device *pdev) |
435 | { |
436 | const struct of_device_id *of_id; |
437 | struct device *dev = &pdev->dev; |
438 | struct brcm_ahci_priv *priv; |
439 | struct ahci_host_priv *hpriv; |
440 | struct resource *res; |
441 | int ret; |
442 | |
443 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
444 | if (!priv) |
445 | return -ENOMEM; |
446 | |
447 | of_id = of_match_node(matches: ahci_of_match, node: pdev->dev.of_node); |
448 | if (!of_id) |
449 | return -ENODEV; |
450 | |
451 | priv->version = (unsigned long)of_id->data; |
452 | priv->dev = dev; |
453 | |
454 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl" ); |
455 | priv->top_ctrl = devm_ioremap_resource(dev, res); |
456 | if (IS_ERR(ptr: priv->top_ctrl)) |
457 | return PTR_ERR(ptr: priv->top_ctrl); |
458 | |
459 | if (priv->version == BRCM_SATA_BCM7216) { |
460 | priv->rcdev_rescal = devm_reset_control_get_optional_shared( |
461 | dev: &pdev->dev, id: "rescal" ); |
462 | if (IS_ERR(ptr: priv->rcdev_rescal)) |
463 | return PTR_ERR(ptr: priv->rcdev_rescal); |
464 | } |
465 | priv->rcdev_ahci = devm_reset_control_get_optional(dev: &pdev->dev, id: "ahci" ); |
466 | if (IS_ERR(ptr: priv->rcdev_ahci)) |
467 | return PTR_ERR(ptr: priv->rcdev_ahci); |
468 | |
469 | hpriv = ahci_platform_get_resources(pdev, flags: 0); |
470 | if (IS_ERR(ptr: hpriv)) |
471 | return PTR_ERR(ptr: hpriv); |
472 | |
473 | hpriv->plat_data = priv; |
474 | hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP | AHCI_HFLAG_NO_WRITE_TO_RO; |
475 | |
476 | switch (priv->version) { |
477 | case BRCM_SATA_BCM7425: |
478 | hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE; |
479 | fallthrough; |
480 | case BRCM_SATA_NSP: |
481 | hpriv->flags |= AHCI_HFLAG_NO_NCQ; |
482 | priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE; |
483 | break; |
484 | default: |
485 | break; |
486 | } |
487 | |
488 | ret = reset_control_reset(rstc: priv->rcdev_rescal); |
489 | if (ret) |
490 | return ret; |
491 | ret = reset_control_deassert(rstc: priv->rcdev_ahci); |
492 | if (ret) |
493 | return ret; |
494 | |
495 | ret = ahci_platform_enable_clks(hpriv); |
496 | if (ret) |
497 | goto out_reset; |
498 | |
499 | ret = ahci_platform_enable_regulators(hpriv); |
500 | if (ret) |
501 | goto out_disable_clks; |
502 | |
503 | /* Must be first so as to configure endianness including that |
504 | * of the standard AHCI register space. |
505 | */ |
506 | brcm_sata_init(priv); |
507 | |
508 | /* Initializes priv->port_mask which is used below */ |
509 | priv->port_mask = brcm_ahci_get_portmask(hpriv, priv); |
510 | if (!priv->port_mask) { |
511 | ret = -ENODEV; |
512 | goto out_disable_regulators; |
513 | } |
514 | |
515 | /* Must be done before ahci_platform_enable_phys() */ |
516 | brcm_sata_phys_enable(priv); |
517 | |
518 | brcm_sata_alpm_init(hpriv); |
519 | |
520 | ret = ahci_platform_enable_phys(hpriv); |
521 | if (ret) |
522 | goto out_disable_phys; |
523 | |
524 | ret = ahci_platform_init_host(pdev, hpriv, pi_template: &ahci_brcm_port_info, |
525 | sht: &ahci_platform_sht); |
526 | if (ret) |
527 | goto out_disable_platform_phys; |
528 | |
529 | dev_info(dev, "Broadcom AHCI SATA3 registered\n" ); |
530 | |
531 | return 0; |
532 | |
533 | out_disable_platform_phys: |
534 | ahci_platform_disable_phys(hpriv); |
535 | out_disable_phys: |
536 | brcm_sata_phys_disable(priv); |
537 | out_disable_regulators: |
538 | ahci_platform_disable_regulators(hpriv); |
539 | out_disable_clks: |
540 | ahci_platform_disable_clks(hpriv); |
541 | out_reset: |
542 | reset_control_assert(rstc: priv->rcdev_ahci); |
543 | reset_control_rearm(rstc: priv->rcdev_rescal); |
544 | return ret; |
545 | } |
546 | |
547 | static void brcm_ahci_remove(struct platform_device *pdev) |
548 | { |
549 | struct ata_host *host = dev_get_drvdata(dev: &pdev->dev); |
550 | struct ahci_host_priv *hpriv = host->private_data; |
551 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
552 | |
553 | brcm_sata_phys_disable(priv); |
554 | |
555 | ata_platform_remove_one(pdev); |
556 | } |
557 | |
558 | static void brcm_ahci_shutdown(struct platform_device *pdev) |
559 | { |
560 | int ret; |
561 | |
562 | /* All resources releasing happens via devres, but our device, unlike a |
563 | * proper remove is not disappearing, therefore using |
564 | * brcm_ahci_suspend() here which does explicit power management is |
565 | * appropriate. |
566 | */ |
567 | ret = brcm_ahci_suspend(dev: &pdev->dev); |
568 | if (ret) |
569 | dev_err(&pdev->dev, "failed to shutdown\n" ); |
570 | } |
571 | |
572 | static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume); |
573 | |
574 | static struct platform_driver brcm_ahci_driver = { |
575 | .probe = brcm_ahci_probe, |
576 | .remove_new = brcm_ahci_remove, |
577 | .shutdown = brcm_ahci_shutdown, |
578 | .driver = { |
579 | .name = DRV_NAME, |
580 | .of_match_table = ahci_of_match, |
581 | .pm = &ahci_brcm_pm_ops, |
582 | }, |
583 | }; |
584 | module_platform_driver(brcm_ahci_driver); |
585 | |
586 | MODULE_DESCRIPTION("Broadcom SATA3 AHCI Controller Driver" ); |
587 | MODULE_AUTHOR("Brian Norris" ); |
588 | MODULE_LICENSE("GPL" ); |
589 | MODULE_ALIAS("platform:sata-brcmstb" ); |
590 | |