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