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