1 /* $OpenBSD: sxiahci.c,v 1.17 2021/10/24 17:52:28 mpi 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/device.h>
22
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25
26 #include <dev/ic/ahcireg.h>
27 #include <dev/ic/ahcivar.h>
28
29 #include <dev/fdt/sunxireg.h>
30
31 #include <dev/ofw/openfirm.h>
32 #include <dev/ofw/ofw_clock.h>
33 #include <dev/ofw/ofw_regulator.h>
34 #include <dev/ofw/fdt.h>
35
36 #define SXIAHCI_CAP 0x0000
37 #define SXIAHCI_GHC 0x0004
38 #define SXIAHCI_PI 0x000c
39 #define SXIAHCI_PHYCS0 0x00c0
40 #define SXIAHCI_PHYCS1 0x00c4
41 #define SXIAHCI_PHYCS2 0x00c8
42 #define SXIAHCI_TIMER1MS 0x00e0
43 #define SXIAHCI_RWC 0x00fc
44 #define SXIAHCI_TIMEOUT 0x100000
45 #define SXIAHCI_PWRPIN 40
46
47 #define SXIAHCI_PREG_DMA 0x70
48 #define SXIAHCI_PREG_DMA_MASK (0xff<<8)
49 #define SXIAHCI_PREG_DMA_INIT (0x44<<8)
50
51 int sxiahci_match(struct device *, void *, void *);
52 void sxiahci_attach(struct device *, struct device *, void *);
53 int sxiahci_detach(struct device *, int);
54 int sxiahci_activate(struct device *, int);
55 int sxiahci_port_start(struct ahci_port *, int);
56
57 extern int ahci_intr(void *);
58 extern u_int32_t ahci_read(struct ahci_softc *, bus_size_t);
59 extern void ahci_write(struct ahci_softc *, bus_size_t, u_int32_t);
60 extern u_int32_t ahci_pread(struct ahci_port *, bus_size_t);
61 extern void ahci_pwrite(struct ahci_port *, bus_size_t, u_int32_t);
62 extern int ahci_default_port_start(struct ahci_port *, int);
63
64 struct sxiahci_softc {
65 struct ahci_softc sc;
66
67 };
68
69 const struct cfattach sxiahci_ca = {
70 sizeof(struct sxiahci_softc),
71 sxiahci_match,
72 sxiahci_attach,
73 sxiahci_detach,
74 sxiahci_activate
75 };
76
77 struct cfdriver sxiahci_cd = {
78 NULL, "sxiahci", DV_DULL
79 };
80
81 int
sxiahci_match(struct device * parent,void * match,void * aux)82 sxiahci_match(struct device *parent, void *match, void *aux)
83 {
84 struct fdt_attach_args *faa = aux;
85
86 return OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-ahci") ||
87 OF_is_compatible(faa->fa_node, "allwinner,sun8i-r40-ahci");
88 }
89
90 void
sxiahci_attach(struct device * parent,struct device * self,void * aux)91 sxiahci_attach(struct device *parent, struct device *self, void *aux)
92 {
93 struct sxiahci_softc *sxisc = (struct sxiahci_softc *)self;
94 struct ahci_softc *sc = &sxisc->sc;
95 struct fdt_attach_args *faa = aux;
96 uint32_t target_supply;
97 uint32_t timo;
98
99 if (faa->fa_nreg < 1)
100 return;
101
102 sc->sc_iot = faa->fa_iot;
103 sc->sc_ios = faa->fa_reg[0].size;
104 sc->sc_dmat = faa->fa_dmat;
105
106 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
107 faa->fa_reg[0].size, 0, &sc->sc_ioh))
108 panic("sxiahci_attach: bus_space_map failed!");
109
110 /* enable clocks */
111 clock_enable_all(faa->fa_node);
112 delay(5000);
113
114 reset_deassert_all(faa->fa_node);
115
116 /* XXX setup magix */
117 SXIWRITE4(sc, SXIAHCI_RWC, 0);
118 delay(10);
119
120 SXISET4(sc, SXIAHCI_PHYCS1, 1 << 19);
121 delay(10);
122
123 SXICMS4(sc, SXIAHCI_PHYCS0, 7 << 24,
124 1 << 23 | 5 << 24 | 1 << 18);
125 delay(10);
126
127 SXICMS4(sc, SXIAHCI_PHYCS1,
128 3 << 16 | 0x1f << 8 | 3 << 6,
129 2 << 16 | 0x06 << 8 | 2 << 6);
130 delay(10);
131
132 SXISET4(sc, SXIAHCI_PHYCS1, 1 << 28 | 1 << 15);
133 delay(10);
134
135 SXICLR4(sc, SXIAHCI_PHYCS1, 1 << 19);
136 delay(10);
137
138 SXICMS4(sc, SXIAHCI_PHYCS0, 0x07 << 20, 0x03 << 20);
139 SXICMS4(sc, SXIAHCI_PHYCS2, 0x1f << 5, 0x19 << 5);
140 delay(5000);
141
142 SXISET4(sc, SXIAHCI_PHYCS0, 1 << 19);
143 delay(20);
144
145 timo = SXIAHCI_TIMEOUT;
146 while ((SXIREAD4(sc, SXIAHCI_PHYCS0) >> 28 & 7) != 2 && --timo)
147 delay(10);
148 if (!timo) {
149 printf(": AHCI phy power up failed.\n");
150 goto dismod;
151 }
152
153 SXISET4(sc, SXIAHCI_PHYCS2, 1 << 24);
154
155 timo = SXIAHCI_TIMEOUT;
156 while ((SXIREAD4(sc, SXIAHCI_PHYCS2) & (1 << 24)) && --timo)
157 delay(10);
158 if (!timo) {
159 printf(": AHCI phy calibration failed.\n");
160 goto dismod;
161 }
162
163 delay(15000);
164 SXIWRITE4(sc, SXIAHCI_RWC, 7);
165
166 /* power up phy */
167 target_supply = OF_getpropint(faa->fa_node, "target-supply", 0);
168 if (target_supply)
169 regulator_enable(target_supply);
170
171 sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
172 ahci_intr, sc, sc->sc_dev.dv_xname);
173 if (sc->sc_ih == NULL) {
174 printf(": unable to establish interrupt\n");
175 goto clrpwr;
176 }
177
178 printf(":");
179
180 SXIWRITE4(sc, SXIAHCI_PI, 1);
181 SXICLR4(sc, SXIAHCI_CAP, AHCI_REG_CAP_SPM);
182 sc->sc_flags |= AHCI_F_NO_PMP;
183 sc->sc_port_start = sxiahci_port_start;
184 if (ahci_attach(sc) != 0) {
185 /* error printed by ahci_attach */
186 goto irq;
187 }
188
189 return;
190 irq:
191 arm_intr_disestablish(sc->sc_ih);
192 clrpwr:
193 if (target_supply)
194 regulator_disable(target_supply);
195 dismod:
196 clock_disable_all(faa->fa_node);
197 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
198 }
199
200 int
sxiahci_detach(struct device * self,int flags)201 sxiahci_detach(struct device *self, int flags)
202 {
203 struct sxiahci_softc *sxisc = (struct sxiahci_softc *) self;
204 struct ahci_softc *sc = &sxisc->sc;
205
206 ahci_detach(sc, flags);
207 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
208 return 0;
209 }
210
211 int
sxiahci_activate(struct device * self,int act)212 sxiahci_activate(struct device *self, int act)
213 {
214 struct sxiahci_softc *sxisc = (struct sxiahci_softc *) self;
215 struct ahci_softc *sc = &sxisc->sc;
216
217 return ahci_activate((struct device *)sc, act);
218 }
219
220 int
sxiahci_port_start(struct ahci_port * ap,int fre_only)221 sxiahci_port_start(struct ahci_port *ap, int fre_only)
222 {
223 uint32_t r;
224
225 /* Setup DMA */
226 r = ahci_pread(ap, SXIAHCI_PREG_DMA);
227 r &= ~SXIAHCI_PREG_DMA_MASK;
228 r |= SXIAHCI_PREG_DMA_INIT; /* XXX if fre_only? */
229 ahci_pwrite(ap, SXIAHCI_PREG_DMA, r);
230
231 return (ahci_default_port_start(ap, fre_only));
232 }
233