Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2012 STMicroelectronics Limited
0004  *
0005  * Authors: Francesco Virlinzi <francesco.virlinzi@st.com>
0006  *      Alexandre Torgue <alexandre.torgue@st.com>
0007  */
0008 
0009 #include <linux/init.h>
0010 #include <linux/module.h>
0011 #include <linux/export.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/clk.h>
0014 #include <linux/of.h>
0015 #include <linux/ahci_platform.h>
0016 #include <linux/libata.h>
0017 #include <linux/reset.h>
0018 #include <linux/io.h>
0019 #include <linux/dma-mapping.h>
0020 
0021 #include "ahci.h"
0022 
0023 #define DRV_NAME  "st_ahci"
0024 
0025 #define ST_AHCI_OOBR            0xbc
0026 #define ST_AHCI_OOBR_WE         BIT(31)
0027 #define ST_AHCI_OOBR_CWMIN_SHIFT    24
0028 #define ST_AHCI_OOBR_CWMAX_SHIFT    16
0029 #define ST_AHCI_OOBR_CIMIN_SHIFT    8
0030 #define ST_AHCI_OOBR_CIMAX_SHIFT    0
0031 
0032 struct st_ahci_drv_data {
0033     struct platform_device *ahci;
0034     struct reset_control *pwr;
0035     struct reset_control *sw_rst;
0036     struct reset_control *pwr_rst;
0037 };
0038 
0039 static void st_ahci_configure_oob(void __iomem *mmio)
0040 {
0041     unsigned long old_val, new_val;
0042 
0043     new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) |
0044           (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) |
0045           (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) |
0046           (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT);
0047 
0048     old_val = readl(mmio + ST_AHCI_OOBR);
0049     writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
0050     writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
0051     writel(new_val, mmio + ST_AHCI_OOBR);
0052 }
0053 
0054 static int st_ahci_deassert_resets(struct ahci_host_priv *hpriv,
0055                 struct device *dev)
0056 {
0057     struct st_ahci_drv_data *drv_data = hpriv->plat_data;
0058     int err;
0059 
0060     if (drv_data->pwr) {
0061         err = reset_control_deassert(drv_data->pwr);
0062         if (err) {
0063             dev_err(dev, "unable to bring out of pwrdwn\n");
0064             return err;
0065         }
0066     }
0067 
0068     if (drv_data->sw_rst) {
0069         err = reset_control_deassert(drv_data->sw_rst);
0070         if (err) {
0071             dev_err(dev, "unable to bring out of sw-rst\n");
0072             return err;
0073         }
0074     }
0075 
0076     if (drv_data->pwr_rst) {
0077         err = reset_control_deassert(drv_data->pwr_rst);
0078         if (err) {
0079             dev_err(dev, "unable to bring out of pwr-rst\n");
0080             return err;
0081         }
0082     }
0083 
0084     return 0;
0085 }
0086 
0087 static void st_ahci_host_stop(struct ata_host *host)
0088 {
0089     struct ahci_host_priv *hpriv = host->private_data;
0090     struct st_ahci_drv_data *drv_data = hpriv->plat_data;
0091     struct device *dev = host->dev;
0092     int err;
0093 
0094     if (drv_data->pwr) {
0095         err = reset_control_assert(drv_data->pwr);
0096         if (err)
0097             dev_err(dev, "unable to pwrdwn\n");
0098     }
0099 
0100     ahci_platform_disable_resources(hpriv);
0101 }
0102 
0103 static int st_ahci_probe_resets(struct ahci_host_priv *hpriv,
0104                 struct device *dev)
0105 {
0106     struct st_ahci_drv_data *drv_data = hpriv->plat_data;
0107 
0108     drv_data->pwr = devm_reset_control_get(dev, "pwr-dwn");
0109     if (IS_ERR(drv_data->pwr)) {
0110         dev_info(dev, "power reset control not defined\n");
0111         drv_data->pwr = NULL;
0112     }
0113 
0114     drv_data->sw_rst = devm_reset_control_get(dev, "sw-rst");
0115     if (IS_ERR(drv_data->sw_rst)) {
0116         dev_info(dev, "soft reset control not defined\n");
0117         drv_data->sw_rst = NULL;
0118     }
0119 
0120     drv_data->pwr_rst = devm_reset_control_get(dev, "pwr-rst");
0121     if (IS_ERR(drv_data->pwr_rst)) {
0122         dev_dbg(dev, "power soft reset control not defined\n");
0123         drv_data->pwr_rst = NULL;
0124     }
0125 
0126     return st_ahci_deassert_resets(hpriv, dev);
0127 }
0128 
0129 static struct ata_port_operations st_ahci_port_ops = {
0130     .inherits   = &ahci_platform_ops,
0131     .host_stop  = st_ahci_host_stop,
0132 };
0133 
0134 static const struct ata_port_info st_ahci_port_info = {
0135     .flags          = AHCI_FLAG_COMMON,
0136     .pio_mask       = ATA_PIO4,
0137     .udma_mask      = ATA_UDMA6,
0138     .port_ops       = &st_ahci_port_ops,
0139 };
0140 
0141 static struct scsi_host_template ahci_platform_sht = {
0142     AHCI_SHT(DRV_NAME),
0143 };
0144 
0145 static int st_ahci_probe(struct platform_device *pdev)
0146 {
0147     struct device *dev = &pdev->dev;
0148     struct st_ahci_drv_data *drv_data;
0149     struct ahci_host_priv *hpriv;
0150     int err;
0151 
0152     drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
0153     if (!drv_data)
0154         return -ENOMEM;
0155 
0156     hpriv = ahci_platform_get_resources(pdev, 0);
0157     if (IS_ERR(hpriv))
0158         return PTR_ERR(hpriv);
0159     hpriv->plat_data = drv_data;
0160 
0161     err = st_ahci_probe_resets(hpriv, &pdev->dev);
0162     if (err)
0163         return err;
0164 
0165     err = ahci_platform_enable_resources(hpriv);
0166     if (err)
0167         return err;
0168 
0169     st_ahci_configure_oob(hpriv->mmio);
0170 
0171     of_property_read_u32(dev->of_node,
0172                  "ports-implemented", &hpriv->force_port_map);
0173 
0174     err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
0175                       &ahci_platform_sht);
0176     if (err) {
0177         ahci_platform_disable_resources(hpriv);
0178         return err;
0179     }
0180 
0181     return 0;
0182 }
0183 
0184 #ifdef CONFIG_PM_SLEEP
0185 static int st_ahci_suspend(struct device *dev)
0186 {
0187     struct ata_host *host = dev_get_drvdata(dev);
0188     struct ahci_host_priv *hpriv = host->private_data;
0189     struct st_ahci_drv_data *drv_data = hpriv->plat_data;
0190     int err;
0191 
0192     err = ahci_platform_suspend_host(dev);
0193     if (err)
0194         return err;
0195 
0196     if (drv_data->pwr) {
0197         err = reset_control_assert(drv_data->pwr);
0198         if (err) {
0199             dev_err(dev, "unable to pwrdwn");
0200             return err;
0201         }
0202     }
0203 
0204     ahci_platform_disable_resources(hpriv);
0205 
0206     return 0;
0207 }
0208 
0209 static int st_ahci_resume(struct device *dev)
0210 {
0211     struct ata_host *host = dev_get_drvdata(dev);
0212     struct ahci_host_priv *hpriv = host->private_data;
0213     int err;
0214 
0215     err = ahci_platform_enable_resources(hpriv);
0216     if (err)
0217         return err;
0218 
0219     err = st_ahci_deassert_resets(hpriv, dev);
0220     if (err) {
0221         ahci_platform_disable_resources(hpriv);
0222         return err;
0223     }
0224 
0225     st_ahci_configure_oob(hpriv->mmio);
0226 
0227     return ahci_platform_resume_host(dev);
0228 }
0229 #endif
0230 
0231 static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume);
0232 
0233 static const struct of_device_id st_ahci_match[] = {
0234     { .compatible = "st,ahci", },
0235     { /* sentinel */ }
0236 };
0237 MODULE_DEVICE_TABLE(of, st_ahci_match);
0238 
0239 static struct platform_driver st_ahci_driver = {
0240     .driver = {
0241         .name = DRV_NAME,
0242         .pm = &st_ahci_pm_ops,
0243         .of_match_table = of_match_ptr(st_ahci_match),
0244     },
0245     .probe = st_ahci_probe,
0246     .remove = ata_platform_remove_one,
0247 };
0248 module_platform_driver(st_ahci_driver);
0249 
0250 MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");
0251 MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>");
0252 MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver");
0253 MODULE_LICENSE("GPL v2");