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