xref: /openbsd/sys/dev/cardbus/cardbus_map.c (revision 753ec538)
1 /*	$OpenBSD: cardbus_map.c,v 1.8 2007/09/17 20:29:47 miod Exp $	*/
2 /*	$NetBSD: cardbus_map.c,v 1.10 2000/03/07 00:31:46 mycroft Exp $	*/
3 
4 /*
5  * Copyright (c) 1999 and 2000
6  *      HAYAKAWA Koichi.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by HAYAKAWA Koichi.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 
41 #include <machine/bus.h>
42 
43 #include <dev/cardbus/cardbusvar.h>
44 
45 #include <dev/pci/pcireg.h>	/* XXX */
46 
47 #if defined DEBUG && !defined CARDBUS_MAP_DEBUG
48 #define CARDBUS_MAP_DEBUG
49 #endif
50 
51 #if defined CARDBUS_MAP_DEBUG
52 #define STATIC
53 #define DPRINTF(a) printf a
54 #else
55 #ifdef DDB
56 #define STATIC
57 #else
58 #define STATIC static
59 #endif
60 #define DPRINTF(a)
61 #endif
62 
63 
64 STATIC int cardbus_io_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
65 	       cardbustag_t, int, cardbusreg_t, bus_addr_t *, bus_size_t *,
66 	       int *);
67 STATIC int cardbus_mem_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
68 	       cardbustag_t, int, cardbusreg_t, bus_addr_t *, bus_size_t *,
69 	       int *);
70 
71 int
72 cardbus_mapreg_probe(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf,
73     cardbustag_t tag, int reg, pcireg_t *typep)
74 {
75 	pcireg_t address, mask;
76 	int s;
77 
78 	s = splhigh();
79 	address = cardbus_conf_read(cc, cf, tag, reg);
80 	cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
81 	mask = cardbus_conf_read(cc, cf, tag, reg);
82 	cardbus_conf_write(cc, cf, tag, reg, address);
83 	splx(s);
84 
85 	if (mask == 0) /* unimplemented mapping register */
86 		return (0);
87 
88 	if (typep)
89 		*typep = _PCI_MAPREG_TYPEBITS(address);
90 	return (1);
91 }
92 
93 /*
94  * STATIC int cardbus_io_find(cardbus_chipset_tag_t cc,
95  *			      cardbus_function_tag_t cf, cardbustag_t tag,
96  *			      int reg, cardbusreg_t type, bus_addr_t *basep,
97  *			      bus_size_t *sizep, int *flagsp)
98  * This code is stolen from sys/dev/pci_map.c.
99  */
100 STATIC int
101 cardbus_io_find(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf,
102     cardbustag_t tag, int reg, cardbusreg_t type, bus_addr_t *basep,
103     bus_size_t *sizep, int *flagsp)
104 {
105 	cardbusreg_t address, mask;
106 	int s;
107 
108 	/* EXT ROM is able to map on memory space ONLY. */
109 	if (reg == CARDBUS_ROM_REG)
110 		return (1);
111 
112 	if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) {
113 		panic("cardbus_io_find: bad request");
114 	}
115 
116 	/*
117 	 * Section 6.2.5.1, `Address Maps', tells us that:
118 	 *
119 	 * 1) The builtin software should have already mapped the device in a
120 	 * reasonable way.
121 	 *
122 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
123 	 * n bits of the address to 0.  As recommended, we write all 1s and see
124 	 * what we get back.
125 	 */
126 	s = splhigh();
127 	address = cardbus_conf_read(cc, cf, tag, reg);
128 	cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
129 	mask = cardbus_conf_read(cc, cf, tag, reg);
130 	cardbus_conf_write(cc, cf, tag, reg, address);
131 	splx(s);
132 
133 	if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
134 		printf("cardbus_io_find: expected type i/o, found mem\n");
135 		return (1);
136 	}
137 
138 	if (PCI_MAPREG_IO_SIZE(mask) == 0) {
139 		printf("cardbus_io_find: void region\n");
140 		return (1);
141 	}
142 
143 	if (basep != 0)
144 		*basep = PCI_MAPREG_IO_ADDR(address);
145 	if (sizep != 0)
146 		*sizep = PCI_MAPREG_IO_SIZE(mask);
147 	if (flagsp != 0)
148 		*flagsp = 0;
149 
150 	return (0);
151 }
152 
153 /*
154  * STATIC int cardbus_mem_find(cardbus_chipset_tag_t cc,
155  *			       cardbus_function_tag_t cf, cardbustag_t tag,
156  *			       int reg, cardbusreg_t type, bus_addr_t *basep,
157  *			       bus_size_t *sizep, int *flagsp)
158  * This code is stolen from sys/dev/pci_map.c.
159  */
160 STATIC int
161 cardbus_mem_find(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf,
162     cardbustag_t tag, int reg, cardbusreg_t type, bus_addr_t *basep,
163     bus_size_t *sizep, int *flagsp)
164 {
165 	cardbusreg_t address, mask;
166 	int s;
167 
168 	if (reg != CARDBUS_ROM_REG &&
169 	    (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))) {
170 		panic("cardbus_mem_find: bad request");
171 	}
172 
173 	/*
174 	 * Section 6.2.5.1, `Address Maps', tells us that:
175 	 *
176 	 * 1) The builtin software should have already mapped the device in a
177 	 * reasonable way.
178 	 *
179 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
180 	 * n bits of the address to 0.  As recommended, we write all 1s and see
181 	 * what we get back.
182 	 */
183 	s = splhigh();
184 	address = cardbus_conf_read(cc, cf, tag, reg);
185 	cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
186 	mask = cardbus_conf_read(cc, cf, tag, reg);
187 	cardbus_conf_write(cc, cf, tag, reg, address);
188 	splx(s);
189 
190 	if (reg != CARDBUS_ROM_REG) {
191 		/* memory space BAR */
192 
193 		if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
194 			printf("cardbus_mem_find: expected type mem, "
195 			    "found i/o\n");
196 			return (1);
197 		}
198 		if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
199 			printf("cardbus_mem_find: expected mem type %08x, "
200 			    "found %08x\n", PCI_MAPREG_MEM_TYPE(type),
201 			    PCI_MAPREG_MEM_TYPE(address));
202 			return (1);
203 		}
204 	}
205 
206 	if (PCI_MAPREG_MEM_SIZE(mask) == 0) {
207 		printf("cardbus_mem_find: void region\n");
208 		return (1);
209 	}
210 
211 	switch (PCI_MAPREG_MEM_TYPE(address)) {
212 	case PCI_MAPREG_MEM_TYPE_32BIT:
213 	case PCI_MAPREG_MEM_TYPE_32BIT_1M:
214 		break;
215 	case PCI_MAPREG_MEM_TYPE_64BIT:
216 		printf("cardbus_mem_find: 64-bit memory mapping register\n");
217 		return (1);
218 	default:
219 		printf("cardbus_mem_find: reserved mapping register type\n");
220 		return (1);
221 	}
222 
223 	if (basep != 0)
224 		*basep = PCI_MAPREG_MEM_ADDR(address);
225 	if (sizep != 0)
226 		*sizep = PCI_MAPREG_MEM_SIZE(mask);
227 	if (flagsp != 0) {
228 		*flagsp =
229 #ifdef BUS_SPACE_MAP_PREFETCHABLE
230 		    PCI_MAPREG_MEM_PREFETCHABLE(address) ?
231 		      BUS_SPACE_MAP_PREFETCHABLE :
232 #endif
233 		0;
234 	}
235 
236 	return (0);
237 }
238 
239 /*
240  * int cardbus_mapreg_map(struct cardbus_softc *, int, int, cardbusreg_t,
241  *			  int bus_space_tag_t *, bus_space_handle_t *,
242  *			  bus_addr_t *, bus_size_t *)
243  *    This function maps bus-space on the value of Base Address
244  *   Register (BAR) indexed by the argument `reg' (the second argument).
245  *   When the value of the BAR is not valid, such as 0x00000000, a new
246  *   address should be allocated for the BAR and new address values is
247  *   written on the BAR.
248  */
249 int
250 cardbus_mapreg_map(struct cardbus_softc *sc, int func, int reg,
251     cardbusreg_t type, int busflags, bus_space_tag_t *tagp,
252     bus_space_handle_t *handlep, bus_addr_t *basep, bus_size_t *sizep)
253 {
254 	cardbus_chipset_tag_t cc = sc->sc_cc;
255 	cardbus_function_tag_t cf = sc->sc_cf;
256 	bus_space_tag_t bustag;
257 	rbus_tag_t rbustag;
258 	bus_space_handle_t handle;
259 	bus_addr_t base;
260 	bus_size_t size;
261 	int flags;
262 	int status = 0;
263 
264 	cardbustag_t tag = cardbus_make_tag(cc, cf, sc->sc_bus,
265 	    sc->sc_device, func);
266 
267 	DPRINTF(("cardbus_mapreg_map called: %s %x\n", sc->sc_dev.dv_xname,
268 	   type));
269 
270 	if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
271 		if (cardbus_io_find(cc, cf, tag, reg, type, &base, &size,
272 		    &flags))
273 			status = 1;
274 		bustag = sc->sc_iot;
275 		rbustag = sc->sc_rbus_iot;
276 	} else {
277 		if (cardbus_mem_find(cc, cf, tag, reg, type, &base, &size,
278 		    &flags))
279 			status = 1;
280 		bustag = sc->sc_memt;
281 		rbustag = sc->sc_rbus_memt;
282 	}
283 	if (status == 0) {
284 		bus_addr_t mask = size - 1;
285 		if (base != 0)
286 			mask = 0xffffffff;
287 		if ((*cf->cardbus_space_alloc)(cc, rbustag, base, size, mask,
288 		    size, busflags | flags, &base, &handle)) {
289 			panic("io alloc");
290 		}
291 	}
292 	cardbus_conf_write(cc, cf, tag, reg, base);
293 
294 	DPRINTF(("cardbus_mapreg_map: physaddr %lx\n", (unsigned long)base));
295 
296 	if (tagp != 0)
297 		*tagp = bustag;
298 	if (handlep != 0)
299 		*handlep = handle;
300 	if (basep != 0)
301 		*basep = base;
302 	if (sizep != 0)
303 		*sizep = size;
304 	cardbus_free_tag(cc, cf, tag);
305 
306 	return (0);
307 }
308 
309 /*
310  * int cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
311  *			    bus_space_tag_t tag, bus_space_handle_t handle,
312  *			    bus_size_t size)
313  *
314  *   This function releases bus-space region and close memory or io
315  *   window on the bridge.
316  *
317  *  Arguments:
318  *   struct cardbus_softc *sc; the pointer to the device structure of cardbus.
319  *   int func; the number of function on the device.
320  *   int reg; the offset of BAR register.
321  */
322 int
323 cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
324     bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t size)
325 {
326 	cardbus_chipset_tag_t cc = sc->sc_cc;
327 	cardbus_function_tag_t cf = sc->sc_cf;
328 	int st = 1;
329 	cardbustag_t cardbustag;
330 	rbus_tag_t rbustag;
331 
332 	if (sc->sc_iot == tag) {
333 		/* bus space is io space */
334 		DPRINTF(("%s: unmap i/o space\n", sc->sc_dev.dv_xname));
335 		rbustag = sc->sc_rbus_iot;
336 	} else if (sc->sc_memt == tag) {
337 		/* bus space is memory space */
338 		DPRINTF(("%s: unmap mem space\n", sc->sc_dev.dv_xname));
339 		rbustag = sc->sc_rbus_memt;
340 	} else
341 		return (1);
342 
343 	cardbustag = cardbus_make_tag(cc, cf, sc->sc_bus, sc->sc_device, func);
344 
345 	cardbus_conf_write(cc, cf, cardbustag, reg, 0);
346 
347 	(*cf->cardbus_space_free)(cc, rbustag, handle, size);
348 
349 	cardbus_free_tag(cc, cf, cardbustag);
350 
351 	return (st);
352 }
353 
354 /*
355  * int cardbus_save_bar(cardbus_devfunc_t);
356  *
357  *   This function saves the Base Address Registers at the CardBus
358  *   function denoted by the argument.
359  */
360 int
361 cardbus_save_bar(cardbus_devfunc_t ct)
362 {
363 	cardbustag_t tag = Cardbus_make_tag(ct);
364 	cardbus_chipset_tag_t cc = ct->ct_cc;
365 	cardbus_function_tag_t cf = ct->ct_cf;
366 
367 	ct->ct_bar[0] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE0_REG);
368 	ct->ct_bar[1] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE1_REG);
369 	ct->ct_bar[2] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE2_REG);
370 	ct->ct_bar[3] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE3_REG);
371 	ct->ct_bar[4] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE4_REG);
372 	ct->ct_bar[5] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE5_REG);
373 
374 	DPRINTF(("cardbus_save_bar: %x %x\n", ct->ct_bar[0], ct->ct_bar[1]));
375 
376 	Cardbus_free_tag(ct, tag);
377 
378 	return (0);
379 }
380 
381 /*
382  * int cardbus_restore_bar(cardbus_devfunc_t);
383  *
384  *   This function saves the Base Address Registers at the CardBus
385  *   function denoted by the argument.
386  */
387 int
388 cardbus_restore_bar(cardbus_devfunc_t ct)
389 {
390 	cardbustag_t tag = Cardbus_make_tag(ct);
391 	cardbus_chipset_tag_t cc = ct->ct_cc;
392 	cardbus_function_tag_t cf = ct->ct_cf;
393 
394 	cardbus_conf_write(cc, cf, tag, CARDBUS_BASE0_REG, ct->ct_bar[0]);
395 	cardbus_conf_write(cc, cf, tag, CARDBUS_BASE1_REG, ct->ct_bar[1]);
396 	cardbus_conf_write(cc, cf, tag, CARDBUS_BASE2_REG, ct->ct_bar[2]);
397 	cardbus_conf_write(cc, cf, tag, CARDBUS_BASE3_REG, ct->ct_bar[3]);
398 	cardbus_conf_write(cc, cf, tag, CARDBUS_BASE4_REG, ct->ct_bar[4]);
399 	cardbus_conf_write(cc, cf, tag, CARDBUS_BASE5_REG, ct->ct_bar[5]);
400 
401 	Cardbus_free_tag(ct, tag);
402 
403 	return (0);
404 }
405