Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * AHCI SATA platform library
0004  *
0005  * Copyright 2004-2005  Red Hat, Inc.
0006  *   Jeff Garzik <jgarzik@pobox.com>
0007  * Copyright 2010  MontaVista Software, LLC.
0008  *   Anton Vorontsov <avorontsov@ru.mvista.com>
0009  */
0010 
0011 #include <linux/clk.h>
0012 #include <linux/kernel.h>
0013 #include <linux/gfp.h>
0014 #include <linux/module.h>
0015 #include <linux/pm.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/device.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/libata.h>
0020 #include <linux/ahci_platform.h>
0021 #include <linux/phy/phy.h>
0022 #include <linux/pm_runtime.h>
0023 #include <linux/of_platform.h>
0024 #include <linux/reset.h>
0025 #include "ahci.h"
0026 
0027 static void ahci_host_stop(struct ata_host *host);
0028 
0029 struct ata_port_operations ahci_platform_ops = {
0030     .inherits   = &ahci_ops,
0031     .host_stop  = ahci_host_stop,
0032 };
0033 EXPORT_SYMBOL_GPL(ahci_platform_ops);
0034 
0035 /**
0036  * ahci_platform_enable_phys - Enable PHYs
0037  * @hpriv: host private area to store config values
0038  *
0039  * This function enables all the PHYs found in hpriv->phys, if any.
0040  * If a PHY fails to be enabled, it disables all the PHYs already
0041  * enabled in reverse order and returns an error.
0042  *
0043  * RETURNS:
0044  * 0 on success otherwise a negative error code
0045  */
0046 int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
0047 {
0048     int rc, i;
0049 
0050     for (i = 0; i < hpriv->nports; i++) {
0051         rc = phy_init(hpriv->phys[i]);
0052         if (rc)
0053             goto disable_phys;
0054 
0055         rc = phy_set_mode(hpriv->phys[i], PHY_MODE_SATA);
0056         if (rc) {
0057             phy_exit(hpriv->phys[i]);
0058             goto disable_phys;
0059         }
0060 
0061         rc = phy_power_on(hpriv->phys[i]);
0062         if (rc) {
0063             phy_exit(hpriv->phys[i]);
0064             goto disable_phys;
0065         }
0066     }
0067 
0068     return 0;
0069 
0070 disable_phys:
0071     while (--i >= 0) {
0072         phy_power_off(hpriv->phys[i]);
0073         phy_exit(hpriv->phys[i]);
0074     }
0075     return rc;
0076 }
0077 EXPORT_SYMBOL_GPL(ahci_platform_enable_phys);
0078 
0079 /**
0080  * ahci_platform_disable_phys - Disable PHYs
0081  * @hpriv: host private area to store config values
0082  *
0083  * This function disables all PHYs found in hpriv->phys.
0084  */
0085 void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
0086 {
0087     int i;
0088 
0089     for (i = 0; i < hpriv->nports; i++) {
0090         phy_power_off(hpriv->phys[i]);
0091         phy_exit(hpriv->phys[i]);
0092     }
0093 }
0094 EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
0095 
0096 /**
0097  * ahci_platform_enable_clks - Enable platform clocks
0098  * @hpriv: host private area to store config values
0099  *
0100  * This function enables all the clks found in hpriv->clks, starting at
0101  * index 0. If any clk fails to enable it disables all the clks already
0102  * enabled in reverse order, and then returns an error.
0103  *
0104  * RETURNS:
0105  * 0 on success otherwise a negative error code
0106  */
0107 int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
0108 {
0109     int c, rc;
0110 
0111     for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
0112         rc = clk_prepare_enable(hpriv->clks[c]);
0113         if (rc)
0114             goto disable_unprepare_clk;
0115     }
0116     return 0;
0117 
0118 disable_unprepare_clk:
0119     while (--c >= 0)
0120         clk_disable_unprepare(hpriv->clks[c]);
0121     return rc;
0122 }
0123 EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
0124 
0125 /**
0126  * ahci_platform_disable_clks - Disable platform clocks
0127  * @hpriv: host private area to store config values
0128  *
0129  * This function disables all the clks found in hpriv->clks, in reverse
0130  * order of ahci_platform_enable_clks (starting at the end of the array).
0131  */
0132 void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
0133 {
0134     int c;
0135 
0136     for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
0137         if (hpriv->clks[c])
0138             clk_disable_unprepare(hpriv->clks[c]);
0139 }
0140 EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
0141 
0142 /**
0143  * ahci_platform_enable_regulators - Enable regulators
0144  * @hpriv: host private area to store config values
0145  *
0146  * This function enables all the regulators found in controller and
0147  * hpriv->target_pwrs, if any.  If a regulator fails to be enabled, it
0148  * disables all the regulators already enabled in reverse order and
0149  * returns an error.
0150  *
0151  * RETURNS:
0152  * 0 on success otherwise a negative error code
0153  */
0154 int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv)
0155 {
0156     int rc, i;
0157 
0158     rc = regulator_enable(hpriv->ahci_regulator);
0159     if (rc)
0160         return rc;
0161 
0162     rc = regulator_enable(hpriv->phy_regulator);
0163     if (rc)
0164         goto disable_ahci_pwrs;
0165 
0166     for (i = 0; i < hpriv->nports; i++) {
0167         if (!hpriv->target_pwrs[i])
0168             continue;
0169 
0170         rc = regulator_enable(hpriv->target_pwrs[i]);
0171         if (rc)
0172             goto disable_target_pwrs;
0173     }
0174 
0175     return 0;
0176 
0177 disable_target_pwrs:
0178     while (--i >= 0)
0179         if (hpriv->target_pwrs[i])
0180             regulator_disable(hpriv->target_pwrs[i]);
0181 
0182     regulator_disable(hpriv->phy_regulator);
0183 disable_ahci_pwrs:
0184     regulator_disable(hpriv->ahci_regulator);
0185     return rc;
0186 }
0187 EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
0188 
0189 /**
0190  * ahci_platform_disable_regulators - Disable regulators
0191  * @hpriv: host private area to store config values
0192  *
0193  * This function disables all regulators found in hpriv->target_pwrs and
0194  * AHCI controller.
0195  */
0196 void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
0197 {
0198     int i;
0199 
0200     for (i = 0; i < hpriv->nports; i++) {
0201         if (!hpriv->target_pwrs[i])
0202             continue;
0203         regulator_disable(hpriv->target_pwrs[i]);
0204     }
0205 
0206     regulator_disable(hpriv->ahci_regulator);
0207     regulator_disable(hpriv->phy_regulator);
0208 }
0209 EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
0210 /**
0211  * ahci_platform_enable_resources - Enable platform resources
0212  * @hpriv: host private area to store config values
0213  *
0214  * This function enables all ahci_platform managed resources in the
0215  * following order:
0216  * 1) Regulator
0217  * 2) Clocks (through ahci_platform_enable_clks)
0218  * 3) Resets
0219  * 4) Phys
0220  *
0221  * If resource enabling fails at any point the previous enabled resources
0222  * are disabled in reverse order.
0223  *
0224  * RETURNS:
0225  * 0 on success otherwise a negative error code
0226  */
0227 int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
0228 {
0229     int rc;
0230 
0231     rc = ahci_platform_enable_regulators(hpriv);
0232     if (rc)
0233         return rc;
0234 
0235     rc = ahci_platform_enable_clks(hpriv);
0236     if (rc)
0237         goto disable_regulator;
0238 
0239     rc = reset_control_deassert(hpriv->rsts);
0240     if (rc)
0241         goto disable_clks;
0242 
0243     rc = ahci_platform_enable_phys(hpriv);
0244     if (rc)
0245         goto disable_resets;
0246 
0247     return 0;
0248 
0249 disable_resets:
0250     reset_control_assert(hpriv->rsts);
0251 
0252 disable_clks:
0253     ahci_platform_disable_clks(hpriv);
0254 
0255 disable_regulator:
0256     ahci_platform_disable_regulators(hpriv);
0257 
0258     return rc;
0259 }
0260 EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
0261 
0262 /**
0263  * ahci_platform_disable_resources - Disable platform resources
0264  * @hpriv: host private area to store config values
0265  *
0266  * This function disables all ahci_platform managed resources in the
0267  * following order:
0268  * 1) Phys
0269  * 2) Resets
0270  * 3) Clocks (through ahci_platform_disable_clks)
0271  * 4) Regulator
0272  */
0273 void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
0274 {
0275     ahci_platform_disable_phys(hpriv);
0276 
0277     reset_control_assert(hpriv->rsts);
0278 
0279     ahci_platform_disable_clks(hpriv);
0280 
0281     ahci_platform_disable_regulators(hpriv);
0282 }
0283 EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
0284 
0285 static void ahci_platform_put_resources(struct device *dev, void *res)
0286 {
0287     struct ahci_host_priv *hpriv = res;
0288     int c;
0289 
0290     if (hpriv->got_runtime_pm) {
0291         pm_runtime_put_sync(dev);
0292         pm_runtime_disable(dev);
0293     }
0294 
0295     for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
0296         clk_put(hpriv->clks[c]);
0297     /*
0298      * The regulators are tied to child node device and not to the
0299      * SATA device itself. So we can't use devm for automatically
0300      * releasing them. We have to do it manually here.
0301      */
0302     for (c = 0; c < hpriv->nports; c++)
0303         if (hpriv->target_pwrs && hpriv->target_pwrs[c])
0304             regulator_put(hpriv->target_pwrs[c]);
0305 
0306     kfree(hpriv->target_pwrs);
0307 }
0308 
0309 static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port,
0310                 struct device *dev, struct device_node *node)
0311 {
0312     int rc;
0313 
0314     hpriv->phys[port] = devm_of_phy_get(dev, node, NULL);
0315 
0316     if (!IS_ERR(hpriv->phys[port]))
0317         return 0;
0318 
0319     rc = PTR_ERR(hpriv->phys[port]);
0320     switch (rc) {
0321     case -ENOSYS:
0322         /* No PHY support. Check if PHY is required. */
0323         if (of_find_property(node, "phys", NULL)) {
0324             dev_err(dev,
0325                 "couldn't get PHY in node %pOFn: ENOSYS\n",
0326                 node);
0327             break;
0328         }
0329         fallthrough;
0330     case -ENODEV:
0331         /* continue normally */
0332         hpriv->phys[port] = NULL;
0333         rc = 0;
0334         break;
0335     case -EPROBE_DEFER:
0336         /* Do not complain yet */
0337         break;
0338 
0339     default:
0340         dev_err(dev,
0341             "couldn't get PHY in node %pOFn: %d\n",
0342             node, rc);
0343 
0344         break;
0345     }
0346 
0347     return rc;
0348 }
0349 
0350 static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
0351                 struct device *dev)
0352 {
0353     struct regulator *target_pwr;
0354     int rc = 0;
0355 
0356     target_pwr = regulator_get(dev, "target");
0357 
0358     if (!IS_ERR(target_pwr))
0359         hpriv->target_pwrs[port] = target_pwr;
0360     else
0361         rc = PTR_ERR(target_pwr);
0362 
0363     return rc;
0364 }
0365 
0366 /**
0367  * ahci_platform_get_resources - Get platform resources
0368  * @pdev: platform device to get resources for
0369  * @flags: bitmap representing the resource to get
0370  *
0371  * This function allocates an ahci_host_priv struct, and gets the following
0372  * resources, storing a reference to them inside the returned struct:
0373  *
0374  * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
0375  * 2) regulator for controlling the targets power (optional)
0376  *    regulator for controlling the AHCI controller (optional)
0377  * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
0378  *    or for non devicetree enabled platforms a single clock
0379  * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
0380  * 5) phys (optional)
0381  *
0382  * RETURNS:
0383  * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
0384  */
0385 struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
0386                            unsigned int flags)
0387 {
0388     struct device *dev = &pdev->dev;
0389     struct ahci_host_priv *hpriv;
0390     struct clk *clk;
0391     struct device_node *child;
0392     int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
0393     u32 mask_port_map = 0;
0394 
0395     if (!devres_open_group(dev, NULL, GFP_KERNEL))
0396         return ERR_PTR(-ENOMEM);
0397 
0398     hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
0399                  GFP_KERNEL);
0400     if (!hpriv)
0401         goto err_out;
0402 
0403     devres_add(dev, hpriv);
0404 
0405     hpriv->mmio = devm_ioremap_resource(dev,
0406                   platform_get_resource(pdev, IORESOURCE_MEM, 0));
0407     if (IS_ERR(hpriv->mmio)) {
0408         rc = PTR_ERR(hpriv->mmio);
0409         goto err_out;
0410     }
0411 
0412     for (i = 0; i < AHCI_MAX_CLKS; i++) {
0413         /*
0414          * For now we must use clk_get(dev, NULL) for the first clock,
0415          * because some platforms (da850, spear13xx) are not yet
0416          * converted to use devicetree for clocks.  For new platforms
0417          * this is equivalent to of_clk_get(dev->of_node, 0).
0418          */
0419         if (i == 0)
0420             clk = clk_get(dev, NULL);
0421         else
0422             clk = of_clk_get(dev->of_node, i);
0423 
0424         if (IS_ERR(clk)) {
0425             rc = PTR_ERR(clk);
0426             if (rc == -EPROBE_DEFER)
0427                 goto err_out;
0428             break;
0429         }
0430         hpriv->clks[i] = clk;
0431     }
0432 
0433     hpriv->ahci_regulator = devm_regulator_get(dev, "ahci");
0434     if (IS_ERR(hpriv->ahci_regulator)) {
0435         rc = PTR_ERR(hpriv->ahci_regulator);
0436         if (rc != 0)
0437             goto err_out;
0438     }
0439 
0440     hpriv->phy_regulator = devm_regulator_get(dev, "phy");
0441     if (IS_ERR(hpriv->phy_regulator)) {
0442         rc = PTR_ERR(hpriv->phy_regulator);
0443         goto err_out;
0444     }
0445 
0446     if (flags & AHCI_PLATFORM_GET_RESETS) {
0447         hpriv->rsts = devm_reset_control_array_get_optional_shared(dev);
0448         if (IS_ERR(hpriv->rsts)) {
0449             rc = PTR_ERR(hpriv->rsts);
0450             goto err_out;
0451         }
0452     }
0453 
0454     hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
0455 
0456     /*
0457      * If no sub-node was found, we still need to set nports to
0458      * one in order to be able to use the
0459      * ahci_platform_[en|dis]able_[phys|regulators] functions.
0460      */
0461     if (!child_nodes)
0462         hpriv->nports = 1;
0463 
0464     hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
0465     if (!hpriv->phys) {
0466         rc = -ENOMEM;
0467         goto err_out;
0468     }
0469     /*
0470      * We cannot use devm_ here, since ahci_platform_put_resources() uses
0471      * target_pwrs after devm_ have freed memory
0472      */
0473     hpriv->target_pwrs = kcalloc(hpriv->nports, sizeof(*hpriv->target_pwrs), GFP_KERNEL);
0474     if (!hpriv->target_pwrs) {
0475         rc = -ENOMEM;
0476         goto err_out;
0477     }
0478 
0479     if (child_nodes) {
0480         for_each_child_of_node(dev->of_node, child) {
0481             u32 port;
0482             struct platform_device *port_dev __maybe_unused;
0483 
0484             if (!of_device_is_available(child))
0485                 continue;
0486 
0487             if (of_property_read_u32(child, "reg", &port)) {
0488                 rc = -EINVAL;
0489                 of_node_put(child);
0490                 goto err_out;
0491             }
0492 
0493             if (port >= hpriv->nports) {
0494                 dev_warn(dev, "invalid port number %d\n", port);
0495                 continue;
0496             }
0497             mask_port_map |= BIT(port);
0498 
0499 #ifdef CONFIG_OF_ADDRESS
0500             of_platform_device_create(child, NULL, NULL);
0501 
0502             port_dev = of_find_device_by_node(child);
0503 
0504             if (port_dev) {
0505                 rc = ahci_platform_get_regulator(hpriv, port,
0506                                 &port_dev->dev);
0507                 if (rc == -EPROBE_DEFER) {
0508                     of_node_put(child);
0509                     goto err_out;
0510                 }
0511             }
0512 #endif
0513 
0514             rc = ahci_platform_get_phy(hpriv, port, dev, child);
0515             if (rc) {
0516                 of_node_put(child);
0517                 goto err_out;
0518             }
0519 
0520             enabled_ports++;
0521         }
0522         if (!enabled_ports) {
0523             dev_warn(dev, "No port enabled\n");
0524             rc = -ENODEV;
0525             goto err_out;
0526         }
0527 
0528         if (!hpriv->mask_port_map)
0529             hpriv->mask_port_map = mask_port_map;
0530     } else {
0531         /*
0532          * If no sub-node was found, keep this for device tree
0533          * compatibility
0534          */
0535         rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node);
0536         if (rc)
0537             goto err_out;
0538 
0539         rc = ahci_platform_get_regulator(hpriv, 0, dev);
0540         if (rc == -EPROBE_DEFER)
0541             goto err_out;
0542     }
0543     pm_runtime_enable(dev);
0544     pm_runtime_get_sync(dev);
0545     hpriv->got_runtime_pm = true;
0546 
0547     devres_remove_group(dev, NULL);
0548     return hpriv;
0549 
0550 err_out:
0551     devres_release_group(dev, NULL);
0552     return ERR_PTR(rc);
0553 }
0554 EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
0555 
0556 /**
0557  * ahci_platform_init_host - Bring up an ahci-platform host
0558  * @pdev: platform device pointer for the host
0559  * @hpriv: ahci-host private data for the host
0560  * @pi_template: template for the ata_port_info to use
0561  * @sht: scsi_host_template to use when registering
0562  *
0563  * This function does all the usual steps needed to bring up an
0564  * ahci-platform host, note any necessary resources (ie clks, phys, etc.)
0565  * must be initialized / enabled before calling this.
0566  *
0567  * RETURNS:
0568  * 0 on success otherwise a negative error code
0569  */
0570 int ahci_platform_init_host(struct platform_device *pdev,
0571                 struct ahci_host_priv *hpriv,
0572                 const struct ata_port_info *pi_template,
0573                 struct scsi_host_template *sht)
0574 {
0575     struct device *dev = &pdev->dev;
0576     struct ata_port_info pi = *pi_template;
0577     const struct ata_port_info *ppi[] = { &pi, NULL };
0578     struct ata_host *host;
0579     int i, irq, n_ports, rc;
0580 
0581     irq = platform_get_irq(pdev, 0);
0582     if (irq < 0)
0583         return irq;
0584     if (!irq)
0585         return -EINVAL;
0586 
0587     hpriv->irq = irq;
0588 
0589     /* prepare host */
0590     pi.private_data = (void *)(unsigned long)hpriv->flags;
0591 
0592     ahci_save_initial_config(dev, hpriv);
0593 
0594     if (hpriv->cap & HOST_CAP_NCQ)
0595         pi.flags |= ATA_FLAG_NCQ;
0596 
0597     if (hpriv->cap & HOST_CAP_PMP)
0598         pi.flags |= ATA_FLAG_PMP;
0599 
0600     ahci_set_em_messages(hpriv, &pi);
0601 
0602     /* CAP.NP sometimes indicate the index of the last enabled
0603      * port, at other times, that of the last possible port, so
0604      * determining the maximum port number requires looking at
0605      * both CAP.NP and port_map.
0606      */
0607     n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
0608 
0609     host = ata_host_alloc_pinfo(dev, ppi, n_ports);
0610     if (!host)
0611         return -ENOMEM;
0612 
0613     host->private_data = hpriv;
0614 
0615     if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
0616         host->flags |= ATA_HOST_PARALLEL_SCAN;
0617     else
0618         dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
0619 
0620     if (pi.flags & ATA_FLAG_EM)
0621         ahci_reset_em(host);
0622 
0623     for (i = 0; i < host->n_ports; i++) {
0624         struct ata_port *ap = host->ports[i];
0625 
0626         ata_port_desc(ap, "mmio %pR",
0627                   platform_get_resource(pdev, IORESOURCE_MEM, 0));
0628         ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
0629 
0630         /* set enclosure management message type */
0631         if (ap->flags & ATA_FLAG_EM)
0632             ap->em_message_type = hpriv->em_msg_type;
0633 
0634         /* disabled/not-implemented port */
0635         if (!(hpriv->port_map & (1 << i)))
0636             ap->ops = &ata_dummy_port_ops;
0637     }
0638 
0639     if (hpriv->cap & HOST_CAP_64) {
0640         rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
0641         if (rc) {
0642             dev_err(dev, "Failed to enable 64-bit DMA.\n");
0643             return rc;
0644         }
0645     }
0646 
0647     rc = ahci_reset_controller(host);
0648     if (rc)
0649         return rc;
0650 
0651     ahci_init_controller(host);
0652     ahci_print_info(host, "platform");
0653 
0654     return ahci_host_activate(host, sht);
0655 }
0656 EXPORT_SYMBOL_GPL(ahci_platform_init_host);
0657 
0658 static void ahci_host_stop(struct ata_host *host)
0659 {
0660     struct ahci_host_priv *hpriv = host->private_data;
0661 
0662     ahci_platform_disable_resources(hpriv);
0663 }
0664 
0665 /**
0666  * ahci_platform_shutdown - Disable interrupts and stop DMA for host ports
0667  * @pdev: platform device pointer for the host
0668  *
0669  * This function is called during system shutdown and performs the minimal
0670  * deconfiguration required to ensure that an ahci_platform host cannot
0671  * corrupt or otherwise interfere with a new kernel being started with kexec.
0672  */
0673 void ahci_platform_shutdown(struct platform_device *pdev)
0674 {
0675     struct ata_host *host = platform_get_drvdata(pdev);
0676     struct ahci_host_priv *hpriv = host->private_data;
0677     void __iomem *mmio = hpriv->mmio;
0678     int i;
0679 
0680     for (i = 0; i < host->n_ports; i++) {
0681         struct ata_port *ap = host->ports[i];
0682 
0683         /* Disable port interrupts */
0684         if (ap->ops->freeze)
0685             ap->ops->freeze(ap);
0686 
0687         /* Stop the port DMA engines */
0688         if (ap->ops->port_stop)
0689             ap->ops->port_stop(ap);
0690     }
0691 
0692     /* Disable and clear host interrupts */
0693     writel(readl(mmio + HOST_CTL) & ~HOST_IRQ_EN, mmio + HOST_CTL);
0694     readl(mmio + HOST_CTL); /* flush */
0695     writel(GENMASK(host->n_ports, 0), mmio + HOST_IRQ_STAT);
0696 }
0697 EXPORT_SYMBOL_GPL(ahci_platform_shutdown);
0698 
0699 #ifdef CONFIG_PM_SLEEP
0700 /**
0701  * ahci_platform_suspend_host - Suspend an ahci-platform host
0702  * @dev: device pointer for the host
0703  *
0704  * This function does all the usual steps needed to suspend an
0705  * ahci-platform host, note any necessary resources (ie clks, phys, etc.)
0706  * must be disabled after calling this.
0707  *
0708  * RETURNS:
0709  * 0 on success otherwise a negative error code
0710  */
0711 int ahci_platform_suspend_host(struct device *dev)
0712 {
0713     struct ata_host *host = dev_get_drvdata(dev);
0714     struct ahci_host_priv *hpriv = host->private_data;
0715     void __iomem *mmio = hpriv->mmio;
0716     u32 ctl;
0717 
0718     if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
0719         dev_err(dev, "firmware update required for suspend/resume\n");
0720         return -EIO;
0721     }
0722 
0723     /*
0724      * AHCI spec rev1.1 section 8.3.3:
0725      * Software must disable interrupts prior to requesting a
0726      * transition of the HBA to D3 state.
0727      */
0728     ctl = readl(mmio + HOST_CTL);
0729     ctl &= ~HOST_IRQ_EN;
0730     writel(ctl, mmio + HOST_CTL);
0731     readl(mmio + HOST_CTL); /* flush */
0732 
0733     if (hpriv->flags & AHCI_HFLAG_SUSPEND_PHYS)
0734         ahci_platform_disable_phys(hpriv);
0735 
0736     ata_host_suspend(host, PMSG_SUSPEND);
0737     return 0;
0738 }
0739 EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
0740 
0741 /**
0742  * ahci_platform_resume_host - Resume an ahci-platform host
0743  * @dev: device pointer for the host
0744  *
0745  * This function does all the usual steps needed to resume an ahci-platform
0746  * host, note any necessary resources (ie clks, phys, etc.)  must be
0747  * initialized / enabled before calling this.
0748  *
0749  * RETURNS:
0750  * 0 on success otherwise a negative error code
0751  */
0752 int ahci_platform_resume_host(struct device *dev)
0753 {
0754     struct ata_host *host = dev_get_drvdata(dev);
0755     struct ahci_host_priv *hpriv = host->private_data;
0756     int rc;
0757 
0758     if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
0759         rc = ahci_reset_controller(host);
0760         if (rc)
0761             return rc;
0762 
0763         ahci_init_controller(host);
0764     }
0765 
0766     if (hpriv->flags & AHCI_HFLAG_SUSPEND_PHYS)
0767         ahci_platform_enable_phys(hpriv);
0768 
0769     ata_host_resume(host);
0770 
0771     return 0;
0772 }
0773 EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
0774 
0775 /**
0776  * ahci_platform_suspend - Suspend an ahci-platform device
0777  * @dev: the platform device to suspend
0778  *
0779  * This function suspends the host associated with the device, followed by
0780  * disabling all the resources of the device.
0781  *
0782  * RETURNS:
0783  * 0 on success otherwise a negative error code
0784  */
0785 int ahci_platform_suspend(struct device *dev)
0786 {
0787     struct ata_host *host = dev_get_drvdata(dev);
0788     struct ahci_host_priv *hpriv = host->private_data;
0789     int rc;
0790 
0791     rc = ahci_platform_suspend_host(dev);
0792     if (rc)
0793         return rc;
0794 
0795     ahci_platform_disable_resources(hpriv);
0796 
0797     return 0;
0798 }
0799 EXPORT_SYMBOL_GPL(ahci_platform_suspend);
0800 
0801 /**
0802  * ahci_platform_resume - Resume an ahci-platform device
0803  * @dev: the platform device to resume
0804  *
0805  * This function enables all the resources of the device followed by
0806  * resuming the host associated with the device.
0807  *
0808  * RETURNS:
0809  * 0 on success otherwise a negative error code
0810  */
0811 int ahci_platform_resume(struct device *dev)
0812 {
0813     struct ata_host *host = dev_get_drvdata(dev);
0814     struct ahci_host_priv *hpriv = host->private_data;
0815     int rc;
0816 
0817     rc = ahci_platform_enable_resources(hpriv);
0818     if (rc)
0819         return rc;
0820 
0821     rc = ahci_platform_resume_host(dev);
0822     if (rc)
0823         goto disable_resources;
0824 
0825     /* We resumed so update PM runtime state */
0826     pm_runtime_disable(dev);
0827     pm_runtime_set_active(dev);
0828     pm_runtime_enable(dev);
0829 
0830     return 0;
0831 
0832 disable_resources:
0833     ahci_platform_disable_resources(hpriv);
0834 
0835     return rc;
0836 }
0837 EXPORT_SYMBOL_GPL(ahci_platform_resume);
0838 #endif
0839 
0840 MODULE_DESCRIPTION("AHCI SATA platform library");
0841 MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
0842 MODULE_LICENSE("GPL");