0001
0002
0003
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
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
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
0050
0051
0052
0053
0054
0055
0056 WARN((refclk_rate % 10) != 0, "refclk must be divisible by 10");
0057 needed = pll_output / (refclk_rate / 10);
0058
0059
0060
0061
0062
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
0087
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
0102
0103
0104
0105
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
0123
0124
0125
0126
0127
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
0143
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
0176
0177
0178
0179
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
0191
0192
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 { }
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");