com_cardbus.c revision 1.5.6.2 1 /* $NetBSD: com_cardbus.c,v 1.5.6.2 2002/10/10 18:38:31 jdolecek 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.5.6.2 2002/10/10 18:38:31 jdolecek 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 CFATTACH_DECL(com_cardbus, sizeof(struct com_cardbus_softc),
83 com_cardbus_match, com_cardbus_attach, com_cardbus_detach, com_activate);
84
85 static struct csdev {
86 int vendor;
87 int product;
88 cardbusreg_t reg;
89 int type;
90 } csdevs[] = {
91 { CARDBUS_VENDOR_XIRCOM, CARDBUS_PRODUCT_XIRCOM_MODEM56,
92 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
93 { CARDBUS_VENDOR_INTEL, CARDBUS_PRODUCT_INTEL_MODEM56,
94 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }
95 };
96
97 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
98
99 static struct csdev*
100 find_csdev(struct cardbus_attach_args *ca)
101 {
102 struct csdev *cp;
103
104 for(cp = csdevs; cp < csdevs + ncsdevs; cp++)
105 if(cp->vendor == CARDBUS_VENDOR(ca->ca_id) &&
106 cp->product == CARDBUS_PRODUCT(ca->ca_id))
107 return cp;
108 return NULL;
109 }
110
111 static int
112 com_cardbus_match(struct device *parent, struct cfdata *match, void *aux)
113 {
114 struct cardbus_attach_args *ca = aux;
115
116 /* known devices are ok */
117 if(find_csdev(ca) != NULL)
118 return 10;
119
120 /* as are serial devices with a known UART */
121 if(ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
122 ca->ca_cis.funce.serial.uart_present != 0 &&
123 (ca->ca_cis.funce.serial.uart_type == 0 || /* 8250 */
124 ca->ca_cis.funce.serial.uart_type == 1 || /* 16450 */
125 ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */
126 return 1;
127
128 return 0;
129 }
130
131 static int
132 gofigure(struct cardbus_attach_args *ca, struct com_cardbus_softc *csc)
133 {
134 int i, index = -1;
135 cardbusreg_t cis_ptr;
136 struct csdev *cp;
137
138 /* If this device is listed above, use the known values, */
139 cp = find_csdev(ca);
140 if(cp != NULL) {
141 csc->cc_reg = cp->reg;
142 csc->cc_type = cp->type;
143 return 0;
144 }
145
146 cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
147
148 /* otherwise try to deduce which BAR and type to use from CIS. If
149 there is only one BAR, it must be the one we should use, if
150 there are more, we're out of luck. */
151 for(i = 0; i < 7; i++) {
152 /* ignore zero sized BARs */
153 if(ca->ca_cis.bar[i].size == 0)
154 continue;
155 /* ignore the CIS BAR */
156 if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
157 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
158 continue;
159 if(index != -1)
160 goto multi_bar;
161 index = i;
162 }
163 if(index == -1) {
164 printf(": couldn't find any base address tuple\n");
165 return 1;
166 }
167 csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
168 if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
169 csc->cc_type = CARDBUS_MAPREG_TYPE_MEM;
170 else
171 csc->cc_type = CARDBUS_MAPREG_TYPE_IO;
172 return 0;
173
174 multi_bar:
175 printf(": there are more than one possible base\n");
176
177 printf("%s: address for this device, "
178 "please report the following information\n",
179 DEVNAME(csc));
180 printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
181 CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id));
182 for(i = 0; i < 7; i++) {
183 /* ignore zero sized BARs */
184 if(ca->ca_cis.bar[i].size == 0)
185 continue;
186 /* ignore the CIS BAR */
187 if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
188 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
189 continue;
190 printf("%s: base address %x type %s size %x\n",
191 DEVNAME(csc),
192 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
193 (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
194 ca->ca_cis.bar[i].size);
195 }
196 return 1;
197 }
198
199 static void
200 com_cardbus_attach (struct device *parent, struct device *self, void *aux)
201 {
202 struct com_softc *sc = (struct com_softc*)self;
203 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
204 struct cardbus_attach_args *ca = aux;
205
206 csc->cc_ct = ca->ca_ct;
207 csc->cc_tag = Cardbus_make_tag(csc->cc_ct);
208
209 if(gofigure(ca, csc) != 0)
210 return;
211
212 if(Cardbus_mapreg_map(ca->ca_ct,
213 csc->cc_reg,
214 csc->cc_type,
215 0,
216 &sc->sc_iot,
217 &sc->sc_ioh,
218 &csc->cc_addr,
219 &csc->cc_size) != 0) {
220 printf("failed to map memory");
221 return;
222 }
223
224 csc->cc_base = csc->cc_addr;
225 csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
226 if(csc->cc_type == CARDBUS_MAPREG_TYPE_IO) {
227 csc->cc_base |= CARDBUS_MAPREG_TYPE_IO;
228 csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE;
229 csc->cc_cben = CARDBUS_IO_ENABLE;
230 } else {
231 csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
232 csc->cc_cben = CARDBUS_MEM_ENABLE;
233 }
234 sc->sc_iobase = csc->cc_addr;
235
236 sc->sc_frequency = COM_FREQ;
237
238 sc->enable = com_cardbus_enable;
239 sc->disable = com_cardbus_disable;
240 sc->enabled = 0;
241
242 if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
243 printf(": %s %s\n", ca->ca_cis.cis1_info[0],
244 ca->ca_cis.cis1_info[1]);
245 printf("%s", DEVNAME(csc));
246 }
247
248 com_cardbus_setup(csc);
249
250 com_attach_subr(sc);
251
252 Cardbus_function_disable(csc->cc_ct);
253 }
254
255 static void
256 com_cardbus_setup(struct com_cardbus_softc *csc)
257 {
258 cardbus_devfunc_t ct = csc->cc_ct;
259 cardbus_chipset_tag_t cc = ct->ct_cc;
260 cardbus_function_tag_t cf = ct->ct_cf;
261 cardbusreg_t reg;
262
263 Cardbus_conf_write(ct, csc->cc_tag, csc->cc_reg, csc->cc_base);
264
265 /* enable accesses on cardbus bridge */
266 (*cf->cardbus_ctrl)(cc, csc->cc_cben);
267 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
268
269 /* and the card itself */
270 reg = Cardbus_conf_read(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG);
271 reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE);
272 reg |= csc->cc_csr;
273 Cardbus_conf_write(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
274
275 /*
276 * Make sure the latency timer is set to some reasonable
277 * value.
278 */
279 reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG);
280 if (CARDBUS_LATTIMER(reg) < 0x20) {
281 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
282 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
283 cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg);
284 }
285 }
286
287 static int
288 com_cardbus_enable(struct com_softc *sc)
289 {
290 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
291 struct cardbus_softc *psc =
292 (struct cardbus_softc *)sc->sc_dev.dv_parent;
293 cardbus_chipset_tag_t cc = psc->sc_cc;
294 cardbus_function_tag_t cf = psc->sc_cf;
295
296 Cardbus_function_enable(csc->cc_ct);
297
298 com_cardbus_setup(csc);
299
300 /* establish the interrupt. */
301 csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
302 IPL_SERIAL, comintr, sc);
303 if (csc->cc_ih == NULL) {
304 printf("%s: couldn't establish interrupt\n",
305 DEVNAME(csc));
306 return 1;
307 }
308
309 printf("%s: interrupting at irq %d\n",
310 DEVNAME(csc), psc->sc_intrline);
311
312 return 0;
313 }
314
315 static void
316 com_cardbus_disable(struct com_softc *sc)
317 {
318 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
319 struct cardbus_softc *psc =
320 (struct cardbus_softc *)sc->sc_dev.dv_parent;
321 cardbus_chipset_tag_t cc = psc->sc_cc;
322 cardbus_function_tag_t cf = psc->sc_cf;
323
324 cardbus_intr_disestablish(cc, cf, csc->cc_ih);
325 Cardbus_function_disable(csc->cc_ct);
326 }
327
328 static int
329 com_cardbus_detach(struct device *self, int flags)
330 {
331 struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
332 struct com_softc *sc = (struct com_softc *) self;
333 struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
334 int error;
335
336 if ((error = com_detach(self, flags)) != 0)
337 return error;
338
339 cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
340
341 Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
342 csc->cc_size);
343
344 return 0;
345 }
346