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