Home | History | Annotate | Line # | Download | only in sparc64
      1 /*	$NetBSD: rbus_machdep.c,v 1.17 2019/03/01 09:25:59 msaitoh Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2003 Takeshi Nakayama.
      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  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: rbus_machdep.c,v 1.17 2019/03/01 09:25:59 msaitoh Exp $");
     30 
     31 #include <sys/param.h>
     32 #include <sys/device.h>
     33 #include <sys/extent.h>
     34 #include <sys/systm.h>
     35 
     36 #include <sys/bus.h>
     37 #include <machine/openfirm.h>
     38 #include <machine/promlib.h>
     39 #include <dev/pci/pcivar.h>
     40 #include <dev/pci/ppbreg.h>
     41 #include <sparc64/dev/iommuvar.h>
     42 #include <sparc64/dev/psychovar.h>
     43 
     44 #include <dev/cardbus/rbus.h>
     45 #include <dev/pcmcia/pcmciachip.h>
     46 #include <dev/ic/i82365reg.h>
     47 #include <dev/pci/pccbbreg.h>
     48 #include <dev/pci/pccbbvar.h>
     49 
     50 #ifdef RBUS_DEBUG
     51 # define DPRINTF printf
     52 #else
     53 # define DPRINTF while (0) printf
     54 #endif
     55 
     56 static int pccbb_cardbus_isvalid(void *);
     57 
     58 int
     59 md_space_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, int flags,
     60 	     bus_space_handle_t *bshp)
     61 {
     62 	DPRINTF("md_space_map: 0x%" PRIxPTR ", 0x%" PRIx64 ", 0x%" PRIx64 "\n",
     63 		(u_long)t->cookie, bpa, size);
     64 
     65 	return bus_space_map(t, bpa, size, flags, bshp);
     66 }
     67 
     68 void
     69 md_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size, bus_addr_t *adrp)
     70 {
     71 	DPRINTF("md_space_unmap: 0x%" PRIxPTR ", 0x%" PRIx64 ", 0x%" PRIx64
     72 		"\n", (u_long)t->cookie, bsh._ptr, size);
     73 
     74 	/* return the PCI offset address if required */
     75 	if (adrp != NULL)
     76 		*adrp = psycho_bus_offset(t, &bsh);
     77 	bus_space_unmap(t, bsh, size);
     78 }
     79 
     80 rbus_tag_t
     81 rbus_pccbb_parent_mem(struct pci_attach_args *pa)
     82 {
     83 	pci_chipset_tag_t pc = pa->pa_pc;
     84 	struct psycho_pbm *pp = pc->cookie;
     85 	struct extent *ex = pp->pp_exmem;
     86 	bus_addr_t start;
     87 	bus_size_t size;
     88 
     89 	if (ex == NULL)
     90 		panic("rbus_pccbb_parent_mem: extent is not initialized");
     91 
     92 	start = ex->ex_start;
     93 	size = ex->ex_end - start;
     94 
     95 	return rbus_new_root_share(pa->pa_memt, ex, start, size, 0);
     96 }
     97 
     98 rbus_tag_t
     99 rbus_pccbb_parent_io(struct pci_attach_args *pa)
    100 {
    101 	pci_chipset_tag_t pc = pa->pa_pc;
    102 	struct psycho_pbm *pp = pc->cookie;
    103 	struct extent *ex = pp->pp_exio;
    104 	bus_addr_t start;
    105 	bus_size_t size;
    106 
    107 	if (ex == NULL)
    108 		panic("rbus_pccbb_parent_io: extent is not initialized");
    109 
    110 	start = ex->ex_start;
    111 	size = ex->ex_end - start;
    112 
    113 	return rbus_new_root_share(pa->pa_iot, ex, start, size, 0);
    114 }
    115 
    116 /*
    117  * Machine dependent part for the attachment of PCI-CardBus bridge.
    118  * This function is called from pccbb_attach() in sys/dev/pci/pccbb.c.
    119  */
    120 void
    121 pccbb_attach_hook(device_t parent, device_t self, struct pci_attach_args *pa)
    122 {
    123 	pci_chipset_tag_t pc = pa->pa_pc;
    124 	pcireg_t reg;
    125 	int node = PCITAG_NODE(pa->pa_tag);
    126 	int error;
    127 	int bus, br[2], *brp;
    128 	int len, intr;
    129 
    130 	/*
    131 	 * bus fixup:
    132 	 *	if OBP didn't assign a bus number to the cardbus bridge,
    133 	 *	then assign it here.
    134 	 */
    135 	brp = br;
    136 	len = 2;
    137 	error = prom_getprop(node, "bus-range", sizeof(*brp), &len, &brp);
    138 	if (error == 0 && len == 2) {
    139 		bus = br[0];
    140 		DPRINTF("pccbb_attach_hook: bus-range %d-%d\n", br[0], br[1]);
    141 		if (bus < 0 || bus >= 256)
    142 			printf("pccbb_attach_hook: broken bus %d\n", bus);
    143 		else {
    144 #ifdef DIAGNOSTIC
    145 			if ((*pc->spc_busnode)[bus].node != 0)
    146 				printf("pccbb_attach_hook: override bus %d"
    147 				       " node %08x -> %08x\n",
    148 				       bus, (*pc->spc_busnode)[bus].node, node);
    149 #endif
    150 			(*pc->spc_busnode)[bus].arg = device_private(self);
    151 			(*pc->spc_busnode)[bus].valid = pccbb_cardbus_isvalid;
    152 			(*pc->spc_busnode)[bus].node = node;
    153 		}
    154 	} else {
    155 		bus = ++pc->spc_busmax;
    156 		DPRINTF("pccbb_attach_hook: bus %d\n", bus);
    157 		if (bus >= 256)
    158 			printf("pccbb_attach_hook: 256 >= busses exist\n");
    159 		else {
    160 			reg = pci_conf_read(pc, pa->pa_tag, PCI_BRIDGE_BUS_REG);
    161 			reg &= 0xff000000;
    162 			reg |= pa->pa_bus | (bus << 8) | (bus << 16);
    163 			pci_conf_write(pc, pa->pa_tag, PCI_BRIDGE_BUS_REG, reg);
    164 #ifdef DIAGNOSTIC
    165 			if ((*pc->spc_busnode)[bus].node != 0)
    166 				printf("pccbb_attach_hook: override bus %d"
    167 				       " node %08x -> %08x\n",
    168 				       bus, (*pc->spc_busnode)[bus].node, node);
    169 #endif
    170 			(*pc->spc_busnode)[bus].arg = device_private(self);
    171 			(*pc->spc_busnode)[bus].valid = pccbb_cardbus_isvalid;
    172 			(*pc->spc_busnode)[bus].node = node;
    173 		}
    174 	}
    175 
    176 	/*
    177 	 * interrupt fixup:
    178 	 *	fake interrupt line not for giving up the probe.
    179 	 *	interrupt numbers assigned by OBP are [0x00,0x3f],
    180 	 *	so they map to [0x40,0x7f] due to inhibit the value 0x00.
    181 	 */
    182 	if ((intr = prom_getpropint(node, "interrupts", -1)) == -1) {
    183 		printf("pccbb_attach_hook: could not read interrupts\n");
    184 		return;
    185 	}
    186 
    187 	if (OF_mapintr(node, &intr, sizeof(intr), sizeof(intr)) < 0) {
    188 		printf("pccbb_attach_hook: OF_mapintr failed\n");
    189 		return;
    190 	}
    191 
    192 	pa->pa_intrline = intr | 0x40;
    193 	DPRINTF("pccbb_attach_hook: interrupt line %d\n", intr);
    194 }
    195 
    196 /*
    197  * Detect a validity of CardBus bus, since it occurs PCI bus error
    198  * when a CardBus card is not present or power-off.
    199  */
    200 static int
    201 pccbb_cardbus_isvalid(void *arg)
    202 {
    203 	struct pccbb_softc *sc = arg;
    204 	bus_space_tag_t memt = sc->sc_base_memt;
    205 	bus_space_handle_t memh = sc->sc_base_memh;
    206 	uint32_t sockstat, sockctrl;
    207 
    208 	/* check CardBus card is present */
    209 	sockstat = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
    210 	DPRINTF("%s: pccbb_cardbus_isvalid: sockstat %08x\n",
    211 		device_xname(sc->sc_dev), sockstat);
    212 	if ((sockstat & CB_SOCKET_STAT_CB) == 0 ||
    213 	    (sockstat & CB_SOCKET_STAT_CD) != 0)
    214 		return 0;
    215 
    216 	/* check card is powered on */
    217 	sockctrl = bus_space_read_4(memt, memh, CB_SOCKET_CTRL);
    218 	DPRINTF("%s: pccbb_cardbus_isvalid: sockctrl %08x\n",
    219 		device_xname(sc->sc_dev), sockctrl);
    220 	if ((sockctrl & CB_SOCKET_CTRL_VCCMASK) == 0)
    221 		return 0;
    222 
    223 	/* card is present and powered on */
    224 	return 1;
    225 }
    226