xref: /netbsd-src/sys/dev/cardbus/cardbus_map.c (revision 3fa968935ade51db60b1c478a23101105a0b0dbb)
1*3fa96893Sdyoung /*	$NetBSD: cardbus_map.c,v 1.36 2010/03/15 19:48:31 dyoung Exp $	*/
24eee1111Shaya 
34eee1111Shaya /*
4ded26ac3Shaya  * Copyright (c) 1999 and 2000
54eee1111Shaya  *      HAYAKAWA Koichi.  All rights reserved.
64eee1111Shaya  *
74eee1111Shaya  * Redistribution and use in source and binary forms, with or without
84eee1111Shaya  * modification, are permitted provided that the following conditions
94eee1111Shaya  * are met:
104eee1111Shaya  * 1. Redistributions of source code must retain the above copyright
114eee1111Shaya  *    notice, this list of conditions and the following disclaimer.
124eee1111Shaya  * 2. Redistributions in binary form must reproduce the above copyright
134eee1111Shaya  *    notice, this list of conditions and the following disclaimer in the
144eee1111Shaya  *    documentation and/or other materials provided with the distribution.
154eee1111Shaya  *
164eee1111Shaya  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
174eee1111Shaya  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
184eee1111Shaya  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
194eee1111Shaya  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
204eee1111Shaya  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
214eee1111Shaya  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
224eee1111Shaya  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234eee1111Shaya  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
244eee1111Shaya  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
254eee1111Shaya  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
264eee1111Shaya  * POSSIBILITY OF SUCH DAMAGE.
274eee1111Shaya  */
284eee1111Shaya 
29f61cbe74Slukem #include <sys/cdefs.h>
30*3fa96893Sdyoung __KERNEL_RCSID(0, "$NetBSD: cardbus_map.c,v 1.36 2010/03/15 19:48:31 dyoung Exp $");
314eee1111Shaya 
324eee1111Shaya #include <sys/param.h>
334eee1111Shaya #include <sys/systm.h>
344eee1111Shaya #include <sys/device.h>
354eee1111Shaya 
36a2a38285Sad #include <sys/bus.h>
374eee1111Shaya 
384eee1111Shaya #include <dev/cardbus/cardbusvar.h>
394eee1111Shaya 
404eee1111Shaya #include <dev/pci/pcireg.h>	/* XXX */
414eee1111Shaya 
424eee1111Shaya #if defined DEBUG && !defined CARDBUS_MAP_DEBUG
434eee1111Shaya #define CARDBUS_MAP_DEBUG
444eee1111Shaya #endif
454eee1111Shaya 
464eee1111Shaya #if defined CARDBUS_MAP_DEBUG
474eee1111Shaya #define STATIC
484eee1111Shaya #define DPRINTF(a) printf a
494eee1111Shaya #else
504eee1111Shaya #define STATIC static
514eee1111Shaya #define DPRINTF(a)
524eee1111Shaya #endif
534eee1111Shaya 
544eee1111Shaya 
5518db93c7Sperry static int cardbus_io_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
568089c2dcSdyoung 				pcitag_t, int, pcireg_t,
5718db93c7Sperry 				bus_addr_t *, bus_size_t *, int *);
5818db93c7Sperry static int cardbus_mem_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
598089c2dcSdyoung 				 pcitag_t, int, pcireg_t,
6018db93c7Sperry 				 bus_addr_t *, bus_size_t *, int *);
614eee1111Shaya 
624eee1111Shaya /*
634eee1111Shaya  * static int cardbus_io_find(cardbus_chipset_tag_t cc,
648089c2dcSdyoung  *			      cardbus_function_tag_t cf, pcitag_t tag,
658089c2dcSdyoung  *			      int reg, pcireg_t type, bus_addr_t *basep,
664eee1111Shaya  *			      bus_size_t *sizep, int *flagsp)
6706ab77c6Swiz  * This code is stolen from sys/dev/pci_map.c.
684eee1111Shaya  */
694eee1111Shaya static int
cardbus_io_find(cardbus_chipset_tag_t cc,cardbus_function_tag_t cf,pcitag_t tag,int reg,pcireg_t type,bus_addr_t * basep,bus_size_t * sizep,int * flagsp)704d595fd7Schristos cardbus_io_find(
714d595fd7Schristos     cardbus_chipset_tag_t cc,
724d595fd7Schristos     cardbus_function_tag_t cf,
738089c2dcSdyoung     pcitag_t tag,
744d595fd7Schristos     int reg,
758089c2dcSdyoung     pcireg_t type,
764d595fd7Schristos     bus_addr_t *basep,
774d595fd7Schristos     bus_size_t *sizep,
784d595fd7Schristos     int *flagsp)
794eee1111Shaya {
808089c2dcSdyoung 	pcireg_t address, mask;
814eee1111Shaya 	int s;
824eee1111Shaya 
83e54d837bShaya 	/* EXT ROM is able to map on memory space ONLY. */
84e54d837bShaya 	if (reg == CARDBUS_ROM_REG) {
85e54d837bShaya 		return 1;
86e54d837bShaya 	}
87e54d837bShaya 
88e54d837bShaya 	if(reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) {
894eee1111Shaya 		panic("cardbus_io_find: bad request");
904eee1111Shaya 	}
914eee1111Shaya 
924eee1111Shaya 	/*
934eee1111Shaya 	 * Section 6.2.5.1, `Address Maps', tells us that:
944eee1111Shaya 	 *
954eee1111Shaya 	 * 1) The builtin software should have already mapped the device in a
964eee1111Shaya 	 * reasonable way.
974eee1111Shaya 	 *
984eee1111Shaya 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
994eee1111Shaya 	 * n bits of the address to 0.  As recommended, we write all 1s and see
1004eee1111Shaya 	 * what we get back.
1014eee1111Shaya 	 */
1024eee1111Shaya 	s = splhigh();
1034eee1111Shaya 	address = cardbus_conf_read(cc, cf, tag, reg);
1044eee1111Shaya 	cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
1054eee1111Shaya 	mask = cardbus_conf_read(cc, cf, tag, reg);
1064eee1111Shaya 	cardbus_conf_write(cc, cf, tag, reg, address);
1074eee1111Shaya 	splx(s);
1084eee1111Shaya 
1094eee1111Shaya 	if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
110e54d837bShaya 		printf("cardbus_io_find: expected type i/o, found mem\n");
1114eee1111Shaya 		return 1;
1124eee1111Shaya 	}
1134eee1111Shaya 
1144eee1111Shaya 	if (PCI_MAPREG_IO_SIZE(mask) == 0) {
115e54d837bShaya 		printf("cardbus_io_find: void region\n");
116ded26ac3Shaya 		return 1;
1174eee1111Shaya 	}
1184eee1111Shaya 
1194eee1111Shaya 	if (basep != 0) {
1204eee1111Shaya 		*basep = PCI_MAPREG_IO_ADDR(address);
1214eee1111Shaya 	}
1224eee1111Shaya 	if (sizep != 0) {
1234eee1111Shaya 		*sizep = PCI_MAPREG_IO_SIZE(mask);
1244eee1111Shaya 	}
1254eee1111Shaya 	if (flagsp != 0) {
1264eee1111Shaya 		*flagsp = 0;
1274eee1111Shaya 	}
1284eee1111Shaya 
1294eee1111Shaya 	return 0;
1304eee1111Shaya }
1314eee1111Shaya 
1324eee1111Shaya 
1334eee1111Shaya 
1344eee1111Shaya /*
1354eee1111Shaya  * static int cardbus_mem_find(cardbus_chipset_tag_t cc,
1368089c2dcSdyoung  *			       cardbus_function_tag_t cf, pcitag_t tag,
1378089c2dcSdyoung  *			       int reg, pcireg_t type, bus_addr_t *basep,
1384eee1111Shaya  *			       bus_size_t *sizep, int *flagsp)
13906ab77c6Swiz  * This code is stolen from sys/dev/pci_map.c.
1404eee1111Shaya  */
1414eee1111Shaya static int
cardbus_mem_find(cardbus_chipset_tag_t cc,cardbus_function_tag_t cf,pcitag_t tag,int reg,pcireg_t type,bus_addr_t * basep,bus_size_t * sizep,int * flagsp)1428089c2dcSdyoung cardbus_mem_find(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf, pcitag_t tag, int reg, pcireg_t type, bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
1434eee1111Shaya {
1448089c2dcSdyoung 	pcireg_t address, mask;
1454eee1111Shaya 	int s;
1464eee1111Shaya 
1474d92da53Sjoda 	if (reg != CARDBUS_ROM_REG &&
1484d92da53Sjoda 	    (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))) {
149e54d837bShaya 		panic("cardbus_mem_find: bad request");
1504eee1111Shaya 	}
1514eee1111Shaya 
1524eee1111Shaya 	/*
1534eee1111Shaya 	 * Section 6.2.5.1, `Address Maps', tells us that:
1544eee1111Shaya 	 *
1554eee1111Shaya 	 * 1) The builtin software should have already mapped the device in a
1564eee1111Shaya 	 * reasonable way.
1574eee1111Shaya 	 *
1584eee1111Shaya 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
1594eee1111Shaya 	 * n bits of the address to 0.  As recommended, we write all 1s and see
1604eee1111Shaya 	 * what we get back.
1614eee1111Shaya 	 */
1624eee1111Shaya 	s = splhigh();
1634eee1111Shaya 	address = cardbus_conf_read(cc, cf, tag, reg);
1644eee1111Shaya 	cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
1654eee1111Shaya 	mask = cardbus_conf_read(cc, cf, tag, reg);
1664eee1111Shaya 	cardbus_conf_write(cc, cf, tag, reg, address);
1674eee1111Shaya 	splx(s);
1684eee1111Shaya 
169e54d837bShaya 	if (reg != CARDBUS_ROM_REG) {
170e54d837bShaya 		/* memory space BAR */
171e54d837bShaya 
1724eee1111Shaya 		if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
1734eee1111Shaya 			printf("cardbus_mem_find: expected type mem, found i/o\n");
1744eee1111Shaya 			return 1;
1754eee1111Shaya 		}
1764eee1111Shaya 		if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
1774eee1111Shaya 			printf("cardbus_mem_find: expected mem type %08x, found %08x\n",
1784eee1111Shaya 			    PCI_MAPREG_MEM_TYPE(type),
1794eee1111Shaya 			    PCI_MAPREG_MEM_TYPE(address));
1804eee1111Shaya 			return 1;
1814eee1111Shaya 		}
182e54d837bShaya 	}
1834eee1111Shaya 
1844eee1111Shaya 	if (PCI_MAPREG_MEM_SIZE(mask) == 0) {
1854eee1111Shaya 		printf("cardbus_mem_find: void region\n");
1864eee1111Shaya 		return 1;
1874eee1111Shaya 	}
1884eee1111Shaya 
1894eee1111Shaya 	switch (PCI_MAPREG_MEM_TYPE(address)) {
1904eee1111Shaya 	case PCI_MAPREG_MEM_TYPE_32BIT:
1914eee1111Shaya 	case PCI_MAPREG_MEM_TYPE_32BIT_1M:
1924eee1111Shaya 		break;
1934eee1111Shaya 	case PCI_MAPREG_MEM_TYPE_64BIT:
194e54d837bShaya 		printf("cardbus_mem_find: 64-bit memory mapping register\n");
1954eee1111Shaya 		return 1;
1964eee1111Shaya 	default:
1974eee1111Shaya 		printf("cardbus_mem_find: reserved mapping register type\n");
1984eee1111Shaya 		return 1;
1994eee1111Shaya 	}
2004eee1111Shaya 
2014eee1111Shaya 	if (basep != 0) {
2024eee1111Shaya 		*basep = PCI_MAPREG_MEM_ADDR(address);
2034eee1111Shaya 	}
2044eee1111Shaya 	if (sizep != 0) {
2054eee1111Shaya 		*sizep = PCI_MAPREG_MEM_SIZE(mask);
2064eee1111Shaya 	}
2074eee1111Shaya 	if (flagsp != 0) {
2081f723151Sdrochner 		*flagsp = PCI_MAPREG_MEM_PREFETCHABLE(address) ?
2091f723151Sdrochner 		    BUS_SPACE_MAP_PREFETCHABLE : 0;
2104eee1111Shaya 	}
2114eee1111Shaya 
2124eee1111Shaya 	return 0;
2134eee1111Shaya }
2144eee1111Shaya 
2154eee1111Shaya 
2164eee1111Shaya 
2174eee1111Shaya 
2184eee1111Shaya /*
2198089c2dcSdyoung  * int cardbus_mapreg_map(struct cardbus_softc *, int, int, pcireg_t,
2204eee1111Shaya  *			  int bus_space_tag_t *, bus_space_handle_t *,
2214eee1111Shaya  *			  bus_addr_t *, bus_size_t *)
2224eee1111Shaya  *    This function maps bus-space on the value of Base Address
2234eee1111Shaya  *   Register (BAR) indexed by the argument `reg' (the second argument).
2244eee1111Shaya  *   When the value of the BAR is not valid, such as 0x00000000, a new
2254eee1111Shaya  *   address should be allocated for the BAR and new address values is
2264eee1111Shaya  *   written on the BAR.
2274eee1111Shaya  */
2284eee1111Shaya int
cardbus_mapreg_map(struct cardbus_softc * sc,int func,int reg,pcireg_t type,int busflags,bus_space_tag_t * tagp,bus_space_handle_t * handlep,bus_addr_t * basep,bus_size_t * sizep)2298089c2dcSdyoung cardbus_mapreg_map(struct cardbus_softc *sc, int func, int reg, pcireg_t type, int busflags, bus_space_tag_t *tagp, bus_space_handle_t *handlep, bus_addr_t *basep, bus_size_t *sizep)
2304eee1111Shaya {
23191b09f5bShaya 	cardbus_chipset_tag_t cc = sc->sc_cc;
23291b09f5bShaya 	cardbus_function_tag_t cf = sc->sc_cf;
2334eee1111Shaya 	bus_space_tag_t bustag;
2344eee1111Shaya 	rbus_tag_t rbustag;
235159e9153Smartin 	bus_space_handle_t handle;
2364eee1111Shaya 	bus_addr_t base;
2374eee1111Shaya 	bus_size_t size;
2384eee1111Shaya 	int flags;
2394eee1111Shaya 	int status = 0;
2408089c2dcSdyoung 	pcitag_t tag;
2414eee1111Shaya 
242ce51c72bSmrg 	size = 0;	/* XXX gcc */
243ce51c72bSmrg 	flags = 0;	/* XXX gcc */
244ce51c72bSmrg 
24590ed6f0bSitohy 	tag = cardbus_make_tag(cc, cf, sc->sc_bus, func);
2464eee1111Shaya 
247dbc87578Sdrochner 	DPRINTF(("cardbus_mapreg_map called: %s %x\n", device_xname(sc->sc_dev),
2484eee1111Shaya 	   type));
2494eee1111Shaya 
2504eee1111Shaya 	if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
2514eee1111Shaya 		if (cardbus_io_find(cc, cf, tag, reg, type, &base, &size, &flags)) {
2524eee1111Shaya 			status = 1;
2534eee1111Shaya 		}
25491b09f5bShaya 		bustag = sc->sc_iot;
25591b09f5bShaya 		rbustag = sc->sc_rbus_iot;
2564eee1111Shaya 	} else {
2574eee1111Shaya 		if (cardbus_mem_find(cc, cf, tag, reg, type, &base, &size, &flags)){
2584eee1111Shaya 			status = 1;
2594eee1111Shaya 		}
26091b09f5bShaya 		bustag = sc->sc_memt;
26191b09f5bShaya 		rbustag = sc->sc_rbus_memt;
2624eee1111Shaya 	}
2634eee1111Shaya 	if (status == 0) {
2644eee1111Shaya 		bus_addr_t mask = size - 1;
2654eee1111Shaya 		if (base != 0) {
2664eee1111Shaya 			mask = 0xffffffff;
2674eee1111Shaya 		}
268ded26ac3Shaya 		if ((*cf->cardbus_space_alloc)(cc, rbustag, base, size, mask,
269ded26ac3Shaya 		    size, busflags | flags, &base, &handle)) {
2704eee1111Shaya 			panic("io alloc");
2714eee1111Shaya 		}
2724eee1111Shaya 	}
2734eee1111Shaya 	cardbus_conf_write(cc, cf, tag, reg, base);
2744eee1111Shaya 
2755a6772dfSjmc 	DPRINTF(("cardbus_mapreg_map: physaddr %lx\n", (unsigned long)base));
2764eee1111Shaya 
2774eee1111Shaya 	if (tagp != 0) {
2784eee1111Shaya 		*tagp = bustag;
2794eee1111Shaya 	}
2804eee1111Shaya 	if (handlep != 0) {
2814eee1111Shaya 		*handlep = handle;
2824eee1111Shaya 	}
2834eee1111Shaya 	if (basep != 0) {
2844eee1111Shaya 		*basep = base;
2854eee1111Shaya 	}
2864eee1111Shaya 	if (sizep != 0) {
2874eee1111Shaya 		*sizep = size;
2884eee1111Shaya 	}
28991b09f5bShaya 
2904eee1111Shaya 	return 0;
2914eee1111Shaya }
2924eee1111Shaya 
2934eee1111Shaya 
2944eee1111Shaya 
2954eee1111Shaya 
2964eee1111Shaya 
297ded26ac3Shaya /*
298ded26ac3Shaya  * int cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
299ded26ac3Shaya  *			    bus_space_tag_t tag, bus_space_handle_t handle,
300ded26ac3Shaya  *			    bus_size_t size)
301ded26ac3Shaya  *
302ded26ac3Shaya  *   This function releases bus-space region and close memory or io
303ded26ac3Shaya  *   window on the bridge.
304ded26ac3Shaya  *
305ded26ac3Shaya  *  Arguments:
306ded26ac3Shaya  *   struct cardbus_softc *sc; the pointer to the device structure of cardbus.
307ded26ac3Shaya  *   int func; the number of function on the device.
308ded26ac3Shaya  *   int reg; the offset of BAR register.
309ded26ac3Shaya  */
310ded26ac3Shaya int
cardbus_mapreg_unmap(struct cardbus_softc * sc,int func,int reg,bus_space_tag_t tag,bus_space_handle_t handle,bus_size_t size)31182357f6dSdsl cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg, bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t size)
312ded26ac3Shaya {
313ded26ac3Shaya 	cardbus_chipset_tag_t cc = sc->sc_cc;
314ded26ac3Shaya 	cardbus_function_tag_t cf = sc->sc_cf;
315ded26ac3Shaya 	int st = 1;
3168089c2dcSdyoung 	pcitag_t cardbustag;
317de839831Smycroft 	rbus_tag_t rbustag;
318ded26ac3Shaya 
319ded26ac3Shaya 	if (sc->sc_iot == tag) {
320ded26ac3Shaya 		/* bus space is io space */
321dbc87578Sdrochner 		DPRINTF(("%s: unmap i/o space\n", device_xname(sc->sc_dev)));
322de839831Smycroft 		rbustag = sc->sc_rbus_iot;
323de839831Smycroft 	} else if (sc->sc_memt == tag) {
324ded26ac3Shaya 		/* bus space is memory space */
325dbc87578Sdrochner 		DPRINTF(("%s: unmap mem space\n", device_xname(sc->sc_dev)));
326de839831Smycroft 		rbustag = sc->sc_rbus_memt;
327ded26ac3Shaya 	} else {
328ded26ac3Shaya 		return 1;
329ded26ac3Shaya 	}
330ded26ac3Shaya 
3311af44f3cSdrochner 	cardbustag = cardbus_make_tag(cc, cf, sc->sc_bus, func);
332ded26ac3Shaya 
333ded26ac3Shaya 	cardbus_conf_write(cc, cf, cardbustag, reg, 0);
334ded26ac3Shaya 
335de839831Smycroft 	(*cf->cardbus_space_free)(cc, rbustag, handle, size);
336ded26ac3Shaya 
337ded26ac3Shaya 	return st;
338ded26ac3Shaya }
339