xref: /openbmc/linux/drivers/ata/ahci_da850.c (revision d2ba09c1)
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");
266