imx6_ahci.c revision 346525
1/*-
2 * Copyright (c) 2017 Rogiel Sulzbach <rogiel@allogica.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28
29__FBSDID("$FreeBSD: stable/11/sys/arm/freescale/imx/imx6_ahci.c 346525 2019-04-22 04:58:01Z ian $");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/bus.h>
34#include <sys/rman.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37
38#include <machine/bus.h>
39#include <dev/ofw/ofw_bus.h>
40#include <dev/ofw/ofw_bus_subr.h>
41
42#include <dev/ahci/ahci.h>
43#include <arm/freescale/imx/imx_iomuxreg.h>
44#include <arm/freescale/imx/imx_iomuxvar.h>
45#include <arm/freescale/imx/imx_ccmvar.h>
46
47#define	SATA_TIMER1MS				0x000000e0
48
49#define	SATA_P0PHYCR				0x00000178
50#define	  SATA_P0PHYCR_CR_READ			  (1 << 19)
51#define	  SATA_P0PHYCR_CR_WRITE			  (1 << 18)
52#define	  SATA_P0PHYCR_CR_CAP_DATA		  (1 << 17)
53#define	  SATA_P0PHYCR_CR_CAP_ADDR		  (1 << 16)
54#define	  SATA_P0PHYCR_CR_DATA_IN(v)		  ((v) & 0xffff)
55
56#define	SATA_P0PHYSR				0x0000017c
57#define	  SATA_P0PHYSR_CR_ACK			  (1 << 18)
58#define	  SATA_P0PHYSR_CR_DATA_OUT(v)		  ((v) & 0xffff)
59
60/* phy registers */
61#define	SATA_PHY_CLOCK_RESET			0x7f3f
62#define	  SATA_PHY_CLOCK_RESET_RST		  (1 << 0)
63
64#define	SATA_PHY_LANE0_OUT_STAT			0x2003
65#define	  SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE	  (1 << 1)
66
67static struct ofw_compat_data compat_data[] = {
68	{"fsl,imx6q-ahci", true},
69	{NULL,             false}
70};
71
72static int
73imx6_ahci_phy_ctrl(struct ahci_controller* sc, uint32_t bitmask, bool on)
74{
75	uint32_t v;
76	int timeout;
77	bool state;
78
79	v = ATA_INL(sc->r_mem, SATA_P0PHYCR);
80	if (on) {
81		v |= bitmask;
82	} else {
83		v &= ~bitmask;
84	}
85	ATA_OUTL(sc->r_mem, SATA_P0PHYCR, v);
86
87	for (timeout = 5000; timeout > 0; --timeout) {
88		v = ATA_INL(sc->r_mem, SATA_P0PHYSR);
89		state = (v & SATA_P0PHYSR_CR_ACK) == SATA_P0PHYSR_CR_ACK;
90		if(state == on) {
91			break;
92		}
93		DELAY(100);
94	}
95
96	if (timeout > 0) {
97		return (0);
98	}
99
100	return (ETIMEDOUT);
101}
102
103static int
104imx6_ahci_phy_addr(struct ahci_controller* sc, uint32_t addr)
105{
106	int error;
107
108	DELAY(100);
109
110	ATA_OUTL(sc->r_mem, SATA_P0PHYCR, addr);
111
112	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, true);
113	if (error != 0) {
114		device_printf(sc->dev,
115		    "%s: timeout on SATA_P0PHYCR_CR_CAP_ADDR=1\n",
116		    __FUNCTION__);
117		return (error);
118	}
119
120	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, false);
121	if (error != 0) {
122		device_printf(sc->dev,
123		    "%s: timeout on SATA_P0PHYCR_CR_CAP_ADDR=0\n",
124		    __FUNCTION__);
125		return (error);
126	}
127
128	return (0);
129}
130
131static int
132imx6_ahci_phy_write(struct ahci_controller* sc, uint32_t addr,
133		    uint16_t data)
134{
135	int error;
136
137	error = imx6_ahci_phy_addr(sc, addr);
138	if (error != 0) {
139		device_printf(sc->dev, "%s: error on imx6_ahci_phy_addr\n",
140		    __FUNCTION__);
141		return (error);
142	}
143
144	ATA_OUTL(sc->r_mem, SATA_P0PHYCR, data);
145
146	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, true);
147	if (error != 0) {
148		device_printf(sc->dev,
149		    "%s: error on SATA_P0PHYCR_CR_CAP_DATA=1\n", __FUNCTION__);
150		return (error);
151	}
152	if (imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, false) != 0) {
153		device_printf(sc->dev,
154		    "%s: error on SATA_P0PHYCR_CR_CAP_DATA=0\n", __FUNCTION__);
155		return (error);
156	}
157
158	if ((addr == SATA_PHY_CLOCK_RESET) && data) {
159		/* we can't check ACK after RESET */
160		ATA_OUTL(sc->r_mem, SATA_P0PHYCR,
161		    SATA_P0PHYCR_CR_DATA_IN(data) | SATA_P0PHYCR_CR_WRITE);
162		return (0);
163	}
164
165	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, true);
166	if (error != 0) {
167		device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_WRITE=1\n",
168		    __FUNCTION__);
169		return (error);
170	}
171
172	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, false);
173	if (error != 0) {
174		device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_WRITE=0\n",
175		    __FUNCTION__);
176		return (error);
177	}
178
179	return (0);
180}
181
182static int
183imx6_ahci_phy_read(struct ahci_controller* sc, uint32_t addr, uint16_t* val)
184{
185	int error;
186	uint32_t v;
187
188	error = imx6_ahci_phy_addr(sc, addr);
189	if (error != 0) {
190		device_printf(sc->dev, "%s: error on imx6_ahci_phy_addr\n",
191		    __FUNCTION__);
192		return (error);
193	}
194
195	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, true);
196	if (error != 0) {
197		device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_READ=1\n",
198		    __FUNCTION__);
199		return (error);
200	}
201
202	v = ATA_INL(sc->r_mem, SATA_P0PHYSR);
203
204	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, false);
205	if (error != 0) {
206		device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_READ=0\n",
207		    __FUNCTION__);
208		return (error);
209	}
210
211	*val = SATA_P0PHYSR_CR_DATA_OUT(v);
212	return (0);
213}
214
215static int
216imx6_ahci_probe(device_t dev)
217{
218
219	if (!ofw_bus_status_okay(dev)) {
220		return (ENXIO);
221	}
222
223	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
224		return (ENXIO);
225	}
226	device_set_desc(dev, "i.MX6 Integrated AHCI controller");
227
228	return (BUS_PROBE_DEFAULT);
229}
230
231static int
232imx6_ahci_attach(device_t dev)
233{
234	struct ahci_controller* ctlr;
235	uint16_t pllstat;
236	uint32_t v;
237	int error, timeout;
238
239	ctlr = device_get_softc(dev);
240
241	/* Power up the controller and phy. */
242	error = imx6_ccm_sata_enable();
243	if (error != 0) {
244		device_printf(dev, "error enabling controller and phy\n");
245		return (error);
246	}
247
248	ctlr->vendorid = 0;
249	ctlr->deviceid = 0;
250	ctlr->subvendorid = 0;
251	ctlr->subdeviceid = 0;
252	ctlr->numirqs = 1;
253	ctlr->r_rid = 0;
254	if ((ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
255	    &ctlr->r_rid, RF_ACTIVE)) == NULL) {
256		return (ENXIO);
257	}
258
259	v = imx_iomux_gpr_get(IOMUX_GPR13);
260	/* Clear out existing values; these numbers are bitmasks. */
261	v &= ~(IOMUX_GPR13_SATA_PHY_8(7) 	|
262	       IOMUX_GPR13_SATA_PHY_7(0x1f) 	|
263	       IOMUX_GPR13_SATA_PHY_6(7) 	|
264	       IOMUX_GPR13_SATA_SPEED(1) 	|
265	       IOMUX_GPR13_SATA_PHY_5(1) 	|
266	       IOMUX_GPR13_SATA_PHY_4(7) 	|
267	       IOMUX_GPR13_SATA_PHY_3(0xf) 	|
268	       IOMUX_GPR13_SATA_PHY_2(0x1f) 	|
269	       IOMUX_GPR13_SATA_PHY_1(1) 	|
270	       IOMUX_GPR13_SATA_PHY_0(1));
271	/* setting */
272	v |= IOMUX_GPR13_SATA_PHY_8(5) 		|     /* Rx 3.0db */
273	     IOMUX_GPR13_SATA_PHY_7(0x12) 	|     /* Rx SATA2m */
274	     IOMUX_GPR13_SATA_PHY_6(3) 		|     /* Rx DPLL mode */
275	     IOMUX_GPR13_SATA_SPEED(1) 		|     /* 3.0GHz */
276	     IOMUX_GPR13_SATA_PHY_5(0) 		|     /* SpreadSpectram */
277	     IOMUX_GPR13_SATA_PHY_4(4) 		|     /* Tx Attenuation 9/16 */
278	     IOMUX_GPR13_SATA_PHY_3(0) 		|     /* Tx Boost 0db */
279	     IOMUX_GPR13_SATA_PHY_2(0x11) 	|     /* Tx Level 1.104V */
280	     IOMUX_GPR13_SATA_PHY_1(1);               /* PLL clock enable */
281	imx_iomux_gpr_set(IOMUX_GPR13, v);
282
283	/* phy reset */
284	error = imx6_ahci_phy_write(ctlr, SATA_PHY_CLOCK_RESET,
285	    SATA_PHY_CLOCK_RESET_RST);
286	if (error != 0) {
287		device_printf(dev, "cannot reset PHY\n");
288		goto fail;
289	}
290
291	for (timeout = 50; timeout > 0; --timeout) {
292		DELAY(100);
293		error = imx6_ahci_phy_read(ctlr, SATA_PHY_LANE0_OUT_STAT,
294		    &pllstat);
295		if (error != 0) {
296			device_printf(dev, "cannot read LANE0 status\n");
297			goto fail;
298		}
299		if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE) {
300			break;
301		}
302	}
303	if (timeout <= 0) {
304		device_printf(dev, "time out reading LANE0 status\n");
305		error = ETIMEDOUT;
306		goto fail;
307	}
308
309	/* Support Staggered Spin-up */
310	v = ATA_INL(ctlr->r_mem, AHCI_CAP);
311	ATA_OUTL(ctlr->r_mem, AHCI_CAP, v | AHCI_CAP_SSS);
312
313	/* Ports Implemented. must set 1 */
314	v = ATA_INL(ctlr->r_mem, AHCI_PI);
315	ATA_OUTL(ctlr->r_mem, AHCI_PI, v | (1 << 0));
316
317	/* set 1ms-timer = AHB clock / 1000 */
318	ATA_OUTL(ctlr->r_mem, SATA_TIMER1MS,
319		 imx_ccm_ahb_hz() / 1000);
320
321	/*
322	 * Note: ahci_attach will release ctlr->r_mem on errors automatically
323	 */
324	return (ahci_attach(dev));
325
326fail:
327	bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
328	return (error);
329}
330
331static int
332imx6_ahci_detach(device_t dev)
333{
334
335	return (ahci_detach(dev));
336}
337
338static device_method_t imx6_ahci_ata_methods[] = {
339	/* device probe, attach and detach methods */
340	DEVMETHOD(device_probe,  imx6_ahci_probe),
341	DEVMETHOD(device_attach, imx6_ahci_attach),
342	DEVMETHOD(device_detach, imx6_ahci_detach),
343
344	/* ahci bus methods */
345	DEVMETHOD(bus_print_child,        ahci_print_child),
346	DEVMETHOD(bus_alloc_resource,     ahci_alloc_resource),
347	DEVMETHOD(bus_release_resource,   ahci_release_resource),
348	DEVMETHOD(bus_setup_intr,         ahci_setup_intr),
349	DEVMETHOD(bus_teardown_intr,      ahci_teardown_intr),
350	DEVMETHOD(bus_child_location_str, ahci_child_location_str),
351
352	DEVMETHOD_END
353};
354
355static driver_t ahci_ata_driver = {
356	"ahci",
357	imx6_ahci_ata_methods,
358	sizeof(struct ahci_controller)
359};
360
361DRIVER_MODULE(imx6_ahci, simplebus, ahci_ata_driver, ahci_devclass, 0, 0);
362MODULE_DEPEND(imx6_ahci, ahci, 1, 1, 1);
363SIMPLEBUS_PNP_INFO(compat_data)
364