xref: /openbsd-src/sys/arch/armv7/sunxi/sxiahci.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD	*/
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 
28 #include <dev/ic/ahcireg.h>
29 #include <dev/ic/ahcivar.h>
30 
31 #include <armv7/armv7/armv7var.h>
32 #include <armv7/sunxi/sunxireg.h>
33 #include <armv7/sunxi/sxiccmuvar.h>
34 #include <armv7/sunxi/sxipiovar.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 void	sxiahci_attach(struct device *, struct device *, void *);
48 int	sxiahci_detach(struct device *, int);
49 int	sxiahci_activate(struct device *, int);
50 
51 extern int ahci_intr(void *);
52 extern u_int32_t ahci_read(struct ahci_softc *, bus_size_t);
53 extern void ahci_write(struct ahci_softc *, bus_size_t, u_int32_t);
54 
55 struct sxiahci_softc {
56 	struct ahci_softc	sc;
57 
58 };
59 
60 struct cfattach sxiahci_ca = {
61 	sizeof(struct sxiahci_softc),
62 	NULL,
63 	sxiahci_attach,
64 	sxiahci_detach,
65 	sxiahci_activate
66 };
67 
68 struct cfdriver sxiahci_cd = {
69 	NULL, "ahci", DV_DULL
70 };
71 
72 void
73 sxiahci_attach(struct device *parent, struct device *self, void *args)
74 {
75 	struct armv7_attach_args *aa = args;
76 	struct sxiahci_softc *sxisc = (struct sxiahci_softc *)self;
77 	struct ahci_softc *sc = &sxisc->sc;
78 	bus_space_tag_t iot;
79 	bus_space_handle_t ioh;
80 	uint32_t timo;
81 
82 	sc->sc_iot = iot = aa->aa_iot;
83 	sc->sc_ios = aa->aa_dev->mem[0].size;
84 	sc->sc_dmat = aa->aa_dmat;
85 
86 	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
87 	    aa->aa_dev->mem[0].size, 0, &sc->sc_ioh))
88 		panic("sxiahci_attach: bus_space_map failed!");
89 	ioh = sc->sc_ioh;
90 
91 	/* enable clock */
92 	sxiccmu_enablemodule(CCMU_AHCI);
93 	delay(5000);
94 
95 	/* XXX setup magix */
96 	SXIWRITE4(sc, SXIAHCI_RWC, 0);
97 	delay(10);
98 
99 	SXISET4(sc, SXIAHCI_PHYCS1, 1 << 19);
100 	delay(10);
101 
102 	SXICMS4(sc, SXIAHCI_PHYCS0, 1 << 25,
103 	    1 << 23 | 1 << 24 | 1 << 18 | 1 << 26);
104 	delay(10);
105 
106 	SXICMS4(sc, SXIAHCI_PHYCS1,
107 	    1 << 16 | 1 << 12 | 1 << 11 | 1 << 8 | 1 << 6,
108 	    1 << 17 | 1 << 10 | 1 << 9 | 1 << 7);
109 	delay(10);
110 
111 	SXISET4(sc, SXIAHCI_PHYCS1, 1 << 28 | 1 << 15);
112 	delay(10);
113 
114 	SXICLR4(sc, SXIAHCI_PHYCS1, 1 << 19);
115 	delay(10);
116 
117 	SXICMS4(sc, SXIAHCI_PHYCS0, 1 << 21 | 1 << 20, 1 << 22);
118 	delay(10);
119 
120 	SXICMS4(sc, SXIAHCI_PHYCS2, 1 << 7 | 1 << 6,
121 	    1 << 9 | 1 << 8 | 1 << 5);
122 	delay(5000);
123 
124 	SXISET4(sc, SXIAHCI_PHYCS0, 1 << 19);
125 	delay(20);
126 
127 	timo = SXIAHCI_TIMEOUT;
128 	while ((SXIREAD4(sc, SXIAHCI_PHYCS0) >> 28 & 3) != 2 && --timo)
129 		delay(10);
130 	if (!timo) {
131 		printf(": AHCI phy power up failed.\n");
132 		goto dismod;
133 	}
134 
135 	SXISET4(sc, SXIAHCI_PHYCS2, 1 << 24);
136 
137 	timo = SXIAHCI_TIMEOUT;
138 	while ((SXIREAD4(sc, SXIAHCI_PHYCS2) & (1 << 24)) && --timo)
139 		delay(10);
140 	if (!timo) {
141 		printf(": AHCI phy calibration failed.\n");
142 		goto dismod;
143 	}
144 
145 	delay(15000);
146 	SXIWRITE4(sc, SXIAHCI_RWC, 7);
147 
148 	/* power up phy */
149 	sxipio_setcfg(SXIAHCI_PWRPIN, SXIPIO_OUTPUT);
150 	sxipio_setpin(SXIAHCI_PWRPIN);
151 
152 	sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_BIO,
153 	    ahci_intr, sc, sc->sc_dev.dv_xname);
154 	if (sc->sc_ih == NULL) {
155 		printf(": unable to establish interrupt\n");
156 		goto clrpwr;
157 	}
158 
159 	SXIWRITE4(sc, SXIAHCI_PI, 1);
160 	SXICLR4(sc, SXIAHCI_CAP, AHCI_REG_CAP_SPM);
161 	sc->sc_flags |= AHCI_F_NO_PMP; /* XXX enough? */
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 clrpwr:
171 	sxipio_clrpin(SXIAHCI_PWRPIN);
172 dismod:
173 	sxiccmu_disablemodule(CCMU_AHCI);
174 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
175 }
176 
177 int
178 sxiahci_detach(struct device *self, int flags)
179 {
180 	struct sxiahci_softc *sxisc = (struct sxiahci_softc *) self;
181 	struct ahci_softc *sc = &sxisc->sc;
182 
183 	ahci_detach(sc, flags);
184 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
185 	return 0;
186 }
187 
188 int
189 sxiahci_activate(struct device *self, int act)
190 {
191 	struct sxiahci_softc *sxisc = (struct sxiahci_softc *) self;
192 	struct ahci_softc *sc = &sxisc->sc;
193 
194 	return ahci_activate((struct device *)sc, act);
195 }
196