Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * MediaTek AHCI SATA driver
0004  *
0005  * Copyright (c) 2017 MediaTek Inc.
0006  * Author: Ryder Lee <ryder.lee@mediatek.com>
0007  */
0008 
0009 #include <linux/ahci_platform.h>
0010 #include <linux/kernel.h>
0011 #include <linux/libata.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/pm.h>
0016 #include <linux/regmap.h>
0017 #include <linux/reset.h>
0018 #include "ahci.h"
0019 
0020 #define DRV_NAME        "ahci-mtk"
0021 
0022 #define SYS_CFG         0x14
0023 #define SYS_CFG_SATA_MSK    GENMASK(31, 30)
0024 #define SYS_CFG_SATA_EN     BIT(31)
0025 
0026 struct mtk_ahci_plat {
0027     struct regmap *mode;
0028     struct reset_control *axi_rst;
0029     struct reset_control *sw_rst;
0030     struct reset_control *reg_rst;
0031 };
0032 
0033 static const struct ata_port_info ahci_port_info = {
0034     .flags      = AHCI_FLAG_COMMON,
0035     .pio_mask   = ATA_PIO4,
0036     .udma_mask  = ATA_UDMA6,
0037     .port_ops   = &ahci_platform_ops,
0038 };
0039 
0040 static struct scsi_host_template ahci_platform_sht = {
0041     AHCI_SHT(DRV_NAME),
0042 };
0043 
0044 static int mtk_ahci_platform_resets(struct ahci_host_priv *hpriv,
0045                     struct device *dev)
0046 {
0047     struct mtk_ahci_plat *plat = hpriv->plat_data;
0048     int err;
0049 
0050     /* reset AXI bus and PHY part */
0051     plat->axi_rst = devm_reset_control_get_optional_exclusive(dev, "axi");
0052     if (PTR_ERR(plat->axi_rst) == -EPROBE_DEFER)
0053         return PTR_ERR(plat->axi_rst);
0054 
0055     plat->sw_rst = devm_reset_control_get_optional_exclusive(dev, "sw");
0056     if (PTR_ERR(plat->sw_rst) == -EPROBE_DEFER)
0057         return PTR_ERR(plat->sw_rst);
0058 
0059     plat->reg_rst = devm_reset_control_get_optional_exclusive(dev, "reg");
0060     if (PTR_ERR(plat->reg_rst) == -EPROBE_DEFER)
0061         return PTR_ERR(plat->reg_rst);
0062 
0063     err = reset_control_assert(plat->axi_rst);
0064     if (err) {
0065         dev_err(dev, "failed to assert AXI bus\n");
0066         return err;
0067     }
0068 
0069     err = reset_control_assert(plat->sw_rst);
0070     if (err) {
0071         dev_err(dev, "failed to assert PHY digital part\n");
0072         return err;
0073     }
0074 
0075     err = reset_control_assert(plat->reg_rst);
0076     if (err) {
0077         dev_err(dev, "failed to assert PHY register part\n");
0078         return err;
0079     }
0080 
0081     err = reset_control_deassert(plat->reg_rst);
0082     if (err) {
0083         dev_err(dev, "failed to deassert PHY register part\n");
0084         return err;
0085     }
0086 
0087     err = reset_control_deassert(plat->sw_rst);
0088     if (err) {
0089         dev_err(dev, "failed to deassert PHY digital part\n");
0090         return err;
0091     }
0092 
0093     err = reset_control_deassert(plat->axi_rst);
0094     if (err) {
0095         dev_err(dev, "failed to deassert AXI bus\n");
0096         return err;
0097     }
0098 
0099     return 0;
0100 }
0101 
0102 static int mtk_ahci_parse_property(struct ahci_host_priv *hpriv,
0103                    struct device *dev)
0104 {
0105     struct mtk_ahci_plat *plat = hpriv->plat_data;
0106     struct device_node *np = dev->of_node;
0107 
0108     /* enable SATA function if needed */
0109     if (of_find_property(np, "mediatek,phy-mode", NULL)) {
0110         plat->mode = syscon_regmap_lookup_by_phandle(
0111                     np, "mediatek,phy-mode");
0112         if (IS_ERR(plat->mode)) {
0113             dev_err(dev, "missing phy-mode phandle\n");
0114             return PTR_ERR(plat->mode);
0115         }
0116 
0117         regmap_update_bits(plat->mode, SYS_CFG, SYS_CFG_SATA_MSK,
0118                    SYS_CFG_SATA_EN);
0119     }
0120 
0121     of_property_read_u32(np, "ports-implemented", &hpriv->force_port_map);
0122 
0123     return 0;
0124 }
0125 
0126 static int mtk_ahci_probe(struct platform_device *pdev)
0127 {
0128     struct device *dev = &pdev->dev;
0129     struct mtk_ahci_plat *plat;
0130     struct ahci_host_priv *hpriv;
0131     int err;
0132 
0133     plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
0134     if (!plat)
0135         return -ENOMEM;
0136 
0137     hpriv = ahci_platform_get_resources(pdev, 0);
0138     if (IS_ERR(hpriv))
0139         return PTR_ERR(hpriv);
0140 
0141     hpriv->plat_data = plat;
0142 
0143     err = mtk_ahci_parse_property(hpriv, dev);
0144     if (err)
0145         return err;
0146 
0147     err = mtk_ahci_platform_resets(hpriv, dev);
0148     if (err)
0149         return err;
0150 
0151     err = ahci_platform_enable_resources(hpriv);
0152     if (err)
0153         return err;
0154 
0155     err = ahci_platform_init_host(pdev, hpriv, &ahci_port_info,
0156                       &ahci_platform_sht);
0157     if (err)
0158         goto disable_resources;
0159 
0160     return 0;
0161 
0162 disable_resources:
0163     ahci_platform_disable_resources(hpriv);
0164     return err;
0165 }
0166 
0167 static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
0168              ahci_platform_resume);
0169 
0170 static const struct of_device_id ahci_of_match[] = {
0171     { .compatible = "mediatek,mtk-ahci", },
0172     { /* sentinel */ }
0173 };
0174 MODULE_DEVICE_TABLE(of, ahci_of_match);
0175 
0176 static struct platform_driver mtk_ahci_driver = {
0177     .probe = mtk_ahci_probe,
0178     .remove = ata_platform_remove_one,
0179     .driver = {
0180         .name = DRV_NAME,
0181         .of_match_table = ahci_of_match,
0182         .pm = &ahci_pm_ops,
0183     },
0184 };
0185 module_platform_driver(mtk_ahci_driver);
0186 
0187 MODULE_DESCRIPTION("MediaTek SATA AHCI Driver");
0188 MODULE_LICENSE("GPL v2");