xref: /freebsd/sys/arm/freescale/imx/imx6_ahci.c (revision dfc016587a1e11191676c42672aeeee5eb8cd64b)
1854519fdSIan Lepore /*-
2854519fdSIan Lepore  * Copyright (c) 2017 Rogiel Sulzbach <rogiel@allogica.com>
3854519fdSIan Lepore  * All rights reserved.
4854519fdSIan Lepore  *
5854519fdSIan Lepore  * Redistribution and use in source and binary forms, with or without
6854519fdSIan Lepore  * modification, are permitted provided that the following conditions
7854519fdSIan Lepore  * are met:
8854519fdSIan Lepore  * 1. Redistributions of source code must retain the above copyright
9854519fdSIan Lepore  *    notice, this list of conditions and the following disclaimer.
10854519fdSIan Lepore  * 2. Redistributions in binary form must reproduce the above copyright
11854519fdSIan Lepore  *    notice, this list of conditions and the following disclaimer in the
12854519fdSIan Lepore  *    documentation and/or other materials provided with the distribution.
13854519fdSIan Lepore  *
14854519fdSIan Lepore  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15854519fdSIan Lepore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16854519fdSIan Lepore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17854519fdSIan Lepore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18854519fdSIan Lepore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19854519fdSIan Lepore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20854519fdSIan Lepore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21854519fdSIan Lepore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22854519fdSIan Lepore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23854519fdSIan Lepore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24854519fdSIan Lepore  * SUCH DAMAGE.
25854519fdSIan Lepore  */
26854519fdSIan Lepore 
27854519fdSIan Lepore 
28854519fdSIan Lepore #include <sys/param.h>
29854519fdSIan Lepore #include <sys/systm.h>
30854519fdSIan Lepore #include <sys/bus.h>
31854519fdSIan Lepore #include <sys/rman.h>
32854519fdSIan Lepore #include <sys/kernel.h>
33854519fdSIan Lepore #include <sys/module.h>
34854519fdSIan Lepore 
35854519fdSIan Lepore #include <machine/bus.h>
36854519fdSIan Lepore #include <dev/ofw/ofw_bus.h>
37854519fdSIan Lepore #include <dev/ofw/ofw_bus_subr.h>
38854519fdSIan Lepore 
39854519fdSIan Lepore #include <dev/ahci/ahci.h>
40854519fdSIan Lepore #include <arm/freescale/imx/imx_iomuxreg.h>
41854519fdSIan Lepore #include <arm/freescale/imx/imx_iomuxvar.h>
42854519fdSIan Lepore #include <arm/freescale/imx/imx_ccmvar.h>
43854519fdSIan Lepore 
44854519fdSIan Lepore #define	SATA_TIMER1MS				0x000000e0
45854519fdSIan Lepore 
46854519fdSIan Lepore #define	SATA_P0PHYCR				0x00000178
47854519fdSIan Lepore #define	  SATA_P0PHYCR_CR_READ			  (1 << 19)
48854519fdSIan Lepore #define	  SATA_P0PHYCR_CR_WRITE			  (1 << 18)
49854519fdSIan Lepore #define	  SATA_P0PHYCR_CR_CAP_DATA		  (1 << 17)
50854519fdSIan Lepore #define	  SATA_P0PHYCR_CR_CAP_ADDR		  (1 << 16)
51854519fdSIan Lepore #define	  SATA_P0PHYCR_CR_DATA_IN(v)		  ((v) & 0xffff)
52854519fdSIan Lepore 
53854519fdSIan Lepore #define	SATA_P0PHYSR				0x0000017c
54854519fdSIan Lepore #define	  SATA_P0PHYSR_CR_ACK			  (1 << 18)
55854519fdSIan Lepore #define	  SATA_P0PHYSR_CR_DATA_OUT(v)		  ((v) & 0xffff)
56854519fdSIan Lepore 
57854519fdSIan Lepore /* phy registers */
58854519fdSIan Lepore #define	SATA_PHY_CLOCK_RESET			0x7f3f
59854519fdSIan Lepore #define	  SATA_PHY_CLOCK_RESET_RST		  (1 << 0)
60854519fdSIan Lepore 
61854519fdSIan Lepore #define	SATA_PHY_LANE0_OUT_STAT			0x2003
62854519fdSIan Lepore #define	  SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE	  (1 << 1)
63854519fdSIan Lepore 
64cf2cec68SIan Lepore static struct ofw_compat_data compat_data[] = {
65cf2cec68SIan Lepore 	{"fsl,imx6q-ahci", true},
66cf2cec68SIan Lepore 	{NULL,             false}
67cf2cec68SIan Lepore };
68cf2cec68SIan Lepore 
69854519fdSIan Lepore static int
imx6_ahci_phy_ctrl(struct ahci_controller * sc,uint32_t bitmask,bool on)70854519fdSIan Lepore imx6_ahci_phy_ctrl(struct ahci_controller* sc, uint32_t bitmask, bool on)
71854519fdSIan Lepore {
72854519fdSIan Lepore 	uint32_t v;
73854519fdSIan Lepore 	int timeout;
74854519fdSIan Lepore 	bool state;
75854519fdSIan Lepore 
76854519fdSIan Lepore 	v = ATA_INL(sc->r_mem, SATA_P0PHYCR);
77854519fdSIan Lepore 	if (on) {
78854519fdSIan Lepore 		v |= bitmask;
79854519fdSIan Lepore 	} else {
80854519fdSIan Lepore 		v &= ~bitmask;
81854519fdSIan Lepore 	}
82854519fdSIan Lepore 	ATA_OUTL(sc->r_mem, SATA_P0PHYCR, v);
83854519fdSIan Lepore 
84854519fdSIan Lepore 	for (timeout = 5000; timeout > 0; --timeout) {
85854519fdSIan Lepore 		v = ATA_INL(sc->r_mem, SATA_P0PHYSR);
86854519fdSIan Lepore 		state = (v & SATA_P0PHYSR_CR_ACK) == SATA_P0PHYSR_CR_ACK;
87854519fdSIan Lepore 		if(state == on) {
88854519fdSIan Lepore 			break;
89854519fdSIan Lepore 		}
90854519fdSIan Lepore 		DELAY(100);
91854519fdSIan Lepore 	}
92854519fdSIan Lepore 
93854519fdSIan Lepore 	if (timeout > 0) {
94854519fdSIan Lepore 		return (0);
95854519fdSIan Lepore 	}
96854519fdSIan Lepore 
97854519fdSIan Lepore 	return (ETIMEDOUT);
98854519fdSIan Lepore }
99854519fdSIan Lepore 
100854519fdSIan Lepore static int
imx6_ahci_phy_addr(struct ahci_controller * sc,uint32_t addr)101854519fdSIan Lepore imx6_ahci_phy_addr(struct ahci_controller* sc, uint32_t addr)
102854519fdSIan Lepore {
103854519fdSIan Lepore 	int error;
104854519fdSIan Lepore 
105854519fdSIan Lepore 	DELAY(100);
106854519fdSIan Lepore 
107854519fdSIan Lepore 	ATA_OUTL(sc->r_mem, SATA_P0PHYCR, addr);
108854519fdSIan Lepore 
109854519fdSIan Lepore 	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, true);
110854519fdSIan Lepore 	if (error != 0) {
111854519fdSIan Lepore 		device_printf(sc->dev,
112854519fdSIan Lepore 		    "%s: timeout on SATA_P0PHYCR_CR_CAP_ADDR=1\n",
113854519fdSIan Lepore 		    __FUNCTION__);
114854519fdSIan Lepore 		return (error);
115854519fdSIan Lepore 	}
116854519fdSIan Lepore 
117854519fdSIan Lepore 	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, false);
118854519fdSIan Lepore 	if (error != 0) {
119854519fdSIan Lepore 		device_printf(sc->dev,
120854519fdSIan Lepore 		    "%s: timeout on SATA_P0PHYCR_CR_CAP_ADDR=0\n",
121854519fdSIan Lepore 		    __FUNCTION__);
122854519fdSIan Lepore 		return (error);
123854519fdSIan Lepore 	}
124854519fdSIan Lepore 
125854519fdSIan Lepore 	return (0);
126854519fdSIan Lepore }
127854519fdSIan Lepore 
128854519fdSIan Lepore static int
imx6_ahci_phy_write(struct ahci_controller * sc,uint32_t addr,uint16_t data)129854519fdSIan Lepore imx6_ahci_phy_write(struct ahci_controller* sc, uint32_t addr,
130854519fdSIan Lepore 		    uint16_t data)
131854519fdSIan Lepore {
132854519fdSIan Lepore 	int error;
133854519fdSIan Lepore 
134854519fdSIan Lepore 	error = imx6_ahci_phy_addr(sc, addr);
135854519fdSIan Lepore 	if (error != 0) {
136854519fdSIan Lepore 		device_printf(sc->dev, "%s: error on imx6_ahci_phy_addr\n",
137854519fdSIan Lepore 		    __FUNCTION__);
138854519fdSIan Lepore 		return (error);
139854519fdSIan Lepore 	}
140854519fdSIan Lepore 
141854519fdSIan Lepore 	ATA_OUTL(sc->r_mem, SATA_P0PHYCR, data);
142854519fdSIan Lepore 
143854519fdSIan Lepore 	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, true);
144854519fdSIan Lepore 	if (error != 0) {
145854519fdSIan Lepore 		device_printf(sc->dev,
146854519fdSIan Lepore 		    "%s: error on SATA_P0PHYCR_CR_CAP_DATA=1\n", __FUNCTION__);
147854519fdSIan Lepore 		return (error);
148854519fdSIan Lepore 	}
149854519fdSIan Lepore 	if (imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, false) != 0) {
150854519fdSIan Lepore 		device_printf(sc->dev,
151854519fdSIan Lepore 		    "%s: error on SATA_P0PHYCR_CR_CAP_DATA=0\n", __FUNCTION__);
152854519fdSIan Lepore 		return (error);
153854519fdSIan Lepore 	}
154854519fdSIan Lepore 
155854519fdSIan Lepore 	if ((addr == SATA_PHY_CLOCK_RESET) && data) {
156854519fdSIan Lepore 		/* we can't check ACK after RESET */
157854519fdSIan Lepore 		ATA_OUTL(sc->r_mem, SATA_P0PHYCR,
158854519fdSIan Lepore 		    SATA_P0PHYCR_CR_DATA_IN(data) | SATA_P0PHYCR_CR_WRITE);
159854519fdSIan Lepore 		return (0);
160854519fdSIan Lepore 	}
161854519fdSIan Lepore 
162854519fdSIan Lepore 	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, true);
163854519fdSIan Lepore 	if (error != 0) {
164854519fdSIan Lepore 		device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_WRITE=1\n",
165854519fdSIan Lepore 		    __FUNCTION__);
166854519fdSIan Lepore 		return (error);
167854519fdSIan Lepore 	}
168854519fdSIan Lepore 
169854519fdSIan Lepore 	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, false);
170854519fdSIan Lepore 	if (error != 0) {
171854519fdSIan Lepore 		device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_WRITE=0\n",
172854519fdSIan Lepore 		    __FUNCTION__);
173854519fdSIan Lepore 		return (error);
174854519fdSIan Lepore 	}
175854519fdSIan Lepore 
176854519fdSIan Lepore 	return (0);
177854519fdSIan Lepore }
178854519fdSIan Lepore 
179854519fdSIan Lepore static int
imx6_ahci_phy_read(struct ahci_controller * sc,uint32_t addr,uint16_t * val)180854519fdSIan Lepore imx6_ahci_phy_read(struct ahci_controller* sc, uint32_t addr, uint16_t* val)
181854519fdSIan Lepore {
182854519fdSIan Lepore 	int error;
183854519fdSIan Lepore 	uint32_t v;
184854519fdSIan Lepore 
185854519fdSIan Lepore 	error = imx6_ahci_phy_addr(sc, addr);
186854519fdSIan Lepore 	if (error != 0) {
187854519fdSIan Lepore 		device_printf(sc->dev, "%s: error on imx6_ahci_phy_addr\n",
188854519fdSIan Lepore 		    __FUNCTION__);
189854519fdSIan Lepore 		return (error);
190854519fdSIan Lepore 	}
191854519fdSIan Lepore 
192854519fdSIan Lepore 	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, true);
193854519fdSIan Lepore 	if (error != 0) {
194854519fdSIan Lepore 		device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_READ=1\n",
195854519fdSIan Lepore 		    __FUNCTION__);
196854519fdSIan Lepore 		return (error);
197854519fdSIan Lepore 	}
198854519fdSIan Lepore 
199854519fdSIan Lepore 	v = ATA_INL(sc->r_mem, SATA_P0PHYSR);
200854519fdSIan Lepore 
201854519fdSIan Lepore 	error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, false);
202854519fdSIan Lepore 	if (error != 0) {
203854519fdSIan Lepore 		device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_READ=0\n",
204854519fdSIan Lepore 		    __FUNCTION__);
205854519fdSIan Lepore 		return (error);
206854519fdSIan Lepore 	}
207854519fdSIan Lepore 
208854519fdSIan Lepore 	*val = SATA_P0PHYSR_CR_DATA_OUT(v);
209854519fdSIan Lepore 	return (0);
210854519fdSIan Lepore }
211854519fdSIan Lepore 
212854519fdSIan Lepore static int
imx6_ahci_probe(device_t dev)213854519fdSIan Lepore imx6_ahci_probe(device_t dev)
214854519fdSIan Lepore {
215854519fdSIan Lepore 
216854519fdSIan Lepore 	if (!ofw_bus_status_okay(dev)) {
217854519fdSIan Lepore 		return (ENXIO);
218854519fdSIan Lepore 	}
219854519fdSIan Lepore 
220cf2cec68SIan Lepore 	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
221854519fdSIan Lepore 		return (ENXIO);
222854519fdSIan Lepore 	}
223854519fdSIan Lepore 	device_set_desc(dev, "i.MX6 Integrated AHCI controller");
224854519fdSIan Lepore 
225854519fdSIan Lepore 	return (BUS_PROBE_DEFAULT);
226854519fdSIan Lepore }
227854519fdSIan Lepore 
228854519fdSIan Lepore static int
imx6_ahci_attach(device_t dev)229854519fdSIan Lepore imx6_ahci_attach(device_t dev)
230854519fdSIan Lepore {
231854519fdSIan Lepore 	struct ahci_controller* ctlr;
232854519fdSIan Lepore 	uint16_t pllstat;
233854519fdSIan Lepore 	uint32_t v;
234854519fdSIan Lepore 	int error, timeout;
235854519fdSIan Lepore 
236854519fdSIan Lepore 	ctlr = device_get_softc(dev);
237854519fdSIan Lepore 
238854519fdSIan Lepore 	/* Power up the controller and phy. */
239854519fdSIan Lepore 	error = imx6_ccm_sata_enable();
240854519fdSIan Lepore 	if (error != 0) {
241854519fdSIan Lepore 		device_printf(dev, "error enabling controller and phy\n");
242854519fdSIan Lepore 		return (error);
243854519fdSIan Lepore 	}
244854519fdSIan Lepore 
245854519fdSIan Lepore 	ctlr->vendorid = 0;
246854519fdSIan Lepore 	ctlr->deviceid = 0;
247854519fdSIan Lepore 	ctlr->subvendorid = 0;
248854519fdSIan Lepore 	ctlr->subdeviceid = 0;
249854519fdSIan Lepore 	ctlr->numirqs = 1;
250854519fdSIan Lepore 	ctlr->r_rid = 0;
251854519fdSIan Lepore 	if ((ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
252854519fdSIan Lepore 	    &ctlr->r_rid, RF_ACTIVE)) == NULL) {
253854519fdSIan Lepore 		return (ENXIO);
254854519fdSIan Lepore 	}
255854519fdSIan Lepore 
256854519fdSIan Lepore 	v = imx_iomux_gpr_get(IOMUX_GPR13);
257854519fdSIan Lepore 	/* Clear out existing values; these numbers are bitmasks. */
258854519fdSIan Lepore 	v &= ~(IOMUX_GPR13_SATA_PHY_8(7) 	|
259854519fdSIan Lepore 	       IOMUX_GPR13_SATA_PHY_7(0x1f) 	|
260854519fdSIan Lepore 	       IOMUX_GPR13_SATA_PHY_6(7) 	|
261854519fdSIan Lepore 	       IOMUX_GPR13_SATA_SPEED(1) 	|
262854519fdSIan Lepore 	       IOMUX_GPR13_SATA_PHY_5(1) 	|
263854519fdSIan Lepore 	       IOMUX_GPR13_SATA_PHY_4(7) 	|
264854519fdSIan Lepore 	       IOMUX_GPR13_SATA_PHY_3(0xf) 	|
265854519fdSIan Lepore 	       IOMUX_GPR13_SATA_PHY_2(0x1f) 	|
266854519fdSIan Lepore 	       IOMUX_GPR13_SATA_PHY_1(1) 	|
267854519fdSIan Lepore 	       IOMUX_GPR13_SATA_PHY_0(1));
268854519fdSIan Lepore 	/* setting */
269854519fdSIan Lepore 	v |= IOMUX_GPR13_SATA_PHY_8(5) 		|     /* Rx 3.0db */
270854519fdSIan Lepore 	     IOMUX_GPR13_SATA_PHY_7(0x12) 	|     /* Rx SATA2m */
271854519fdSIan Lepore 	     IOMUX_GPR13_SATA_PHY_6(3) 		|     /* Rx DPLL mode */
272854519fdSIan Lepore 	     IOMUX_GPR13_SATA_SPEED(1) 		|     /* 3.0GHz */
273854519fdSIan Lepore 	     IOMUX_GPR13_SATA_PHY_5(0) 		|     /* SpreadSpectram */
274854519fdSIan Lepore 	     IOMUX_GPR13_SATA_PHY_4(4) 		|     /* Tx Attenuation 9/16 */
275854519fdSIan Lepore 	     IOMUX_GPR13_SATA_PHY_3(0) 		|     /* Tx Boost 0db */
276854519fdSIan Lepore 	     IOMUX_GPR13_SATA_PHY_2(0x11) 	|     /* Tx Level 1.104V */
277854519fdSIan Lepore 	     IOMUX_GPR13_SATA_PHY_1(1);               /* PLL clock enable */
278854519fdSIan Lepore 	imx_iomux_gpr_set(IOMUX_GPR13, v);
279854519fdSIan Lepore 
280854519fdSIan Lepore 	/* phy reset */
281854519fdSIan Lepore 	error = imx6_ahci_phy_write(ctlr, SATA_PHY_CLOCK_RESET,
282854519fdSIan Lepore 	    SATA_PHY_CLOCK_RESET_RST);
283854519fdSIan Lepore 	if (error != 0) {
284854519fdSIan Lepore 		device_printf(dev, "cannot reset PHY\n");
285854519fdSIan Lepore 		goto fail;
286854519fdSIan Lepore 	}
287854519fdSIan Lepore 
288854519fdSIan Lepore 	for (timeout = 50; timeout > 0; --timeout) {
289854519fdSIan Lepore 		DELAY(100);
290854519fdSIan Lepore 		error = imx6_ahci_phy_read(ctlr, SATA_PHY_LANE0_OUT_STAT,
291854519fdSIan Lepore 		    &pllstat);
292854519fdSIan Lepore 		if (error != 0) {
293854519fdSIan Lepore 			device_printf(dev, "cannot read LANE0 status\n");
294854519fdSIan Lepore 			goto fail;
295854519fdSIan Lepore 		}
296854519fdSIan Lepore 		if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE) {
297854519fdSIan Lepore 			break;
298854519fdSIan Lepore 		}
299854519fdSIan Lepore 	}
300854519fdSIan Lepore 	if (timeout <= 0) {
301854519fdSIan Lepore 		device_printf(dev, "time out reading LANE0 status\n");
302854519fdSIan Lepore 		error = ETIMEDOUT;
303854519fdSIan Lepore 		goto fail;
304854519fdSIan Lepore 	}
305854519fdSIan Lepore 
306854519fdSIan Lepore 	/* Support Staggered Spin-up */
307854519fdSIan Lepore 	v = ATA_INL(ctlr->r_mem, AHCI_CAP);
308854519fdSIan Lepore 	ATA_OUTL(ctlr->r_mem, AHCI_CAP, v | AHCI_CAP_SSS);
309854519fdSIan Lepore 
310854519fdSIan Lepore 	/* Ports Implemented. must set 1 */
311854519fdSIan Lepore 	v = ATA_INL(ctlr->r_mem, AHCI_PI);
312854519fdSIan Lepore 	ATA_OUTL(ctlr->r_mem, AHCI_PI, v | (1 << 0));
313854519fdSIan Lepore 
314854519fdSIan Lepore 	/* set 1ms-timer = AHB clock / 1000 */
315854519fdSIan Lepore 	ATA_OUTL(ctlr->r_mem, SATA_TIMER1MS,
316854519fdSIan Lepore 		 imx_ccm_ahb_hz() / 1000);
317854519fdSIan Lepore 
318854519fdSIan Lepore 	/*
319854519fdSIan Lepore 	 * Note: ahci_attach will release ctlr->r_mem on errors automatically
320854519fdSIan Lepore 	 */
321854519fdSIan Lepore 	return (ahci_attach(dev));
322854519fdSIan Lepore 
323854519fdSIan Lepore fail:
324854519fdSIan Lepore 	bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
325854519fdSIan Lepore 	return (error);
326854519fdSIan Lepore }
327854519fdSIan Lepore 
328854519fdSIan Lepore static int
imx6_ahci_detach(device_t dev)329854519fdSIan Lepore imx6_ahci_detach(device_t dev)
330854519fdSIan Lepore {
331854519fdSIan Lepore 
332854519fdSIan Lepore 	return (ahci_detach(dev));
333854519fdSIan Lepore }
334854519fdSIan Lepore 
335854519fdSIan Lepore static device_method_t imx6_ahci_ata_methods[] = {
336854519fdSIan Lepore 	/* device probe, attach and detach methods */
337854519fdSIan Lepore 	DEVMETHOD(device_probe,  imx6_ahci_probe),
338854519fdSIan Lepore 	DEVMETHOD(device_attach, imx6_ahci_attach),
339854519fdSIan Lepore 	DEVMETHOD(device_detach, imx6_ahci_detach),
340854519fdSIan Lepore 
341854519fdSIan Lepore 	/* ahci bus methods */
342854519fdSIan Lepore 	DEVMETHOD(bus_print_child,        ahci_print_child),
343854519fdSIan Lepore 	DEVMETHOD(bus_alloc_resource,     ahci_alloc_resource),
344854519fdSIan Lepore 	DEVMETHOD(bus_release_resource,   ahci_release_resource),
345854519fdSIan Lepore 	DEVMETHOD(bus_setup_intr,         ahci_setup_intr),
346854519fdSIan Lepore 	DEVMETHOD(bus_teardown_intr,      ahci_teardown_intr),
347ddfc9c4cSWarner Losh 	DEVMETHOD(bus_child_location,	  ahci_child_location),
348854519fdSIan Lepore 
349854519fdSIan Lepore 	DEVMETHOD_END
350854519fdSIan Lepore };
351854519fdSIan Lepore 
352854519fdSIan Lepore static driver_t ahci_ata_driver = {
353854519fdSIan Lepore 	"ahci",
354854519fdSIan Lepore 	imx6_ahci_ata_methods,
355854519fdSIan Lepore 	sizeof(struct ahci_controller)
356854519fdSIan Lepore };
357854519fdSIan Lepore 
358*23802d41SJohn Baldwin DRIVER_MODULE(imx6_ahci, simplebus, ahci_ata_driver, 0, 0);
359cf2cec68SIan Lepore MODULE_DEPEND(imx6_ahci, ahci, 1, 1, 1);
360cf2cec68SIan Lepore SIMPLEBUS_PNP_INFO(compat_data)
361