xref: /openbsd-src/sys/arch/armv7/imx/imxahci.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: imxahci.c,v 1.7 2016/08/04 15:52:52 kettenis Exp $ */
2 /*
3  * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/buf.h>
21 #include <sys/kernel.h>
22 #include <sys/malloc.h>
23 #include <sys/device.h>
24 #include <sys/queue.h>
25 
26 #include <machine/bus.h>
27 #include <machine/fdt.h>
28 
29 #include <dev/ic/ahcireg.h>
30 #include <dev/ic/ahcivar.h>
31 
32 #include <armv7/armv7/armv7var.h>
33 #include <armv7/imx/imxccmvar.h>
34 #include <armv7/imx/imxiomuxcvar.h>
35 
36 #include <dev/ofw/openfirm.h>
37 #include <dev/ofw/fdt.h>
38 
39 /* registers */
40 #define SATA_CAP		0x000
41 #define SATA_GHC		0x004
42 #define SATA_IS			0x008
43 #define SATA_PI			0x00C
44 #define SATA_VS			0x010
45 #define SATA_CCC_CTL		0x014
46 #define SATA_CCC_PORTS		0x018
47 #define SATA_CAP2		0x024
48 #define SATA_BISTAFR		0x0A0
49 #define SATA_BISTCR		0x0A4
50 #define SATA_BISTFCTR		0x0A8
51 #define SATA_BSTSR		0x0AC
52 #define SATA_OOBR		0x0BC
53 #define SATA_GPCR		0x0D0
54 #define SATA_GPSR		0x0D4
55 #define SATA_TIMER1MS		0x0E0
56 #define SATA_TESTR		0x0F4
57 #define SATA_VERSIONR		0x0F8
58 #define SATA_P0CLB		0x100
59 #define SATA_P0FB		0x108
60 #define SATA_P0IS		0x110
61 #define SATA_P0IE		0x114
62 #define SATA_P0CMD		0x118
63 #define SATA_P0TFD		0x120
64 #define SATA_P0SIG		0x124
65 #define SATA_P0SSTS		0x128
66 #define SATA_P0SCTL		0x12C
67 #define SATA_P0SERR		0x130
68 #define SATA_P0SACT		0x134
69 #define SATA_P0CI		0x138
70 #define SATA_P0SNTF		0x13C
71 #define SATA_P0DMACR		0x170
72 #define SATA_P0PHYCR		0x178
73 #define SATA_P0PHYSR		0x17C
74 
75 #define SATA_CAP_SSS		(1 << 27)
76 #define SATA_GHC_HR		(1 << 0)
77 #define SATA_P0PHYCR_TEST_PDDQ	(1 << 20)
78 
79 int	imxahci_match(struct device *, void *, void *);
80 void	imxahci_attach(struct device *, struct device *, void *);
81 int	imxahci_detach(struct device *, int);
82 int	imxahci_activate(struct device *, int);
83 
84 extern int ahci_intr(void *);
85 
86 struct imxahci_softc {
87 	struct ahci_softc	sc;
88 };
89 
90 struct cfattach imxahci_ca = {
91 	sizeof(struct imxahci_softc),
92 	imxahci_match,
93 	imxahci_attach,
94 	imxahci_detach,
95 	imxahci_activate
96 };
97 
98 struct cfdriver imxahci_cd = {
99 	NULL, "imxahci", DV_DULL
100 };
101 
102 int
103 imxahci_match(struct device *parent, void *match, void *aux)
104 {
105 	struct fdt_attach_args *faa = aux;
106 
107 	return OF_is_compatible(faa->fa_node, "fsl,imx6q-ahci");
108 }
109 
110 void
111 imxahci_attach(struct device *parent, struct device *self, void *aux)
112 {
113 	struct imxahci_softc *imxsc = (struct imxahci_softc *) self;
114 	struct ahci_softc *sc = &imxsc->sc;
115 	struct fdt_attach_args *faa = aux;
116 	uint32_t timeout = 0x100000;
117 
118 	if (faa->fa_nreg < 1)
119 		return;
120 
121 	sc->sc_iot = faa->fa_iot;
122 	sc->sc_ios = faa->fa_reg[0].size;
123 	sc->sc_dmat = faa->fa_dmat;
124 
125 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
126 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
127 		panic("imxahci_attach: bus_space_map failed!");
128 
129 	sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
130 	    ahci_intr, sc, sc->sc_dev.dv_xname);
131 	if (sc->sc_ih == NULL) {
132 		printf(": unable to establish interrupt\n");
133 		goto unmap;
134 	}
135 
136 	/* power it up */
137 	imxccm_enable_sata();
138 	delay(100);
139 
140 	/* power phy up */
141 	imxiomuxc_enable_sata();
142 
143 	/* setup */
144 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR,
145 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR) & ~SATA_P0PHYCR_TEST_PDDQ);
146 
147 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_GHC, SATA_GHC_HR);
148 
149 	while (!bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_VERSIONR));
150 
151 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP,
152 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP) | SATA_CAP_SSS);
153 
154 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, 1);
155 
156 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS, imxccm_get_ahbclk());
157 
158 	while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0SSTS) & 0xF) && timeout--);
159 
160 	printf(":");
161 
162 	if (ahci_attach(sc) != 0) {
163 		/* error printed by ahci_attach */
164 		goto irq;
165 	}
166 
167 	return;
168 irq:
169 	arm_intr_disestablish(sc->sc_ih);
170 unmap:
171 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
172 }
173 
174 int
175 imxahci_detach(struct device *self, int flags)
176 {
177 	struct imxahci_softc *imxsc = (struct imxahci_softc *) self;
178 	struct ahci_softc *sc = &imxsc->sc;
179 
180 	ahci_detach(sc, flags);
181 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
182 	return 0;
183 }
184 
185 int
186 imxahci_activate(struct device *self, int act)
187 {
188 	struct imxahci_softc *imxsc = (struct imxahci_softc *) self;
189 	struct ahci_softc *sc = &imxsc->sc;
190 
191 	return ahci_activate((struct device *)sc, act);
192 }
193