1 /* $OpenBSD: if_acx_cardbus.c,v 1.24 2024/05/24 06:26:47 jsg 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/systm.h>
29 #include <sys/timeout.h>
30 #include <sys/device.h>
31
32 #include <machine/bus.h>
33
34 #include <net/if.h>
35 #include <net/if_media.h>
36
37 #include <netinet/in.h>
38 #include <netinet/if_ether.h>
39
40 #include <net80211/ieee80211_var.h>
41 #include <net80211/ieee80211_amrr.h>
42 #include <net80211/ieee80211_radiotap.h>
43
44 #include <dev/ic/acxvar.h>
45
46 #include <dev/pci/pcireg.h>
47 #include <dev/pci/pcivar.h>
48 #include <dev/pci/pcidevs.h>
49
50 #include <dev/cardbus/cardbusvar.h>
51
52 struct acx_cardbus_softc {
53 struct acx_softc sc_acx;
54
55 /* cardbus specific goo */
56 cardbus_devfunc_t sc_ct;
57 pcitag_t sc_tag;
58 void *sc_ih;
59 bus_size_t sc_mapsize1;
60 bus_size_t sc_mapsize2;
61 pcireg_t sc_iobar_val; /* acx100 only */
62 pcireg_t sc_bar1_val;
63 pcireg_t sc_bar2_val;
64 int sc_intrline;
65
66 /* hack for ACX100A */
67 bus_space_tag_t sc_io_bt;
68 bus_space_handle_t sc_io_bh;
69 bus_size_t sc_iomapsize;
70
71 int sc_acx_attached;
72 pci_chipset_tag_t sc_pc;
73 };
74
75 int acx_cardbus_match(struct device *, void *, void *);
76 void acx_cardbus_attach(struct device *, struct device *, void *);
77 int acx_cardbus_detach(struct device *, int);
78
79 const struct cfattach acx_cardbus_ca = {
80 sizeof (struct acx_cardbus_softc), acx_cardbus_match,
81 acx_cardbus_attach, acx_cardbus_detach
82 };
83
84 static const struct pci_matchid acx_cardbus_devices[] = {
85 { PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100A },
86 { PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100B },
87 { PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX111 },
88 };
89
90 int acx_cardbus_enable(struct acx_softc *);
91 void acx_cardbus_disable(struct acx_softc *);
92 void acx_cardbus_power(struct acx_softc *, int);
93 void acx_cardbus_setup(struct acx_cardbus_softc *);
94
95 int
acx_cardbus_match(struct device * parent,void * match,void * aux)96 acx_cardbus_match(struct device *parent, void *match, void *aux)
97 {
98 return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
99 acx_cardbus_devices,
100 sizeof (acx_cardbus_devices) / sizeof (acx_cardbus_devices[0])));
101 }
102
103 void
acx_cardbus_attach(struct device * parent,struct device * self,void * aux)104 acx_cardbus_attach(struct device *parent, struct device *self, void *aux)
105 {
106 struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self;
107 struct acx_softc *sc = &csc->sc_acx;
108 struct cardbus_attach_args *ca = aux;
109 cardbus_devfunc_t ct = ca->ca_ct;
110 bus_addr_t base;
111 int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;
112
113 sc->sc_dmat = ca->ca_dmat;
114 csc->sc_ct = ct;
115 csc->sc_tag = ca->ca_tag;
116 csc->sc_intrline = ca->ca_intrline;
117 csc->sc_pc = ca->ca_pc;
118
119 /* power management hooks */
120 sc->sc_enable = acx_cardbus_enable;
121 sc->sc_disable = acx_cardbus_disable;
122 sc->sc_power = acx_cardbus_power;
123
124 if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX100A) {
125 /* first map I/O space as seen in the dragonfly code */
126 error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
127 PCI_MAPREG_TYPE_IO, 0, &csc->sc_io_bt, &csc->sc_io_bh,
128 &base, &csc->sc_iomapsize);
129 if (error != 0) {
130 printf(": can't map i/o space\n");
131 return;
132 }
133 csc->sc_iobar_val = base | PCI_MAPREG_TYPE_IO;
134 b1 = CARDBUS_BASE1_REG;
135 b2 = CARDBUS_BASE2_REG;
136 }
137
138 /* map control/status registers */
139 error = Cardbus_mapreg_map(ct, b1, PCI_MAPREG_TYPE_MEM, 0,
140 &sc->sc_mem1_bt, &sc->sc_mem1_bh, &base, &csc->sc_mapsize1);
141 if (error != 0) {
142 printf(": can't map mem1 space\n");
143 return;
144 }
145
146 csc->sc_bar1_val = base | PCI_MAPREG_TYPE_MEM;
147
148 /* map the other memory region */
149 error = Cardbus_mapreg_map(ct, b2, PCI_MAPREG_TYPE_MEM, 0,
150 &sc->sc_mem2_bt, &sc->sc_mem2_bh, &base, &csc->sc_mapsize2);
151 if (error != 0) {
152 printf(": can't map mem2 space\n");
153 return;
154 }
155
156 csc->sc_bar2_val = base | PCI_MAPREG_TYPE_MEM;
157
158 /* set up the PCI configuration registers */
159 acx_cardbus_setup(csc);
160
161 printf(": irq %d\n", csc->sc_intrline);
162
163 if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX111)
164 acx111_set_param(sc);
165 else
166 acx100_set_param(sc);
167
168 error = acx_attach(sc);
169 csc->sc_acx_attached = error == 0;
170
171 Cardbus_function_disable(ct);
172 }
173
174 int
acx_cardbus_detach(struct device * self,int flags)175 acx_cardbus_detach(struct device *self, int flags)
176 {
177 struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self;
178 struct acx_softc *sc = &csc->sc_acx;
179 cardbus_devfunc_t ct = csc->sc_ct;
180 cardbus_chipset_tag_t cc = ct->ct_cc;
181 cardbus_function_tag_t cf = ct->ct_cf;
182 int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;
183
184 if (csc->sc_acx_attached) {
185 error = acx_detach(sc);
186 if (error != 0)
187 return (error);
188 }
189
190 /* unhook the interrupt handler */
191 if (csc->sc_ih != NULL) {
192 cardbus_intr_disestablish(cc, cf, csc->sc_ih);
193 csc->sc_ih = NULL;
194 }
195
196 /* release bus space and close window */
197 if (csc->sc_iomapsize) {
198 b1 = CARDBUS_BASE1_REG;
199 b2 = CARDBUS_BASE2_REG;
200 }
201 Cardbus_mapreg_unmap(ct, b1, sc->sc_mem1_bt,
202 sc->sc_mem1_bh, csc->sc_mapsize1);
203 Cardbus_mapreg_unmap(ct, b2, sc->sc_mem2_bt,
204 sc->sc_mem2_bh, csc->sc_mapsize2);
205 if (csc->sc_iomapsize)
206 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, csc->sc_io_bt,
207 csc->sc_io_bh, csc->sc_iomapsize);
208
209 return (0);
210 }
211
212 int
acx_cardbus_enable(struct acx_softc * sc)213 acx_cardbus_enable(struct acx_softc *sc)
214 {
215 struct acx_cardbus_softc *csc;
216 int error;
217
218 csc = (struct acx_cardbus_softc *)sc;
219 cardbus_devfunc_t ct = csc->sc_ct;
220 cardbus_chipset_tag_t cc = ct->ct_cc;
221 cardbus_function_tag_t cf = ct->ct_cf;
222
223 /* power on the socket */
224 error = Cardbus_function_enable(ct);
225 if (error)
226 return error;
227
228 /* setup the PCI configuration registers */
229 acx_cardbus_setup(csc);
230
231 /* map and establish the interrupt handler */
232 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
233 acx_intr, sc, sc->sc_dev.dv_xname);
234 if (csc->sc_ih == NULL) {
235 printf("%s: could not establish interrupt at %d\n",
236 sc->sc_dev.dv_xname, csc->sc_intrline);
237 Cardbus_function_disable(ct);
238 return (1);
239 }
240
241 return (0);
242 }
243
244 void
acx_cardbus_disable(struct acx_softc * sc)245 acx_cardbus_disable(struct acx_softc *sc)
246 {
247 struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc;
248 cardbus_devfunc_t ct = csc->sc_ct;
249 cardbus_chipset_tag_t cc = ct->ct_cc;
250 cardbus_function_tag_t cf = ct->ct_cf;
251
252 /* unhook the interrupt handler */
253 cardbus_intr_disestablish(cc, cf, csc->sc_ih);
254 csc->sc_ih = NULL;
255
256 /* power down the socket */
257 Cardbus_function_disable(ct);
258 }
259
260 void
acx_cardbus_power(struct acx_softc * sc,int why)261 acx_cardbus_power(struct acx_softc *sc, int why)
262 {
263 struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc;
264
265 if (why == DVACT_RESUME) {
266 /* kick the PCI configuration registers */
267 acx_cardbus_setup(csc);
268 }
269 }
270
271 void
acx_cardbus_setup(struct acx_cardbus_softc * csc)272 acx_cardbus_setup(struct acx_cardbus_softc *csc)
273 {
274 cardbus_devfunc_t ct = csc->sc_ct;
275 cardbus_chipset_tag_t cc = ct->ct_cc;
276 pci_chipset_tag_t pc = csc->sc_pc;
277 cardbus_function_tag_t cf = ct->ct_cf;
278 pcireg_t reg;
279 int b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;
280
281 if (csc->sc_iobar_val) {
282 pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG,
283 csc->sc_iobar_val);
284 b1 = CARDBUS_BASE1_REG;
285 b2 = CARDBUS_BASE2_REG;
286 /* (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); */
287 }
288
289 /* program the BAR */
290 pci_conf_write(pc, csc->sc_tag, b1, csc->sc_bar1_val);
291 pci_conf_write(pc, csc->sc_tag, b2, csc->sc_bar2_val);
292
293 /* make sure the right access type is on the cardbus bridge */
294 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
295 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
296
297 /* enable the appropriate bits in the PCI CSR */
298 reg = pci_conf_read(pc, csc->sc_tag,
299 PCI_COMMAND_STATUS_REG);
300 reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
301 #if 0
302 if (csc->sc_iobar_val)
303 reg |= PCI_COMMAND_IO_ENABLE;
304 #endif
305 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
306 reg);
307 }
308