blob: 1a50cd3b4233bdf467049f3308c636fe32c0caf4 [file] [log] [blame]
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +01001/*
2 * DaVinci DA850 AHCI SATA platform driver
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 */
9
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/pm.h>
13#include <linux/device.h>
14#include <linux/platform_device.h>
15#include <linux/libata.h>
16#include <linux/ahci_platform.h>
17#include "ahci.h"
18
Bartosz Golaszewskid3d557c2017-01-30 11:02:07 +010019#define DRV_NAME "ahci_da850"
20#define HARDRESET_RETRIES 5
Akinobu Mita018d5ef2015-01-29 08:30:29 +090021
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +010022/* SATA PHY Control Register offset from AHCI base */
23#define SATA_P0PHYCR_REG 0x178
24
25#define SATA_PHY_MPY(x) ((x) << 0)
26#define SATA_PHY_LOS(x) ((x) << 6)
27#define SATA_PHY_RXCDR(x) ((x) << 10)
28#define SATA_PHY_RXEQ(x) ((x) << 13)
29#define SATA_PHY_TXSWING(x) ((x) << 19)
30#define SATA_PHY_ENPLL(x) ((x) << 31)
31
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +010032static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
Bartosz Golaszewskicdf0ead2017-01-30 11:02:08 +010033 void __iomem *ahci_base, u32 mpy)
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +010034{
35 unsigned int val;
36
37 /* Enable SATA clock receiver */
38 val = readl(pwrdn_reg);
39 val &= ~BIT(0);
40 writel(val, pwrdn_reg);
41
Bartosz Golaszewskicdf0ead2017-01-30 11:02:08 +010042 val = SATA_PHY_MPY(mpy) | SATA_PHY_LOS(1) | SATA_PHY_RXCDR(4) |
43 SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) | SATA_PHY_ENPLL(1);
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +010044
45 writel(val, ahci_base + SATA_P0PHYCR_REG);
46}
47
Bartosz Golaszewskicdf0ead2017-01-30 11:02:08 +010048static u32 ahci_da850_calculate_mpy(unsigned long refclk_rate)
49{
50 u32 pll_output = 1500000000, needed;
51
52 /*
53 * We need to determine the value of the multiplier (MPY) bits.
54 * In order to include the 12.5 multiplier we need to first divide
55 * the refclk rate by ten.
56 *
57 * __div64_32() turned out to be unreliable, sometimes returning
58 * false results.
59 */
60 WARN((refclk_rate % 10) != 0, "refclk must be divisible by 10");
61 needed = pll_output / (refclk_rate / 10);
62
63 /*
64 * What we have now is (multiplier * 10).
65 *
66 * Let's determine the actual register value we need to write.
67 */
68
69 switch (needed) {
70 case 50:
71 return 0x1;
72 case 60:
73 return 0x2;
74 case 80:
75 return 0x4;
76 case 100:
77 return 0x5;
78 case 120:
79 return 0x6;
80 case 125:
81 return 0x7;
82 case 150:
83 return 0x8;
84 case 200:
85 return 0x9;
86 case 250:
87 return 0xa;
88 default:
89 /*
90 * We should have divided evenly - if not, return an invalid
91 * value.
92 */
93 return 0;
94 }
95}
96
Bartosz Golaszewskif4d435f2017-01-30 11:02:05 +010097static int ahci_da850_softreset(struct ata_link *link,
98 unsigned int *class, unsigned long deadline)
99{
100 int pmp, ret;
101
102 pmp = sata_srst_pmp(link);
103
104 /*
105 * There's an issue with the SATA controller on da850 SoCs: if we
106 * enable Port Multiplier support, but the drive is connected directly
107 * to the board, it can't be detected. As a workaround: if PMP is
108 * enabled, we first call ahci_do_softreset() and pass it the result of
109 * sata_srst_pmp(). If this call fails, we retry with pmp = 0.
110 */
111 ret = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
112 if (pmp && ret == -EBUSY)
113 return ahci_do_softreset(link, class, 0,
114 deadline, ahci_check_ready);
115
116 return ret;
117}
118
Bartosz Golaszewskid3d557c2017-01-30 11:02:07 +0100119static int ahci_da850_hardreset(struct ata_link *link,
120 unsigned int *class, unsigned long deadline)
121{
122 int ret, retry = HARDRESET_RETRIES;
123 bool online;
124
125 /*
126 * In order to correctly service the LCD controller of the da850 SoC,
127 * we increased the PLL0 frequency to 456MHz from the default 300MHz.
128 *
129 * This made the SATA controller unstable and the hardreset operation
130 * does not always succeed the first time. Before really giving up to
131 * bring up the link, retry the reset a couple times.
132 */
133 do {
134 ret = ahci_do_hardreset(link, class, deadline, &online);
135 if (online)
136 return ret;
137 } while (retry--);
138
139 return ret;
140}
141
Bartosz Golaszewskif4d435f2017-01-30 11:02:05 +0100142static struct ata_port_operations ahci_da850_port_ops = {
143 .inherits = &ahci_platform_ops,
144 .softreset = ahci_da850_softreset,
145 /*
146 * No need to override .pmp_softreset - it's only used for actual
147 * PMP-enabled ports.
148 */
Bartosz Golaszewskid3d557c2017-01-30 11:02:07 +0100149 .hardreset = ahci_da850_hardreset,
150 .pmp_hardreset = ahci_da850_hardreset,
Bartosz Golaszewskif4d435f2017-01-30 11:02:05 +0100151};
152
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100153static const struct ata_port_info ahci_da850_port_info = {
154 .flags = AHCI_FLAG_COMMON,
155 .pio_mask = ATA_PIO4,
156 .udma_mask = ATA_UDMA6,
Bartosz Golaszewskif4d435f2017-01-30 11:02:05 +0100157 .port_ops = &ahci_da850_port_ops,
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100158};
159
Akinobu Mita018d5ef2015-01-29 08:30:29 +0900160static struct scsi_host_template ahci_platform_sht = {
161 AHCI_SHT(DRV_NAME),
162};
163
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100164static int ahci_da850_probe(struct platform_device *pdev)
165{
166 struct device *dev = &pdev->dev;
167 struct ahci_host_priv *hpriv;
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100168 void __iomem *pwrdn_reg;
Bartosz Golaszewskicdf0ead2017-01-30 11:02:08 +0100169 struct resource *res;
Bartosz Golaszewski82dbe1a2017-01-30 11:02:01 +0100170 struct clk *clk;
Bartosz Golaszewskicdf0ead2017-01-30 11:02:08 +0100171 u32 mpy;
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100172 int rc;
173
174 hpriv = ahci_platform_get_resources(pdev);
175 if (IS_ERR(hpriv))
176 return PTR_ERR(hpriv);
177
Bartosz Golaszewski82dbe1a2017-01-30 11:02:01 +0100178 /*
179 * Internally ahci_platform_get_resources() calls clk_get(dev, NULL)
180 * when trying to obtain the functional clock. This SATA controller
181 * uses two clocks for which we specify two connection ids. If we don't
182 * have the functional clock at this point - call clk_get() again with
183 * con_id = "fck".
184 */
185 if (!hpriv->clks[0]) {
186 clk = clk_get(dev, "fck");
187 if (IS_ERR(clk))
188 return PTR_ERR(clk);
189
190 hpriv->clks[0] = clk;
191 }
192
Bartosz Golaszewskicdf0ead2017-01-30 11:02:08 +0100193 /*
194 * The second clock used by ahci-da850 is the external REFCLK. If we
195 * didn't get it from ahci_platform_get_resources(), let's try to
196 * specify the con_id in clk_get().
197 */
198 if (!hpriv->clks[1]) {
199 clk = clk_get(dev, "refclk");
200 if (IS_ERR(clk)) {
201 dev_err(dev, "unable to obtain the reference clock");
202 return -ENODEV;
203 }
204
205 hpriv->clks[1] = clk;
206 }
207
208 mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
209 if (mpy == 0) {
210 dev_err(dev, "invalid REFCLK multiplier value: 0x%x", mpy);
211 return -EINVAL;
212 }
213
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100214 rc = ahci_platform_enable_resources(hpriv);
215 if (rc)
216 return rc;
217
218 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
219 if (!res)
220 goto disable_resources;
221
222 pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
223 if (!pwrdn_reg)
224 goto disable_resources;
225
Bartosz Golaszewskicdf0ead2017-01-30 11:02:08 +0100226 da850_sata_init(dev, pwrdn_reg, hpriv->mmio, mpy);
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100227
Akinobu Mita018d5ef2015-01-29 08:30:29 +0900228 rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
229 &ahci_platform_sht);
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100230 if (rc)
231 goto disable_resources;
232
233 return 0;
234disable_resources:
235 ahci_platform_disable_resources(hpriv);
236 return rc;
237}
238
239static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend,
240 ahci_platform_resume);
241
Bartosz Golaszewskibf4ae3f2017-01-30 11:02:04 +0100242static const struct of_device_id ahci_da850_of_match[] = {
243 { .compatible = "ti,da850-ahci", },
244 { },
245};
246MODULE_DEVICE_TABLE(of, ahci_da850_of_match);
247
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100248static struct platform_driver ahci_da850_driver = {
249 .probe = ahci_da850_probe,
250 .remove = ata_platform_remove_one,
251 .driver = {
Akinobu Mita018d5ef2015-01-29 08:30:29 +0900252 .name = DRV_NAME,
Bartosz Golaszewskibf4ae3f2017-01-30 11:02:04 +0100253 .of_match_table = ahci_da850_of_match,
Bartlomiej Zolnierkiewiczae8723f2014-03-25 19:51:40 +0100254 .pm = &ahci_da850_pm_ops,
255 },
256};
257module_platform_driver(ahci_da850_driver);
258
259MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver");
260MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>");
261MODULE_LICENSE("GPL");