xref: /openbsd/sys/dev/cardbus/if_acx_cardbus.c (revision a6445c1d)
1 /*	$OpenBSD: if_acx_cardbus.c,v 1.19 2010/09/06 19:20:21 deraadt Exp $  */
2 
3 /*
4  * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2005, 2006
6  *	Damien Bergamini <damien.bergamini@free.fr>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 /*
22  * CardBus front-end for the Texas Instruments ACX driver
23  */
24 
25 #include "bpfilter.h"
26 
27 #include <sys/param.h>
28 #include <sys/sockio.h>
29 #include <sys/mbuf.h>
30 #include <sys/kernel.h>
31 #include <sys/socket.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/timeout.h>
35 #include <sys/device.h>
36 
37 #include <machine/bus.h>
38 #include <machine/intr.h>
39 
40 #include <net/if.h>
41 #include <net/if_dl.h>
42 #include <net/if_media.h>
43 
44 #ifdef INET
45 #include <netinet/in.h>
46 #include <netinet/if_ether.h>
47 #endif
48 
49 #include <net80211/ieee80211_var.h>
50 #include <net80211/ieee80211_amrr.h>
51 #include <net80211/ieee80211_radiotap.h>
52 
53 #include <dev/ic/acxvar.h>
54 #include <dev/ic/acxreg.h>
55 
56 #include <dev/pci/pcireg.h>
57 #include <dev/pci/pcivar.h>
58 #include <dev/pci/pcidevs.h>
59 
60 #include <dev/cardbus/cardbusvar.h>
61 
62 struct acx_cardbus_softc {
63 	struct acx_softc	sc_acx;
64 
65 	/* cardbus specific goo */
66 	cardbus_devfunc_t	sc_ct;
67 	pcitag_t		sc_tag;
68 	void			*sc_ih;
69 	bus_size_t		sc_mapsize1;
70 	bus_size_t		sc_mapsize2;
71 	pcireg_t		sc_iobar_val; /* acx100 only */
72 	pcireg_t		sc_bar1_val;
73 	pcireg_t		sc_bar2_val;
74 	int			sc_intrline;
75 
76 	/* hack for ACX100A */
77 	bus_space_tag_t		sc_io_bt;
78 	bus_space_handle_t	sc_io_bh;
79 	bus_size_t		sc_iomapsize;
80 
81 	int			sc_acx_attached;
82 	pci_chipset_tag_t	sc_pc;
83 };
84 
85 int	acx_cardbus_match(struct device *, void *, void *);
86 void	acx_cardbus_attach(struct device *, struct device *, void *);
87 int	acx_cardbus_detach(struct device *, int);
88 
89 struct cfattach acx_cardbus_ca = {
90 	sizeof (struct acx_cardbus_softc), acx_cardbus_match,
91 	acx_cardbus_attach, acx_cardbus_detach
92 };
93 
94 static const struct pci_matchid acx_cardbus_devices[] = {
95 	{ PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100A },
96 	{ PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100B },
97 	{ PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX111 },
98 };
99 
100 int	acx_cardbus_enable(struct acx_softc *);
101 void	acx_cardbus_disable(struct acx_softc *);
102 void	acx_cardbus_power(struct acx_softc *, int);
103 void	acx_cardbus_setup(struct acx_cardbus_softc *);
104 
105 int
106 acx_cardbus_match(struct device *parent, void *match, void *aux)
107 {
108 	return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
109 	    acx_cardbus_devices,
110 	    sizeof (acx_cardbus_devices) / sizeof (acx_cardbus_devices[0])));
111 }
112 
113 void
114 acx_cardbus_attach(struct device *parent, struct device *self, void *aux)
115 {
116 	struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self;
117 	struct acx_softc *sc = &csc->sc_acx;
118 	struct cardbus_attach_args *ca = aux;
119 	cardbus_devfunc_t ct = ca->ca_ct;
120 	bus_addr_t base;
121 	int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;
122 
123 	sc->sc_dmat = ca->ca_dmat;
124 	csc->sc_ct = ct;
125 	csc->sc_tag = ca->ca_tag;
126 	csc->sc_intrline = ca->ca_intrline;
127 	csc->sc_pc = ca->ca_pc;
128 
129 	/* power management hooks */
130 	sc->sc_enable = acx_cardbus_enable;
131 	sc->sc_disable = acx_cardbus_disable;
132 	sc->sc_power = acx_cardbus_power;
133 
134 	if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX100A) {
135 		/* first map I/O space as seen in the dragonfly code */
136 		error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
137 		    PCI_MAPREG_TYPE_IO, 0, &csc->sc_io_bt, &csc->sc_io_bh,
138 		    &base, &csc->sc_iomapsize);
139 		if (error != 0) {
140 			printf(": can't map i/o space\n");
141 			return;
142 		}
143 		csc->sc_iobar_val = base | PCI_MAPREG_TYPE_IO;
144 		b1 = CARDBUS_BASE1_REG;
145 		b2 = CARDBUS_BASE2_REG;
146 	}
147 
148 	/* map control/status registers */
149 	error = Cardbus_mapreg_map(ct, b1, PCI_MAPREG_TYPE_MEM, 0,
150 	    &sc->sc_mem1_bt, &sc->sc_mem1_bh, &base, &csc->sc_mapsize1);
151 	if (error != 0) {
152 		printf(": can't map mem1 space\n");
153 		return;
154 	}
155 
156 	csc->sc_bar1_val = base | PCI_MAPREG_TYPE_MEM;
157 
158 	/* map the other memory region */
159 	error = Cardbus_mapreg_map(ct, b2, PCI_MAPREG_TYPE_MEM, 0,
160 	    &sc->sc_mem2_bt, &sc->sc_mem2_bh, &base, &csc->sc_mapsize2);
161 	if (error != 0) {
162 		printf(": can't map mem2 space\n");
163 		return;
164 	}
165 
166 	csc->sc_bar2_val = base | PCI_MAPREG_TYPE_MEM;
167 
168 	/* set up the PCI configuration registers */
169 	acx_cardbus_setup(csc);
170 
171 	printf(": irq %d\n", csc->sc_intrline);
172 
173 	if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX111)
174 		acx111_set_param(sc);
175 	else
176 		acx100_set_param(sc);
177 
178 	error = acx_attach(sc);
179 	csc->sc_acx_attached = error == 0;
180 
181 	Cardbus_function_disable(ct);
182 }
183 
184 int
185 acx_cardbus_detach(struct device *self, int flags)
186 {
187 	struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self;
188 	struct acx_softc *sc = &csc->sc_acx;
189 	cardbus_devfunc_t ct = csc->sc_ct;
190 	cardbus_chipset_tag_t cc = ct->ct_cc;
191 	cardbus_function_tag_t cf = ct->ct_cf;
192 	int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;
193 
194 	if (csc->sc_acx_attached) {
195 		error = acx_detach(sc);
196 		if (error != 0)
197 			return (error);
198 	}
199 
200 	/* unhook the interrupt handler */
201 	if (csc->sc_ih != NULL) {
202 		cardbus_intr_disestablish(cc, cf, csc->sc_ih);
203 		csc->sc_ih = NULL;
204 	}
205 
206 	/* release bus space and close window */
207 	if (csc->sc_iomapsize) {
208 		b1 = CARDBUS_BASE1_REG;
209 		b2 = CARDBUS_BASE2_REG;
210 	}
211 	Cardbus_mapreg_unmap(ct, b1, sc->sc_mem1_bt,
212 	    sc->sc_mem1_bh, csc->sc_mapsize1);
213 	Cardbus_mapreg_unmap(ct, b2, sc->sc_mem2_bt,
214 	    sc->sc_mem2_bh, csc->sc_mapsize2);
215 	if (csc->sc_iomapsize)
216 		Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, csc->sc_io_bt,
217 		    csc->sc_io_bh, csc->sc_iomapsize);
218 
219 	return (0);
220 }
221 
222 int
223 acx_cardbus_enable(struct acx_softc *sc)
224 {
225 	struct acx_cardbus_softc *csc;
226 	int error;
227 
228 	csc = (struct acx_cardbus_softc *)sc;
229 	cardbus_devfunc_t ct = csc->sc_ct;
230 	cardbus_chipset_tag_t cc = ct->ct_cc;
231 	cardbus_function_tag_t cf = ct->ct_cf;
232 
233 	/* power on the socket */
234 	error = Cardbus_function_enable(ct);
235 	if (error)
236 		return error;
237 
238 	/* setup the PCI configuration registers */
239 	acx_cardbus_setup(csc);
240 
241 	/* map and establish the interrupt handler */
242 	csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
243 	    acx_intr, sc, sc->sc_dev.dv_xname);
244 	if (csc->sc_ih == NULL) {
245 		printf("%s: could not establish interrupt at %d\n",
246 		    sc->sc_dev.dv_xname, csc->sc_intrline);
247 		Cardbus_function_disable(ct);
248 		return (1);
249 	}
250 
251 	return (0);
252 }
253 
254 void
255 acx_cardbus_disable(struct acx_softc *sc)
256 {
257 	struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc;
258 	cardbus_devfunc_t ct = csc->sc_ct;
259 	cardbus_chipset_tag_t cc = ct->ct_cc;
260 	cardbus_function_tag_t cf = ct->ct_cf;
261 
262 	/* unhook the interrupt handler */
263 	cardbus_intr_disestablish(cc, cf, csc->sc_ih);
264 	csc->sc_ih = NULL;
265 
266 	/* power down the socket */
267 	Cardbus_function_disable(ct);
268 }
269 
270 void
271 acx_cardbus_power(struct acx_softc *sc, int why)
272 {
273 	struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc;
274 
275 	if (why == DVACT_RESUME) {
276 		/* kick the PCI configuration registers */
277 		acx_cardbus_setup(csc);
278 	}
279 }
280 
281 void
282 acx_cardbus_setup(struct acx_cardbus_softc *csc)
283 {
284 	cardbus_devfunc_t ct = csc->sc_ct;
285 	cardbus_chipset_tag_t cc = ct->ct_cc;
286 	pci_chipset_tag_t pc = csc->sc_pc;
287 	cardbus_function_tag_t cf = ct->ct_cf;
288 	pcireg_t reg;
289 	int b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;
290 
291 	if (csc->sc_iobar_val) {
292 		pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG,
293 		    csc->sc_iobar_val);
294 		b1 = CARDBUS_BASE1_REG;
295 		b2 = CARDBUS_BASE2_REG;
296 		/* (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); */
297 	}
298 
299 	/* program the BAR */
300 	pci_conf_write(pc, csc->sc_tag, b1, csc->sc_bar1_val);
301 	pci_conf_write(pc, csc->sc_tag, b2, csc->sc_bar2_val);
302 
303 	/* make sure the right access type is on the cardbus bridge */
304 	(*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
305 	(*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
306 
307 	/* enable the appropriate bits in the PCI CSR */
308 	reg = pci_conf_read(pc, csc->sc_tag,
309 	    PCI_COMMAND_STATUS_REG);
310 	reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
311 #if 0
312 	if (csc->sc_iobar_val)
313 		reg |= PCI_COMMAND_IO_ENABLE;
314 #endif
315 	pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
316 	    reg);
317 }
318