]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/ata/ahci_da850.c
ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t
[mirror_ubuntu-artful-kernel.git] / drivers / ata / ahci_da850.c
1 /*
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
19 #define DRV_NAME "ahci_da850"
20 #define HARDRESET_RETRIES 5
21
22 /* 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
32 static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
33 void __iomem *ahci_base, u32 mpy)
34 {
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
42 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);
44
45 writel(val, ahci_base + SATA_P0PHYCR_REG);
46 }
47
48 static 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
97 static 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
119 static 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
142 static 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 */
149 .hardreset = ahci_da850_hardreset,
150 .pmp_hardreset = ahci_da850_hardreset,
151 };
152
153 static const struct ata_port_info ahci_da850_port_info = {
154 .flags = AHCI_FLAG_COMMON,
155 .pio_mask = ATA_PIO4,
156 .udma_mask = ATA_UDMA6,
157 .port_ops = &ahci_da850_port_ops,
158 };
159
160 static struct scsi_host_template ahci_platform_sht = {
161 AHCI_SHT(DRV_NAME),
162 };
163
164 static int ahci_da850_probe(struct platform_device *pdev)
165 {
166 struct device *dev = &pdev->dev;
167 struct ahci_host_priv *hpriv;
168 void __iomem *pwrdn_reg;
169 struct resource *res;
170 struct clk *clk;
171 u32 mpy;
172 int rc;
173
174 hpriv = ahci_platform_get_resources(pdev);
175 if (IS_ERR(hpriv))
176 return PTR_ERR(hpriv);
177
178 /*
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
193 /*
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
214 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 rc = -ENODEV;
221 goto disable_resources;
222 }
223
224 pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
225 if (!pwrdn_reg) {
226 rc = -ENOMEM;
227 goto disable_resources;
228 }
229
230 da850_sata_init(dev, pwrdn_reg, hpriv->mmio, mpy);
231
232 rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
233 &ahci_platform_sht);
234 if (rc)
235 goto disable_resources;
236
237 return 0;
238 disable_resources:
239 ahci_platform_disable_resources(hpriv);
240 return rc;
241 }
242
243 static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend,
244 ahci_platform_resume);
245
246 static const struct of_device_id ahci_da850_of_match[] = {
247 { .compatible = "ti,da850-ahci", },
248 { },
249 };
250 MODULE_DEVICE_TABLE(of, ahci_da850_of_match);
251
252 static struct platform_driver ahci_da850_driver = {
253 .probe = ahci_da850_probe,
254 .remove = ata_platform_remove_one,
255 .driver = {
256 .name = DRV_NAME,
257 .of_match_table = ahci_da850_of_match,
258 .pm = &ahci_da850_pm_ops,
259 },
260 };
261 module_platform_driver(ahci_da850_driver);
262
263 MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver");
264 MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>");
265 MODULE_LICENSE("GPL");