xref: /openbsd/sys/arch/armv7/sunxi/sxiahci.c (revision e5dd7070)
1 /*	$OpenBSD: sxiahci.c,v 1.15 2019/08/19 07:27:11 jsg Exp $	*/
2 /*
3  * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
4  * Copyright (c) 2013,2014 Artturi Alm
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/buf.h>
22 #include <sys/kernel.h>
23 #include <sys/malloc.h>
24 #include <sys/device.h>
25 #include <sys/queue.h>
26 
27 #include <machine/bus.h>
28 #include <machine/fdt.h>
29 
30 #include <dev/ic/ahcireg.h>
31 #include <dev/ic/ahcivar.h>
32 
33 #include <dev/fdt/sunxireg.h>
34 
35 #include <dev/ofw/openfirm.h>
36 #include <dev/ofw/ofw_clock.h>
37 #include <dev/ofw/ofw_regulator.h>
38 #include <dev/ofw/fdt.h>
39 
40 #define	SXIAHCI_CAP	0x0000
41 #define	SXIAHCI_GHC	0x0004
42 #define	SXIAHCI_PI	0x000c
43 #define	SXIAHCI_PHYCS0	0x00c0
44 #define	SXIAHCI_PHYCS1	0x00c4
45 #define	SXIAHCI_PHYCS2	0x00c8
46 #define	SXIAHCI_TIMER1MS	0x00e0
47 #define	SXIAHCI_RWC	0x00fc
48 #define	SXIAHCI_TIMEOUT	0x100000
49 #define SXIAHCI_PWRPIN	40
50 
51 #define SXIAHCI_PREG_DMA	0x70
52 #define  SXIAHCI_PREG_DMA_MASK	(0xff<<8)
53 #define  SXIAHCI_PREG_DMA_INIT	(0x44<<8)
54 
55 int	sxiahci_match(struct device *, void *, void *);
56 void	sxiahci_attach(struct device *, struct device *, void *);
57 int	sxiahci_detach(struct device *, int);
58 int	sxiahci_activate(struct device *, int);
59 int	sxiahci_port_start(struct ahci_port *, int);
60 
61 extern int ahci_intr(void *);
62 extern u_int32_t ahci_read(struct ahci_softc *, bus_size_t);
63 extern void ahci_write(struct ahci_softc *, bus_size_t, u_int32_t);
64 extern u_int32_t ahci_pread(struct ahci_port *, bus_size_t);
65 extern void ahci_pwrite(struct ahci_port *, bus_size_t, u_int32_t);
66 extern int ahci_default_port_start(struct ahci_port *, int);
67 
68 struct sxiahci_softc {
69 	struct ahci_softc	sc;
70 
71 };
72 
73 struct cfattach sxiahci_ca = {
74 	sizeof(struct sxiahci_softc),
75 	sxiahci_match,
76 	sxiahci_attach,
77 	sxiahci_detach,
78 	sxiahci_activate
79 };
80 
81 struct cfdriver sxiahci_cd = {
82 	NULL, "sxiahci", DV_DULL
83 };
84 
85 int
86 sxiahci_match(struct device *parent, void *match, void *aux)
87 {
88 	struct fdt_attach_args *faa = aux;
89 
90 	return OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-ahci") ||
91 	    OF_is_compatible(faa->fa_node, "allwinner,sun8i-r40-ahci");
92 }
93 
94 void
95 sxiahci_attach(struct device *parent, struct device *self, void *aux)
96 {
97 	struct sxiahci_softc *sxisc = (struct sxiahci_softc *)self;
98 	struct ahci_softc *sc = &sxisc->sc;
99 	struct fdt_attach_args *faa = aux;
100 	uint32_t target_supply;
101 	uint32_t timo;
102 
103 	if (faa->fa_nreg < 1)
104 		return;
105 
106 	sc->sc_iot = faa->fa_iot;
107 	sc->sc_ios = faa->fa_reg[0].size;
108 	sc->sc_dmat = faa->fa_dmat;
109 
110 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
111 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
112 		panic("sxiahci_attach: bus_space_map failed!");
113 
114 	/* enable clocks */
115 	clock_enable_all(faa->fa_node);
116 	delay(5000);
117 
118 	reset_deassert_all(faa->fa_node);
119 
120 	/* XXX setup magix */
121 	SXIWRITE4(sc, SXIAHCI_RWC, 0);
122 	delay(10);
123 
124 	SXISET4(sc, SXIAHCI_PHYCS1, 1 << 19);
125 	delay(10);
126 
127 	SXICMS4(sc, SXIAHCI_PHYCS0, 7 << 24,
128 	    1 << 23 | 5 << 24 | 1 << 18);
129 	delay(10);
130 
131 	SXICMS4(sc, SXIAHCI_PHYCS1,
132 	    3 << 16 | 0x1f << 8 | 3 << 6,
133 	    2 << 16 | 0x06 << 8 | 2 << 6);
134 	delay(10);
135 
136 	SXISET4(sc, SXIAHCI_PHYCS1, 1 << 28 | 1 << 15);
137 	delay(10);
138 
139 	SXICLR4(sc, SXIAHCI_PHYCS1, 1 << 19);
140 	delay(10);
141 
142 	SXICMS4(sc, SXIAHCI_PHYCS0, 0x07 << 20, 0x03 << 20);
143 	SXICMS4(sc, SXIAHCI_PHYCS2, 0x1f <<  5, 0x19 << 5);
144 	delay(5000);
145 
146 	SXISET4(sc, SXIAHCI_PHYCS0, 1 << 19);
147 	delay(20);
148 
149 	timo = SXIAHCI_TIMEOUT;
150 	while ((SXIREAD4(sc, SXIAHCI_PHYCS0) >> 28 & 7) != 2 && --timo)
151 		delay(10);
152 	if (!timo) {
153 		printf(": AHCI phy power up failed.\n");
154 		goto dismod;
155 	}
156 
157 	SXISET4(sc, SXIAHCI_PHYCS2, 1 << 24);
158 
159 	timo = SXIAHCI_TIMEOUT;
160 	while ((SXIREAD4(sc, SXIAHCI_PHYCS2) & (1 << 24)) && --timo)
161 		delay(10);
162 	if (!timo) {
163 		printf(": AHCI phy calibration failed.\n");
164 		goto dismod;
165 	}
166 
167 	delay(15000);
168 	SXIWRITE4(sc, SXIAHCI_RWC, 7);
169 
170 	/* power up phy */
171 	target_supply = OF_getpropint(faa->fa_node, "target-supply", 0);
172 	if (target_supply)
173 		regulator_enable(target_supply);
174 
175 	sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
176 	    ahci_intr, sc, sc->sc_dev.dv_xname);
177 	if (sc->sc_ih == NULL) {
178 		printf(": unable to establish interrupt\n");
179 		goto clrpwr;
180 	}
181 
182 	printf(":");
183 
184 	SXIWRITE4(sc, SXIAHCI_PI, 1);
185 	SXICLR4(sc, SXIAHCI_CAP, AHCI_REG_CAP_SPM);
186 	sc->sc_flags |= AHCI_F_NO_PMP;
187 	sc->sc_port_start = sxiahci_port_start;
188 	if (ahci_attach(sc) != 0) {
189 		/* error printed by ahci_attach */
190 		goto irq;
191 	}
192 
193 	return;
194 irq:
195 	arm_intr_disestablish(sc->sc_ih);
196 clrpwr:
197 	if (target_supply)
198 		regulator_disable(target_supply);
199 dismod:
200 	clock_disable_all(faa->fa_node);
201 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
202 }
203 
204 int
205 sxiahci_detach(struct device *self, int flags)
206 {
207 	struct sxiahci_softc *sxisc = (struct sxiahci_softc *) self;
208 	struct ahci_softc *sc = &sxisc->sc;
209 
210 	ahci_detach(sc, flags);
211 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
212 	return 0;
213 }
214 
215 int
216 sxiahci_activate(struct device *self, int act)
217 {
218 	struct sxiahci_softc *sxisc = (struct sxiahci_softc *) self;
219 	struct ahci_softc *sc = &sxisc->sc;
220 
221 	return ahci_activate((struct device *)sc, act);
222 }
223 
224 int
225 sxiahci_port_start(struct ahci_port *ap, int fre_only)
226 {
227 	uint32_t r;
228 
229 	/* Setup DMA */
230 	r = ahci_pread(ap, SXIAHCI_PREG_DMA);
231 	r &= ~SXIAHCI_PREG_DMA_MASK;
232 	r |= SXIAHCI_PREG_DMA_INIT; /* XXX if fre_only? */
233 	ahci_pwrite(ap, SXIAHCI_PREG_DMA, r);
234 
235 	return (ahci_default_port_start(ap, fre_only));
236 }
237