Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * DaVinci DA850 AHCI SATA platform driver
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/module.h>
0008 #include <linux/pm.h>
0009 #include <linux/device.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/libata.h>
0012 #include <linux/ahci_platform.h>
0013 #include "ahci.h"
0014 
0015 #define DRV_NAME        "ahci_da850"
0016 #define HARDRESET_RETRIES   5
0017 
0018 /* SATA PHY Control Register offset from AHCI base */
0019 #define SATA_P0PHYCR_REG    0x178
0020 
0021 #define SATA_PHY_MPY(x)     ((x) << 0)
0022 #define SATA_PHY_LOS(x)     ((x) << 6)
0023 #define SATA_PHY_RXCDR(x)   ((x) << 10)
0024 #define SATA_PHY_RXEQ(x)    ((x) << 13)
0025 #define SATA_PHY_TXSWING(x) ((x) << 19)
0026 #define SATA_PHY_ENPLL(x)   ((x) << 31)
0027 
0028 static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
0029                 void __iomem *ahci_base, u32 mpy)
0030 {
0031     unsigned int val;
0032 
0033     /* Enable SATA clock receiver */
0034     val = readl(pwrdn_reg);
0035     val &= ~BIT(0);
0036     writel(val, pwrdn_reg);
0037 
0038     val = SATA_PHY_MPY(mpy) | SATA_PHY_LOS(1) | SATA_PHY_RXCDR(4) |
0039           SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) | SATA_PHY_ENPLL(1);
0040 
0041     writel(val, ahci_base + SATA_P0PHYCR_REG);
0042 }
0043 
0044 static u32 ahci_da850_calculate_mpy(unsigned long refclk_rate)
0045 {
0046     u32 pll_output = 1500000000, needed;
0047 
0048     /*
0049      * We need to determine the value of the multiplier (MPY) bits.
0050      * In order to include the 12.5 multiplier we need to first divide
0051      * the refclk rate by ten.
0052      *
0053      * __div64_32() turned out to be unreliable, sometimes returning
0054      * false results.
0055      */
0056     WARN((refclk_rate % 10) != 0, "refclk must be divisible by 10");
0057     needed = pll_output / (refclk_rate / 10);
0058 
0059     /*
0060      * What we have now is (multiplier * 10).
0061      *
0062      * Let's determine the actual register value we need to write.
0063      */
0064 
0065     switch (needed) {
0066     case 50:
0067         return 0x1;
0068     case 60:
0069         return 0x2;
0070     case 80:
0071         return 0x4;
0072     case 100:
0073         return 0x5;
0074     case 120:
0075         return 0x6;
0076     case 125:
0077         return 0x7;
0078     case 150:
0079         return 0x8;
0080     case 200:
0081         return 0x9;
0082     case 250:
0083         return 0xa;
0084     default:
0085         /*
0086          * We should have divided evenly - if not, return an invalid
0087          * value.
0088          */
0089         return 0;
0090     }
0091 }
0092 
0093 static int ahci_da850_softreset(struct ata_link *link,
0094                 unsigned int *class, unsigned long deadline)
0095 {
0096     int pmp, ret;
0097 
0098     pmp = sata_srst_pmp(link);
0099 
0100     /*
0101      * There's an issue with the SATA controller on da850 SoCs: if we
0102      * enable Port Multiplier support, but the drive is connected directly
0103      * to the board, it can't be detected. As a workaround: if PMP is
0104      * enabled, we first call ahci_do_softreset() and pass it the result of
0105      * sata_srst_pmp(). If this call fails, we retry with pmp = 0.
0106      */
0107     ret = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
0108     if (pmp && ret == -EBUSY)
0109         return ahci_do_softreset(link, class, 0,
0110                      deadline, ahci_check_ready);
0111 
0112     return ret;
0113 }
0114 
0115 static int ahci_da850_hardreset(struct ata_link *link,
0116                 unsigned int *class, unsigned long deadline)
0117 {
0118     int ret, retry = HARDRESET_RETRIES;
0119     bool online;
0120 
0121     /*
0122      * In order to correctly service the LCD controller of the da850 SoC,
0123      * we increased the PLL0 frequency to 456MHz from the default 300MHz.
0124      *
0125      * This made the SATA controller unstable and the hardreset operation
0126      * does not always succeed the first time. Before really giving up to
0127      * bring up the link, retry the reset a couple times.
0128      */
0129     do {
0130         ret = ahci_do_hardreset(link, class, deadline, &online);
0131         if (online)
0132             return ret;
0133     } while (retry--);
0134 
0135     return ret;
0136 }
0137 
0138 static struct ata_port_operations ahci_da850_port_ops = {
0139     .inherits = &ahci_platform_ops,
0140     .softreset = ahci_da850_softreset,
0141     /*
0142      * No need to override .pmp_softreset - it's only used for actual
0143      * PMP-enabled ports.
0144      */
0145     .hardreset = ahci_da850_hardreset,
0146     .pmp_hardreset = ahci_da850_hardreset,
0147 };
0148 
0149 static const struct ata_port_info ahci_da850_port_info = {
0150     .flags      = AHCI_FLAG_COMMON,
0151     .pio_mask   = ATA_PIO4,
0152     .udma_mask  = ATA_UDMA6,
0153     .port_ops   = &ahci_da850_port_ops,
0154 };
0155 
0156 static struct scsi_host_template ahci_platform_sht = {
0157     AHCI_SHT(DRV_NAME),
0158 };
0159 
0160 static int ahci_da850_probe(struct platform_device *pdev)
0161 {
0162     struct device *dev = &pdev->dev;
0163     struct ahci_host_priv *hpriv;
0164     void __iomem *pwrdn_reg;
0165     struct resource *res;
0166     struct clk *clk;
0167     u32 mpy;
0168     int rc;
0169 
0170     hpriv = ahci_platform_get_resources(pdev, 0);
0171     if (IS_ERR(hpriv))
0172         return PTR_ERR(hpriv);
0173 
0174     /*
0175      * Internally ahci_platform_get_resources() calls clk_get(dev, NULL)
0176      * when trying to obtain the functional clock. This SATA controller
0177      * uses two clocks for which we specify two connection ids. If we don't
0178      * have the functional clock at this point - call clk_get() again with
0179      * con_id = "fck".
0180      */
0181     if (!hpriv->clks[0]) {
0182         clk = clk_get(dev, "fck");
0183         if (IS_ERR(clk))
0184             return PTR_ERR(clk);
0185 
0186         hpriv->clks[0] = clk;
0187     }
0188 
0189     /*
0190      * The second clock used by ahci-da850 is the external REFCLK. If we
0191      * didn't get it from ahci_platform_get_resources(), let's try to
0192      * specify the con_id in clk_get().
0193      */
0194     if (!hpriv->clks[1]) {
0195         clk = clk_get(dev, "refclk");
0196         if (IS_ERR(clk)) {
0197             dev_err(dev, "unable to obtain the reference clock");
0198             return -ENODEV;
0199         }
0200 
0201         hpriv->clks[1] = clk;
0202     }
0203 
0204     mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
0205     if (mpy == 0) {
0206         dev_err(dev, "invalid REFCLK multiplier value: 0x%x", mpy);
0207         return -EINVAL;
0208     }
0209 
0210     rc = ahci_platform_enable_resources(hpriv);
0211     if (rc)
0212         return rc;
0213 
0214     res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0215     if (!res) {
0216         rc = -ENODEV;
0217         goto disable_resources;
0218     }
0219 
0220     pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
0221     if (!pwrdn_reg) {
0222         rc = -ENOMEM;
0223         goto disable_resources;
0224     }
0225 
0226     da850_sata_init(dev, pwrdn_reg, hpriv->mmio, mpy);
0227 
0228     rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
0229                      &ahci_platform_sht);
0230     if (rc)
0231         goto disable_resources;
0232 
0233     return 0;
0234 disable_resources:
0235     ahci_platform_disable_resources(hpriv);
0236     return rc;
0237 }
0238 
0239 static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend,
0240              ahci_platform_resume);
0241 
0242 static const struct of_device_id ahci_da850_of_match[] = {
0243     { .compatible = "ti,da850-ahci", },
0244     { /* sentinel */ }
0245 };
0246 MODULE_DEVICE_TABLE(of, ahci_da850_of_match);
0247 
0248 static struct platform_driver ahci_da850_driver = {
0249     .probe = ahci_da850_probe,
0250     .remove = ata_platform_remove_one,
0251     .driver = {
0252         .name = DRV_NAME,
0253         .of_match_table = ahci_da850_of_match,
0254         .pm = &ahci_da850_pm_ops,
0255     },
0256 };
0257 module_platform_driver(ahci_da850_driver);
0258 
0259 MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver");
0260 MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>");
0261 MODULE_LICENSE("GPL");