1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * AHCI SATA platform library |
4 | * |
5 | * Copyright 2004-2005 Red Hat, Inc. |
6 | * Jeff Garzik <jgarzik@pobox.com> |
7 | * Copyright 2010 MontaVista Software, LLC. |
8 | * Anton Vorontsov <avorontsov@ru.mvista.com> |
9 | */ |
10 | |
11 | #include <linux/clk.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/gfp.h> |
14 | #include <linux/module.h> |
15 | #include <linux/pm.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/device.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/libata.h> |
20 | #include <linux/ahci_platform.h> |
21 | #include <linux/phy/phy.h> |
22 | #include <linux/pm_runtime.h> |
23 | #include <linux/of.h> |
24 | #include <linux/of_platform.h> |
25 | #include <linux/reset.h> |
26 | #include "ahci.h" |
27 | |
28 | static void ahci_host_stop(struct ata_host *host); |
29 | |
30 | struct ata_port_operations ahci_platform_ops = { |
31 | .inherits = &ahci_ops, |
32 | .host_stop = ahci_host_stop, |
33 | }; |
34 | EXPORT_SYMBOL_GPL(ahci_platform_ops); |
35 | |
36 | /** |
37 | * ahci_platform_enable_phys - Enable PHYs |
38 | * @hpriv: host private area to store config values |
39 | * |
40 | * This function enables all the PHYs found in hpriv->phys, if any. |
41 | * If a PHY fails to be enabled, it disables all the PHYs already |
42 | * enabled in reverse order and returns an error. |
43 | * |
44 | * RETURNS: |
45 | * 0 on success otherwise a negative error code |
46 | */ |
47 | int ahci_platform_enable_phys(struct ahci_host_priv *hpriv) |
48 | { |
49 | int rc, i; |
50 | |
51 | for (i = 0; i < hpriv->nports; i++) { |
52 | rc = phy_init(phy: hpriv->phys[i]); |
53 | if (rc) |
54 | goto disable_phys; |
55 | |
56 | rc = phy_set_mode(hpriv->phys[i], PHY_MODE_SATA); |
57 | if (rc) { |
58 | phy_exit(phy: hpriv->phys[i]); |
59 | goto disable_phys; |
60 | } |
61 | |
62 | rc = phy_power_on(phy: hpriv->phys[i]); |
63 | if (rc) { |
64 | phy_exit(phy: hpriv->phys[i]); |
65 | goto disable_phys; |
66 | } |
67 | } |
68 | |
69 | return 0; |
70 | |
71 | disable_phys: |
72 | while (--i >= 0) { |
73 | phy_power_off(phy: hpriv->phys[i]); |
74 | phy_exit(phy: hpriv->phys[i]); |
75 | } |
76 | return rc; |
77 | } |
78 | EXPORT_SYMBOL_GPL(ahci_platform_enable_phys); |
79 | |
80 | /** |
81 | * ahci_platform_disable_phys - Disable PHYs |
82 | * @hpriv: host private area to store config values |
83 | * |
84 | * This function disables all PHYs found in hpriv->phys. |
85 | */ |
86 | void ahci_platform_disable_phys(struct ahci_host_priv *hpriv) |
87 | { |
88 | int i; |
89 | |
90 | for (i = 0; i < hpriv->nports; i++) { |
91 | phy_power_off(phy: hpriv->phys[i]); |
92 | phy_exit(phy: hpriv->phys[i]); |
93 | } |
94 | } |
95 | EXPORT_SYMBOL_GPL(ahci_platform_disable_phys); |
96 | |
97 | /** |
98 | * ahci_platform_find_clk - Find platform clock |
99 | * @hpriv: host private area to store config values |
100 | * @con_id: clock connection ID |
101 | * |
102 | * This function returns a pointer to the clock descriptor of the clock with |
103 | * the passed ID. |
104 | * |
105 | * RETURNS: |
106 | * Pointer to the clock descriptor on success otherwise NULL |
107 | */ |
108 | struct clk *ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id) |
109 | { |
110 | int i; |
111 | |
112 | for (i = 0; i < hpriv->n_clks; i++) { |
113 | if (hpriv->clks[i].id && !strcmp(hpriv->clks[i].id, con_id)) |
114 | return hpriv->clks[i].clk; |
115 | } |
116 | |
117 | return NULL; |
118 | } |
119 | EXPORT_SYMBOL_GPL(ahci_platform_find_clk); |
120 | |
121 | /** |
122 | * ahci_platform_enable_clks - Enable platform clocks |
123 | * @hpriv: host private area to store config values |
124 | * |
125 | * This function enables all the clks found for the AHCI device. |
126 | * |
127 | * RETURNS: |
128 | * 0 on success otherwise a negative error code |
129 | */ |
130 | int ahci_platform_enable_clks(struct ahci_host_priv *hpriv) |
131 | { |
132 | return clk_bulk_prepare_enable(num_clks: hpriv->n_clks, clks: hpriv->clks); |
133 | } |
134 | EXPORT_SYMBOL_GPL(ahci_platform_enable_clks); |
135 | |
136 | /** |
137 | * ahci_platform_disable_clks - Disable platform clocks |
138 | * @hpriv: host private area to store config values |
139 | * |
140 | * This function disables all the clocks enabled before |
141 | * (bulk-clocks-disable function is supposed to do that in reverse |
142 | * from the enabling procedure order). |
143 | */ |
144 | void ahci_platform_disable_clks(struct ahci_host_priv *hpriv) |
145 | { |
146 | clk_bulk_disable_unprepare(num_clks: hpriv->n_clks, clks: hpriv->clks); |
147 | } |
148 | EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); |
149 | |
150 | /** |
151 | * ahci_platform_deassert_rsts - Deassert/trigger platform resets |
152 | * @hpriv: host private area to store config values |
153 | * |
154 | * This function deasserts or triggers all the reset lines found for |
155 | * the AHCI device. |
156 | * |
157 | * RETURNS: |
158 | * 0 on success otherwise a negative error code |
159 | */ |
160 | int ahci_platform_deassert_rsts(struct ahci_host_priv *hpriv) |
161 | { |
162 | if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER) |
163 | return reset_control_reset(rstc: hpriv->rsts); |
164 | |
165 | return reset_control_deassert(rstc: hpriv->rsts); |
166 | } |
167 | EXPORT_SYMBOL_GPL(ahci_platform_deassert_rsts); |
168 | |
169 | /** |
170 | * ahci_platform_assert_rsts - Assert/rearm platform resets |
171 | * @hpriv: host private area to store config values |
172 | * |
173 | * This function asserts or rearms (for self-deasserting resets) all |
174 | * the reset controls found for the AHCI device. |
175 | * |
176 | * RETURNS: |
177 | * 0 on success otherwise a negative error code |
178 | */ |
179 | int ahci_platform_assert_rsts(struct ahci_host_priv *hpriv) |
180 | { |
181 | if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER) |
182 | return reset_control_rearm(rstc: hpriv->rsts); |
183 | |
184 | return reset_control_assert(rstc: hpriv->rsts); |
185 | } |
186 | EXPORT_SYMBOL_GPL(ahci_platform_assert_rsts); |
187 | |
188 | /** |
189 | * ahci_platform_enable_regulators - Enable regulators |
190 | * @hpriv: host private area to store config values |
191 | * |
192 | * This function enables all the regulators found in controller and |
193 | * hpriv->target_pwrs, if any. If a regulator fails to be enabled, it |
194 | * disables all the regulators already enabled in reverse order and |
195 | * returns an error. |
196 | * |
197 | * RETURNS: |
198 | * 0 on success otherwise a negative error code |
199 | */ |
200 | int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv) |
201 | { |
202 | int rc, i; |
203 | |
204 | rc = regulator_enable(regulator: hpriv->ahci_regulator); |
205 | if (rc) |
206 | return rc; |
207 | |
208 | rc = regulator_enable(regulator: hpriv->phy_regulator); |
209 | if (rc) |
210 | goto disable_ahci_pwrs; |
211 | |
212 | for (i = 0; i < hpriv->nports; i++) { |
213 | if (!hpriv->target_pwrs[i]) |
214 | continue; |
215 | |
216 | rc = regulator_enable(regulator: hpriv->target_pwrs[i]); |
217 | if (rc) |
218 | goto disable_target_pwrs; |
219 | } |
220 | |
221 | return 0; |
222 | |
223 | disable_target_pwrs: |
224 | while (--i >= 0) |
225 | if (hpriv->target_pwrs[i]) |
226 | regulator_disable(regulator: hpriv->target_pwrs[i]); |
227 | |
228 | regulator_disable(regulator: hpriv->phy_regulator); |
229 | disable_ahci_pwrs: |
230 | regulator_disable(regulator: hpriv->ahci_regulator); |
231 | return rc; |
232 | } |
233 | EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators); |
234 | |
235 | /** |
236 | * ahci_platform_disable_regulators - Disable regulators |
237 | * @hpriv: host private area to store config values |
238 | * |
239 | * This function disables all regulators found in hpriv->target_pwrs and |
240 | * AHCI controller. |
241 | */ |
242 | void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv) |
243 | { |
244 | int i; |
245 | |
246 | for (i = 0; i < hpriv->nports; i++) { |
247 | if (!hpriv->target_pwrs[i]) |
248 | continue; |
249 | regulator_disable(regulator: hpriv->target_pwrs[i]); |
250 | } |
251 | |
252 | regulator_disable(regulator: hpriv->ahci_regulator); |
253 | regulator_disable(regulator: hpriv->phy_regulator); |
254 | } |
255 | EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators); |
256 | /** |
257 | * ahci_platform_enable_resources - Enable platform resources |
258 | * @hpriv: host private area to store config values |
259 | * |
260 | * This function enables all ahci_platform managed resources in the |
261 | * following order: |
262 | * 1) Regulator |
263 | * 2) Clocks (through ahci_platform_enable_clks) |
264 | * 3) Resets |
265 | * 4) Phys |
266 | * |
267 | * If resource enabling fails at any point the previous enabled resources |
268 | * are disabled in reverse order. |
269 | * |
270 | * RETURNS: |
271 | * 0 on success otherwise a negative error code |
272 | */ |
273 | int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) |
274 | { |
275 | int rc; |
276 | |
277 | rc = ahci_platform_enable_regulators(hpriv); |
278 | if (rc) |
279 | return rc; |
280 | |
281 | rc = ahci_platform_enable_clks(hpriv); |
282 | if (rc) |
283 | goto disable_regulator; |
284 | |
285 | rc = ahci_platform_deassert_rsts(hpriv); |
286 | if (rc) |
287 | goto disable_clks; |
288 | |
289 | rc = ahci_platform_enable_phys(hpriv); |
290 | if (rc) |
291 | goto disable_rsts; |
292 | |
293 | return 0; |
294 | |
295 | disable_rsts: |
296 | ahci_platform_assert_rsts(hpriv); |
297 | |
298 | disable_clks: |
299 | ahci_platform_disable_clks(hpriv); |
300 | |
301 | disable_regulator: |
302 | ahci_platform_disable_regulators(hpriv); |
303 | |
304 | return rc; |
305 | } |
306 | EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); |
307 | |
308 | /** |
309 | * ahci_platform_disable_resources - Disable platform resources |
310 | * @hpriv: host private area to store config values |
311 | * |
312 | * This function disables all ahci_platform managed resources in the |
313 | * following order: |
314 | * 1) Phys |
315 | * 2) Resets |
316 | * 3) Clocks (through ahci_platform_disable_clks) |
317 | * 4) Regulator |
318 | */ |
319 | void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) |
320 | { |
321 | ahci_platform_disable_phys(hpriv); |
322 | |
323 | ahci_platform_assert_rsts(hpriv); |
324 | |
325 | ahci_platform_disable_clks(hpriv); |
326 | |
327 | ahci_platform_disable_regulators(hpriv); |
328 | } |
329 | EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); |
330 | |
331 | static void ahci_platform_put_resources(struct device *dev, void *res) |
332 | { |
333 | struct ahci_host_priv *hpriv = res; |
334 | int c; |
335 | |
336 | if (hpriv->got_runtime_pm) { |
337 | pm_runtime_put_sync(dev); |
338 | pm_runtime_disable(dev); |
339 | } |
340 | |
341 | /* |
342 | * The regulators are tied to child node device and not to the |
343 | * SATA device itself. So we can't use devm for automatically |
344 | * releasing them. We have to do it manually here. |
345 | */ |
346 | for (c = 0; c < hpriv->nports; c++) |
347 | if (hpriv->target_pwrs && hpriv->target_pwrs[c]) |
348 | regulator_put(regulator: hpriv->target_pwrs[c]); |
349 | |
350 | kfree(objp: hpriv->target_pwrs); |
351 | } |
352 | |
353 | static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port, |
354 | struct device *dev, struct device_node *node) |
355 | { |
356 | int rc; |
357 | |
358 | hpriv->phys[port] = devm_of_phy_get(dev, np: node, NULL); |
359 | |
360 | if (!IS_ERR(ptr: hpriv->phys[port])) |
361 | return 0; |
362 | |
363 | rc = PTR_ERR(ptr: hpriv->phys[port]); |
364 | switch (rc) { |
365 | case -ENOSYS: |
366 | /* No PHY support. Check if PHY is required. */ |
367 | if (of_property_present(np: node, propname: "phys" )) { |
368 | dev_err(dev, |
369 | "couldn't get PHY in node %pOFn: ENOSYS\n" , |
370 | node); |
371 | break; |
372 | } |
373 | fallthrough; |
374 | case -ENODEV: |
375 | /* continue normally */ |
376 | hpriv->phys[port] = NULL; |
377 | rc = 0; |
378 | break; |
379 | case -EPROBE_DEFER: |
380 | /* Do not complain yet */ |
381 | break; |
382 | |
383 | default: |
384 | dev_err(dev, |
385 | "couldn't get PHY in node %pOFn: %d\n" , |
386 | node, rc); |
387 | |
388 | break; |
389 | } |
390 | |
391 | return rc; |
392 | } |
393 | |
394 | static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port, |
395 | struct device *dev) |
396 | { |
397 | struct regulator *target_pwr; |
398 | int rc = 0; |
399 | |
400 | target_pwr = regulator_get(dev, id: "target" ); |
401 | |
402 | if (!IS_ERR(ptr: target_pwr)) |
403 | hpriv->target_pwrs[port] = target_pwr; |
404 | else |
405 | rc = PTR_ERR(ptr: target_pwr); |
406 | |
407 | return rc; |
408 | } |
409 | |
410 | static int ahci_platform_get_firmware(struct ahci_host_priv *hpriv, |
411 | struct device *dev) |
412 | { |
413 | struct device_node *child; |
414 | u32 port; |
415 | |
416 | if (!of_property_read_u32(np: dev->of_node, propname: "hba-cap" , out_value: &hpriv->saved_cap)) |
417 | hpriv->saved_cap &= (HOST_CAP_SSS | HOST_CAP_MPS); |
418 | |
419 | of_property_read_u32(np: dev->of_node, |
420 | propname: "ports-implemented" , out_value: &hpriv->saved_port_map); |
421 | |
422 | for_each_child_of_node(dev->of_node, child) { |
423 | if (!of_device_is_available(device: child)) |
424 | continue; |
425 | |
426 | if (of_property_read_u32(np: child, propname: "reg" , out_value: &port)) { |
427 | of_node_put(node: child); |
428 | return -EINVAL; |
429 | } |
430 | |
431 | if (!of_property_read_u32(np: child, propname: "hba-port-cap" , out_value: &hpriv->saved_port_cap[port])) |
432 | hpriv->saved_port_cap[port] &= PORT_CMD_CAP; |
433 | } |
434 | |
435 | return 0; |
436 | } |
437 | |
438 | /** |
439 | * ahci_platform_get_resources - Get platform resources |
440 | * @pdev: platform device to get resources for |
441 | * @flags: bitmap representing the resource to get |
442 | * |
443 | * This function allocates an ahci_host_priv struct, and gets the following |
444 | * resources, storing a reference to them inside the returned struct: |
445 | * |
446 | * 1) mmio registers (IORESOURCE_MEM 0, mandatory) |
447 | * 2) regulator for controlling the targets power (optional) |
448 | * regulator for controlling the AHCI controller (optional) |
449 | * 3) all clocks specified in the devicetree node, or a single |
450 | * clock for non-OF platforms (optional) |
451 | * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional) |
452 | * 5) phys (optional) |
453 | * |
454 | * RETURNS: |
455 | * The allocated ahci_host_priv on success, otherwise an ERR_PTR value |
456 | */ |
457 | struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev, |
458 | unsigned int flags) |
459 | { |
460 | int child_nodes, rc = -ENOMEM, enabled_ports = 0; |
461 | struct device *dev = &pdev->dev; |
462 | struct ahci_host_priv *hpriv; |
463 | struct device_node *child; |
464 | u32 mask_port_map = 0; |
465 | |
466 | if (!devres_open_group(dev, NULL, GFP_KERNEL)) |
467 | return ERR_PTR(error: -ENOMEM); |
468 | |
469 | hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv), |
470 | GFP_KERNEL); |
471 | if (!hpriv) |
472 | goto err_out; |
473 | |
474 | devres_add(dev, res: hpriv); |
475 | |
476 | /* |
477 | * If the DT provided an "ahci" named resource, use it. Otherwise, |
478 | * fallback to using the default first resource for the device node. |
479 | */ |
480 | if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci" )) |
481 | hpriv->mmio = devm_platform_ioremap_resource_byname(pdev, name: "ahci" ); |
482 | else |
483 | hpriv->mmio = devm_platform_ioremap_resource(pdev, index: 0); |
484 | if (IS_ERR(ptr: hpriv->mmio)) { |
485 | rc = PTR_ERR(ptr: hpriv->mmio); |
486 | goto err_out; |
487 | } |
488 | |
489 | /* |
490 | * Bulk clocks getting procedure can fail to find any clock due to |
491 | * running on a non-OF platform or due to the clocks being defined in |
492 | * bypass of the DT firmware (like da850, spear13xx). In that case we |
493 | * fallback to getting a single clock source right from the dev clocks |
494 | * list. |
495 | */ |
496 | rc = devm_clk_bulk_get_all(dev, clks: &hpriv->clks); |
497 | if (rc < 0) |
498 | goto err_out; |
499 | |
500 | if (rc > 0) { |
501 | /* Got clocks in bulk */ |
502 | hpriv->n_clks = rc; |
503 | } else { |
504 | /* |
505 | * No clock bulk found: fallback to manually getting |
506 | * the optional clock. |
507 | */ |
508 | hpriv->clks = devm_kzalloc(dev, size: sizeof(*hpriv->clks), GFP_KERNEL); |
509 | if (!hpriv->clks) { |
510 | rc = -ENOMEM; |
511 | goto err_out; |
512 | } |
513 | hpriv->clks->clk = devm_clk_get_optional(dev, NULL); |
514 | if (IS_ERR(ptr: hpriv->clks->clk)) { |
515 | rc = PTR_ERR(ptr: hpriv->clks->clk); |
516 | goto err_out; |
517 | } else if (hpriv->clks->clk) { |
518 | hpriv->clks->id = "ahci" ; |
519 | hpriv->n_clks = 1; |
520 | } |
521 | } |
522 | |
523 | hpriv->ahci_regulator = devm_regulator_get(dev, id: "ahci" ); |
524 | if (IS_ERR(ptr: hpriv->ahci_regulator)) { |
525 | rc = PTR_ERR(ptr: hpriv->ahci_regulator); |
526 | if (rc != 0) |
527 | goto err_out; |
528 | } |
529 | |
530 | hpriv->phy_regulator = devm_regulator_get(dev, id: "phy" ); |
531 | if (IS_ERR(ptr: hpriv->phy_regulator)) { |
532 | rc = PTR_ERR(ptr: hpriv->phy_regulator); |
533 | goto err_out; |
534 | } |
535 | |
536 | if (flags & AHCI_PLATFORM_GET_RESETS) { |
537 | hpriv->rsts = devm_reset_control_array_get_optional_shared(dev); |
538 | if (IS_ERR(ptr: hpriv->rsts)) { |
539 | rc = PTR_ERR(ptr: hpriv->rsts); |
540 | goto err_out; |
541 | } |
542 | |
543 | hpriv->f_rsts = flags & AHCI_PLATFORM_RST_TRIGGER; |
544 | } |
545 | |
546 | /* |
547 | * Too many sub-nodes most likely means having something wrong with |
548 | * the firmware. |
549 | */ |
550 | child_nodes = of_get_child_count(np: dev->of_node); |
551 | if (child_nodes > AHCI_MAX_PORTS) { |
552 | rc = -EINVAL; |
553 | goto err_out; |
554 | } |
555 | |
556 | /* |
557 | * If no sub-node was found, we still need to set nports to |
558 | * one in order to be able to use the |
559 | * ahci_platform_[en|dis]able_[phys|regulators] functions. |
560 | */ |
561 | if (child_nodes) |
562 | hpriv->nports = child_nodes; |
563 | else |
564 | hpriv->nports = 1; |
565 | |
566 | hpriv->phys = devm_kcalloc(dev, n: hpriv->nports, size: sizeof(*hpriv->phys), GFP_KERNEL); |
567 | if (!hpriv->phys) { |
568 | rc = -ENOMEM; |
569 | goto err_out; |
570 | } |
571 | /* |
572 | * We cannot use devm_ here, since ahci_platform_put_resources() uses |
573 | * target_pwrs after devm_ have freed memory |
574 | */ |
575 | hpriv->target_pwrs = kcalloc(n: hpriv->nports, size: sizeof(*hpriv->target_pwrs), GFP_KERNEL); |
576 | if (!hpriv->target_pwrs) { |
577 | rc = -ENOMEM; |
578 | goto err_out; |
579 | } |
580 | |
581 | if (child_nodes) { |
582 | for_each_child_of_node(dev->of_node, child) { |
583 | u32 port; |
584 | struct platform_device *port_dev __maybe_unused; |
585 | |
586 | if (!of_device_is_available(device: child)) |
587 | continue; |
588 | |
589 | if (of_property_read_u32(np: child, propname: "reg" , out_value: &port)) { |
590 | rc = -EINVAL; |
591 | of_node_put(node: child); |
592 | goto err_out; |
593 | } |
594 | |
595 | if (port >= hpriv->nports) { |
596 | dev_warn(dev, "invalid port number %d\n" , port); |
597 | continue; |
598 | } |
599 | mask_port_map |= BIT(port); |
600 | |
601 | #ifdef CONFIG_OF_ADDRESS |
602 | of_platform_device_create(np: child, NULL, NULL); |
603 | |
604 | port_dev = of_find_device_by_node(np: child); |
605 | |
606 | if (port_dev) { |
607 | rc = ahci_platform_get_regulator(hpriv, port, |
608 | dev: &port_dev->dev); |
609 | if (rc == -EPROBE_DEFER) { |
610 | of_node_put(node: child); |
611 | goto err_out; |
612 | } |
613 | } |
614 | #endif |
615 | |
616 | rc = ahci_platform_get_phy(hpriv, port, dev, node: child); |
617 | if (rc) { |
618 | of_node_put(node: child); |
619 | goto err_out; |
620 | } |
621 | |
622 | enabled_ports++; |
623 | } |
624 | if (!enabled_ports) { |
625 | dev_warn(dev, "No port enabled\n" ); |
626 | rc = -ENODEV; |
627 | goto err_out; |
628 | } |
629 | |
630 | if (!hpriv->mask_port_map) |
631 | hpriv->mask_port_map = mask_port_map; |
632 | } else { |
633 | /* |
634 | * If no sub-node was found, keep this for device tree |
635 | * compatibility |
636 | */ |
637 | rc = ahci_platform_get_phy(hpriv, port: 0, dev, node: dev->of_node); |
638 | if (rc) |
639 | goto err_out; |
640 | |
641 | rc = ahci_platform_get_regulator(hpriv, port: 0, dev); |
642 | if (rc == -EPROBE_DEFER) |
643 | goto err_out; |
644 | } |
645 | |
646 | /* |
647 | * Retrieve firmware-specific flags which then will be used to set |
648 | * the HW-init fields of HBA and its ports |
649 | */ |
650 | rc = ahci_platform_get_firmware(hpriv, dev); |
651 | if (rc) |
652 | goto err_out; |
653 | |
654 | pm_runtime_enable(dev); |
655 | pm_runtime_get_sync(dev); |
656 | hpriv->got_runtime_pm = true; |
657 | |
658 | devres_remove_group(dev, NULL); |
659 | return hpriv; |
660 | |
661 | err_out: |
662 | devres_release_group(dev, NULL); |
663 | return ERR_PTR(error: rc); |
664 | } |
665 | EXPORT_SYMBOL_GPL(ahci_platform_get_resources); |
666 | |
667 | /** |
668 | * ahci_platform_init_host - Bring up an ahci-platform host |
669 | * @pdev: platform device pointer for the host |
670 | * @hpriv: ahci-host private data for the host |
671 | * @pi_template: template for the ata_port_info to use |
672 | * @sht: scsi_host_template to use when registering |
673 | * |
674 | * This function does all the usual steps needed to bring up an |
675 | * ahci-platform host, note any necessary resources (ie clks, phys, etc.) |
676 | * must be initialized / enabled before calling this. |
677 | * |
678 | * RETURNS: |
679 | * 0 on success otherwise a negative error code |
680 | */ |
681 | int ahci_platform_init_host(struct platform_device *pdev, |
682 | struct ahci_host_priv *hpriv, |
683 | const struct ata_port_info *pi_template, |
684 | const struct scsi_host_template *sht) |
685 | { |
686 | struct device *dev = &pdev->dev; |
687 | struct ata_port_info pi = *pi_template; |
688 | const struct ata_port_info *ppi[] = { &pi, NULL }; |
689 | struct ata_host *host; |
690 | int i, irq, n_ports, rc; |
691 | |
692 | irq = platform_get_irq(pdev, 0); |
693 | if (irq < 0) |
694 | return irq; |
695 | if (!irq) |
696 | return -EINVAL; |
697 | |
698 | hpriv->irq = irq; |
699 | |
700 | /* prepare host */ |
701 | pi.private_data = (void *)(unsigned long)hpriv->flags; |
702 | |
703 | ahci_save_initial_config(dev, hpriv); |
704 | |
705 | if (hpriv->cap & HOST_CAP_NCQ) |
706 | pi.flags |= ATA_FLAG_NCQ; |
707 | |
708 | if (hpriv->cap & HOST_CAP_PMP) |
709 | pi.flags |= ATA_FLAG_PMP; |
710 | |
711 | ahci_set_em_messages(hpriv, pi: &pi); |
712 | |
713 | /* CAP.NP sometimes indicate the index of the last enabled |
714 | * port, at other times, that of the last possible port, so |
715 | * determining the maximum port number requires looking at |
716 | * both CAP.NP and port_map. |
717 | */ |
718 | n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); |
719 | |
720 | host = ata_host_alloc_pinfo(dev, ppi, n_ports); |
721 | if (!host) |
722 | return -ENOMEM; |
723 | |
724 | host->private_data = hpriv; |
725 | |
726 | if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) |
727 | host->flags |= ATA_HOST_PARALLEL_SCAN; |
728 | else |
729 | dev_info(dev, "SSS flag set, parallel bus scan disabled\n" ); |
730 | |
731 | if (pi.flags & ATA_FLAG_EM) |
732 | ahci_reset_em(host); |
733 | |
734 | for (i = 0; i < host->n_ports; i++) { |
735 | struct ata_port *ap = host->ports[i]; |
736 | |
737 | ata_port_desc(ap, fmt: "mmio %pR" , |
738 | platform_get_resource(pdev, IORESOURCE_MEM, 0)); |
739 | ata_port_desc(ap, fmt: "port 0x%x" , 0x100 + ap->port_no * 0x80); |
740 | |
741 | /* set enclosure management message type */ |
742 | if (ap->flags & ATA_FLAG_EM) |
743 | ap->em_message_type = hpriv->em_msg_type; |
744 | |
745 | /* disabled/not-implemented port */ |
746 | if (!(hpriv->port_map & (1 << i))) |
747 | ap->ops = &ata_dummy_port_ops; |
748 | } |
749 | |
750 | if (hpriv->cap & HOST_CAP_64) { |
751 | rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); |
752 | if (rc) { |
753 | dev_err(dev, "Failed to enable 64-bit DMA.\n" ); |
754 | return rc; |
755 | } |
756 | } |
757 | |
758 | rc = ahci_reset_controller(host); |
759 | if (rc) |
760 | return rc; |
761 | |
762 | ahci_init_controller(host); |
763 | ahci_print_info(host, scc_s: "platform" ); |
764 | |
765 | return ahci_host_activate(host, sht); |
766 | } |
767 | EXPORT_SYMBOL_GPL(ahci_platform_init_host); |
768 | |
769 | static void ahci_host_stop(struct ata_host *host) |
770 | { |
771 | struct ahci_host_priv *hpriv = host->private_data; |
772 | |
773 | ahci_platform_disable_resources(hpriv); |
774 | } |
775 | |
776 | /** |
777 | * ahci_platform_shutdown - Disable interrupts and stop DMA for host ports |
778 | * @pdev: platform device pointer for the host |
779 | * |
780 | * This function is called during system shutdown and performs the minimal |
781 | * deconfiguration required to ensure that an ahci_platform host cannot |
782 | * corrupt or otherwise interfere with a new kernel being started with kexec. |
783 | */ |
784 | void ahci_platform_shutdown(struct platform_device *pdev) |
785 | { |
786 | struct ata_host *host = platform_get_drvdata(pdev); |
787 | struct ahci_host_priv *hpriv = host->private_data; |
788 | void __iomem *mmio = hpriv->mmio; |
789 | int i; |
790 | |
791 | for (i = 0; i < host->n_ports; i++) { |
792 | struct ata_port *ap = host->ports[i]; |
793 | |
794 | /* Disable port interrupts */ |
795 | if (ap->ops->freeze) |
796 | ap->ops->freeze(ap); |
797 | |
798 | /* Stop the port DMA engines */ |
799 | if (ap->ops->port_stop) |
800 | ap->ops->port_stop(ap); |
801 | } |
802 | |
803 | /* Disable and clear host interrupts */ |
804 | writel(readl(addr: mmio + HOST_CTL) & ~HOST_IRQ_EN, addr: mmio + HOST_CTL); |
805 | readl(addr: mmio + HOST_CTL); /* flush */ |
806 | writel(GENMASK(host->n_ports, 0), addr: mmio + HOST_IRQ_STAT); |
807 | } |
808 | EXPORT_SYMBOL_GPL(ahci_platform_shutdown); |
809 | |
810 | #ifdef CONFIG_PM_SLEEP |
811 | /** |
812 | * ahci_platform_suspend_host - Suspend an ahci-platform host |
813 | * @dev: device pointer for the host |
814 | * |
815 | * This function does all the usual steps needed to suspend an |
816 | * ahci-platform host, note any necessary resources (ie clks, phys, etc.) |
817 | * must be disabled after calling this. |
818 | * |
819 | * RETURNS: |
820 | * 0 on success otherwise a negative error code |
821 | */ |
822 | int ahci_platform_suspend_host(struct device *dev) |
823 | { |
824 | struct ata_host *host = dev_get_drvdata(dev); |
825 | struct ahci_host_priv *hpriv = host->private_data; |
826 | void __iomem *mmio = hpriv->mmio; |
827 | u32 ctl; |
828 | |
829 | if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { |
830 | dev_err(dev, "firmware update required for suspend/resume\n" ); |
831 | return -EIO; |
832 | } |
833 | |
834 | /* |
835 | * AHCI spec rev1.1 section 8.3.3: |
836 | * Software must disable interrupts prior to requesting a |
837 | * transition of the HBA to D3 state. |
838 | */ |
839 | ctl = readl(addr: mmio + HOST_CTL); |
840 | ctl &= ~HOST_IRQ_EN; |
841 | writel(val: ctl, addr: mmio + HOST_CTL); |
842 | readl(addr: mmio + HOST_CTL); /* flush */ |
843 | |
844 | if (hpriv->flags & AHCI_HFLAG_SUSPEND_PHYS) |
845 | ahci_platform_disable_phys(hpriv); |
846 | |
847 | ata_host_suspend(host, PMSG_SUSPEND); |
848 | return 0; |
849 | } |
850 | EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); |
851 | |
852 | /** |
853 | * ahci_platform_resume_host - Resume an ahci-platform host |
854 | * @dev: device pointer for the host |
855 | * |
856 | * This function does all the usual steps needed to resume an ahci-platform |
857 | * host, note any necessary resources (ie clks, phys, etc.) must be |
858 | * initialized / enabled before calling this. |
859 | * |
860 | * RETURNS: |
861 | * 0 on success otherwise a negative error code |
862 | */ |
863 | int ahci_platform_resume_host(struct device *dev) |
864 | { |
865 | struct ata_host *host = dev_get_drvdata(dev); |
866 | struct ahci_host_priv *hpriv = host->private_data; |
867 | int rc; |
868 | |
869 | if (dev->power.power_state.event == PM_EVENT_SUSPEND) { |
870 | rc = ahci_reset_controller(host); |
871 | if (rc) |
872 | return rc; |
873 | |
874 | ahci_init_controller(host); |
875 | } |
876 | |
877 | if (hpriv->flags & AHCI_HFLAG_SUSPEND_PHYS) |
878 | ahci_platform_enable_phys(hpriv); |
879 | |
880 | ata_host_resume(host); |
881 | |
882 | return 0; |
883 | } |
884 | EXPORT_SYMBOL_GPL(ahci_platform_resume_host); |
885 | |
886 | /** |
887 | * ahci_platform_suspend - Suspend an ahci-platform device |
888 | * @dev: the platform device to suspend |
889 | * |
890 | * This function suspends the host associated with the device, followed by |
891 | * disabling all the resources of the device. |
892 | * |
893 | * RETURNS: |
894 | * 0 on success otherwise a negative error code |
895 | */ |
896 | int ahci_platform_suspend(struct device *dev) |
897 | { |
898 | struct ata_host *host = dev_get_drvdata(dev); |
899 | struct ahci_host_priv *hpriv = host->private_data; |
900 | int rc; |
901 | |
902 | rc = ahci_platform_suspend_host(dev); |
903 | if (rc) |
904 | return rc; |
905 | |
906 | ahci_platform_disable_resources(hpriv); |
907 | |
908 | return 0; |
909 | } |
910 | EXPORT_SYMBOL_GPL(ahci_platform_suspend); |
911 | |
912 | /** |
913 | * ahci_platform_resume - Resume an ahci-platform device |
914 | * @dev: the platform device to resume |
915 | * |
916 | * This function enables all the resources of the device followed by |
917 | * resuming the host associated with the device. |
918 | * |
919 | * RETURNS: |
920 | * 0 on success otherwise a negative error code |
921 | */ |
922 | int ahci_platform_resume(struct device *dev) |
923 | { |
924 | struct ata_host *host = dev_get_drvdata(dev); |
925 | struct ahci_host_priv *hpriv = host->private_data; |
926 | int rc; |
927 | |
928 | rc = ahci_platform_enable_resources(hpriv); |
929 | if (rc) |
930 | return rc; |
931 | |
932 | rc = ahci_platform_resume_host(dev); |
933 | if (rc) |
934 | goto disable_resources; |
935 | |
936 | /* We resumed so update PM runtime state */ |
937 | pm_runtime_disable(dev); |
938 | pm_runtime_set_active(dev); |
939 | pm_runtime_enable(dev); |
940 | |
941 | return 0; |
942 | |
943 | disable_resources: |
944 | ahci_platform_disable_resources(hpriv); |
945 | |
946 | return rc; |
947 | } |
948 | EXPORT_SYMBOL_GPL(ahci_platform_resume); |
949 | #endif |
950 | |
951 | MODULE_DESCRIPTION("AHCI SATA platform library" ); |
952 | MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>" ); |
953 | MODULE_LICENSE("GPL" ); |
954 | |