com_cardbus.c revision 1.6 1 /* $NetBSD: com_cardbus.c,v 1.6 2001/11/13 12:51:12 lukem Exp $ */
2
3 /*
4 * Copyright (c) 2000 Johan Danielsson
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * 3. Neither the name of author nor the names of any contributors may
19 * be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /* A driver for CardBus based serial devices.
36
37 If the CardBus device only has one BAR (that is not also the CIS
38 BAR) listed in the CIS, it is assumed to be the one to use. For
39 devices with more than one BAR, the list of known devices has to be
40 updated below. */
41
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: com_cardbus.c,v 1.6 2001/11/13 12:51:12 lukem Exp $");
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/tty.h>
48 #include <sys/device.h>
49
50 #include <dev/cardbus/cardbusvar.h>
51 #include <dev/cardbus/cardbusdevs.h>
52
53 #include <dev/pcmcia/pcmciareg.h>
54
55 #include <dev/ic/comreg.h>
56 #include <dev/ic/comvar.h>
57
58 struct com_cardbus_softc {
59 struct com_softc cc_com;
60 void *cc_ih;
61 cardbus_devfunc_t cc_ct;
62 bus_addr_t cc_addr;
63 cardbusreg_t cc_base;
64 bus_size_t cc_size;
65 cardbusreg_t cc_csr;
66 int cc_cben;
67 cardbustag_t cc_tag;
68 cardbusreg_t cc_reg;
69 int cc_type;
70 };
71
72 #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)
73
74 static int com_cardbus_match (struct device*, struct cfdata*, void*);
75 static void com_cardbus_attach (struct device*, struct device*, void*);
76 static int com_cardbus_detach (struct device*, int);
77
78 static void com_cardbus_setup(struct com_cardbus_softc*);
79 static int com_cardbus_enable (struct com_softc*);
80 static void com_cardbus_disable (struct com_softc*);
81
82 struct cfattach com_cardbus_ca = {
83 sizeof(struct com_cardbus_softc), com_cardbus_match,
84 com_cardbus_attach, com_cardbus_detach, com_activate
85 };
86
87 static struct csdev {
88 int vendor;
89 int product;
90 cardbusreg_t reg;
91 int type;
92 } csdevs[] = {
93 { CARDBUS_VENDOR_XIRCOM, CARDBUS_PRODUCT_XIRCOM_MODEM56,
94 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
95 { CARDBUS_VENDOR_INTEL, CARDBUS_PRODUCT_INTEL_MODEM56,
96 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }
97 };
98
99 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
100
101 static struct csdev*
102 find_csdev(struct cardbus_attach_args *ca)
103 {
104 struct csdev *cp;
105
106 for(cp = csdevs; cp < csdevs + ncsdevs; cp++)
107 if(cp->vendor == CARDBUS_VENDOR(ca->ca_id) &&
108 cp->product == CARDBUS_PRODUCT(ca->ca_id))
109 return cp;
110 return NULL;
111 }
112
113 static int
114 com_cardbus_match(struct device *parent, struct cfdata *match, void *aux)
115 {
116 struct cardbus_attach_args *ca = aux;
117
118 /* known devices are ok */
119 if(find_csdev(ca) != NULL)
120 return 10;
121
122 /* as are serial devices with a known UART */
123 if(ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
124 ca->ca_cis.funce.serial.uart_present != 0 &&
125 (ca->ca_cis.funce.serial.uart_type == 0 || /* 8250 */
126 ca->ca_cis.funce.serial.uart_type == 1 || /* 16450 */
127 ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */
128 return 1;
129
130 return 0;
131 }
132
133 static int
134 gofigure(struct cardbus_attach_args *ca, struct com_cardbus_softc *csc)
135 {
136 int i, index = -1;
137 cardbusreg_t cis_ptr;
138 struct csdev *cp;
139
140 /* If this device is listed above, use the known values, */
141 cp = find_csdev(ca);
142 if(cp != NULL) {
143 csc->cc_reg = cp->reg;
144 csc->cc_type = cp->type;
145 return 0;
146 }
147
148 cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
149
150 /* otherwise try to deduce which BAR and type to use from CIS. If
151 there is only one BAR, it must be the one we should use, if
152 there are more, we're out of luck. */
153 for(i = 0; i < 7; i++) {
154 /* ignore zero sized BARs */
155 if(ca->ca_cis.bar[i].size == 0)
156 continue;
157 /* ignore the CIS BAR */
158 if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
159 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
160 continue;
161 if(index != -1)
162 goto multi_bar;
163 index = i;
164 }
165 if(index == -1) {
166 printf(": couldn't find any base address tuple\n");
167 return 1;
168 }
169 csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
170 if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
171 csc->cc_type = CARDBUS_MAPREG_TYPE_MEM;
172 else
173 csc->cc_type = CARDBUS_MAPREG_TYPE_IO;
174 return 0;
175
176 multi_bar:
177 printf(": there are more than one possible base\n");
178
179 printf("%s: address for this device, "
180 "please report the following information\n",
181 DEVNAME(csc));
182 printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
183 CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id));
184 for(i = 0; i < 7; i++) {
185 /* ignore zero sized BARs */
186 if(ca->ca_cis.bar[i].size == 0)
187 continue;
188 /* ignore the CIS BAR */
189 if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
190 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
191 continue;
192 printf("%s: base address %x type %s size %x\n",
193 DEVNAME(csc),
194 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
195 (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
196 ca->ca_cis.bar[i].size);
197 }
198 return 1;
199 }
200
201 static void
202 com_cardbus_attach (struct device *parent, struct device *self, void *aux)
203 {
204 struct com_softc *sc = (struct com_softc*)self;
205 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
206 struct cardbus_attach_args *ca = aux;
207
208 csc->cc_ct = ca->ca_ct;
209 csc->cc_tag = Cardbus_make_tag(csc->cc_ct);
210
211 if(gofigure(ca, csc) != 0)
212 return;
213
214 if(Cardbus_mapreg_map(ca->ca_ct,
215 csc->cc_reg,
216 csc->cc_type,
217 0,
218 &sc->sc_iot,
219 &sc->sc_ioh,
220 &csc->cc_addr,
221 &csc->cc_size) != 0) {
222 printf("failed to map memory");
223 return;
224 }
225
226 csc->cc_base = csc->cc_addr;
227 csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
228 if(csc->cc_type == CARDBUS_MAPREG_TYPE_IO) {
229 csc->cc_base |= CARDBUS_MAPREG_TYPE_IO;
230 csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE;
231 csc->cc_cben = CARDBUS_IO_ENABLE;
232 } else {
233 csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
234 csc->cc_cben = CARDBUS_MEM_ENABLE;
235 }
236 sc->sc_iobase = csc->cc_addr;
237
238 sc->sc_frequency = COM_FREQ;
239
240 sc->enable = com_cardbus_enable;
241 sc->disable = com_cardbus_disable;
242 sc->enabled = 0;
243
244 if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
245 printf(": %s %s\n", ca->ca_cis.cis1_info[0],
246 ca->ca_cis.cis1_info[1]);
247 printf("%s", DEVNAME(csc));
248 }
249
250 com_cardbus_setup(csc);
251
252 com_attach_subr(sc);
253
254 Cardbus_function_disable(csc->cc_ct);
255 }
256
257 static void
258 com_cardbus_setup(struct com_cardbus_softc *csc)
259 {
260 cardbus_devfunc_t ct = csc->cc_ct;
261 cardbus_chipset_tag_t cc = ct->ct_cc;
262 cardbus_function_tag_t cf = ct->ct_cf;
263 cardbusreg_t reg;
264
265 Cardbus_conf_write(ct, csc->cc_tag, csc->cc_reg, csc->cc_base);
266
267 /* enable accesses on cardbus bridge */
268 (*cf->cardbus_ctrl)(cc, csc->cc_cben);
269 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
270
271 /* and the card itself */
272 reg = Cardbus_conf_read(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG);
273 reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE);
274 reg |= csc->cc_csr;
275 Cardbus_conf_write(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
276
277 /*
278 * Make sure the latency timer is set to some reasonable
279 * value.
280 */
281 reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG);
282 if (CARDBUS_LATTIMER(reg) < 0x20) {
283 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
284 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
285 cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg);
286 }
287 }
288
289 static int
290 com_cardbus_enable(struct com_softc *sc)
291 {
292 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
293 struct cardbus_softc *psc =
294 (struct cardbus_softc *)sc->sc_dev.dv_parent;
295 cardbus_chipset_tag_t cc = psc->sc_cc;
296 cardbus_function_tag_t cf = psc->sc_cf;
297
298 Cardbus_function_enable(csc->cc_ct);
299
300 com_cardbus_setup(csc);
301
302 /* establish the interrupt. */
303 csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
304 IPL_SERIAL, comintr, sc);
305 if (csc->cc_ih == NULL) {
306 printf("%s: couldn't establish interrupt\n",
307 DEVNAME(csc));
308 return 1;
309 }
310
311 printf("%s: interrupting at irq %d\n",
312 DEVNAME(csc), psc->sc_intrline);
313
314 return 0;
315 }
316
317 static void
318 com_cardbus_disable(struct com_softc *sc)
319 {
320 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
321 struct cardbus_softc *psc =
322 (struct cardbus_softc *)sc->sc_dev.dv_parent;
323 cardbus_chipset_tag_t cc = psc->sc_cc;
324 cardbus_function_tag_t cf = psc->sc_cf;
325
326 cardbus_intr_disestablish(cc, cf, csc->cc_ih);
327 Cardbus_function_disable(csc->cc_ct);
328 }
329
330 static int
331 com_cardbus_detach(struct device *self, int flags)
332 {
333 struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
334 struct com_softc *sc = (struct com_softc *) self;
335 struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
336 int error;
337
338 if ((error = com_detach(self, flags)) != 0)
339 return error;
340
341 cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
342
343 Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
344 csc->cc_size);
345
346 return 0;
347 }
348