Home | History | Annotate | Line # | Download | only in dev
psycho.c revision 1.1
      1 /*	$NetBSD: psycho.c,v 1.1 1999/06/04 13:42:14 mrg Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1999 Matthew R. Green
      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  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * PCI support for UltraSPARC `psycho'
     33  */
     34 
     35 #undef DEBUG
     36 #define DEBUG
     37 
     38 #ifdef DEBUG
     39 #define	PDB_PROM	0x1
     40 #define	PDB_IOMMU	0x2
     41 int psycho_debug = 0;
     42 #define DPRINTF(l, s)   do { if (psycho_debug & l) printf s; } while (0)
     43 #else
     44 #define DPRINTF(l, s)
     45 #endif
     46 
     47 #include <sys/param.h>
     48 #include <sys/extent.h>
     49 #include <sys/time.h>
     50 #include <sys/systm.h>
     51 #include <sys/errno.h>
     52 #include <sys/device.h>
     53 #include <sys/malloc.h>
     54 
     55 #include <vm/vm.h>
     56 #include <vm/vm_kern.h>
     57 
     58 #define _SPARC_BUS_DMA_PRIVATE
     59 #include <machine/bus.h>
     60 #include <machine/autoconf.h>
     61 
     62 #include <dev/pci/pcivar.h>
     63 #include <dev/pci/pcireg.h>
     64 
     65 #include <sparc64/dev/iommureg.h>
     66 #include <sparc64/dev/iommuvar.h>
     67 #include <sparc64/dev/psychoreg.h>
     68 #include <sparc64/dev/psychovar.h>
     69 
     70 static pci_chipset_tag_t psycho_alloc_chipset __P((struct psycho_pbm *, int,
     71 						   pci_chipset_tag_t));
     72 static void psycho_get_bus_range __P((int, int *));
     73 static void psycho_get_ranges __P((int, struct psycho_ranges **, int *));
     74 static void psycho_get_registers __P((int, struct psycho_registers **, int *));
     75 static void psycho_get_intmap __P((int, struct psycho_interrupt_map **, int *));
     76 static void psycho_get_intmapmask __P((int, struct psycho_interrupt_map_mask *));
     77 
     78 /* IOMMU support */
     79 static void psycho_iommu_init __P((struct psycho_softc *));
     80 
     81 extern struct sparc_pci_chipset _sparc_pci_chipset;
     82 
     83 /*
     84  * autoconfiguration
     85  */
     86 static	int	psycho_match __P((struct device *, struct cfdata *, void *));
     87 static	void	psycho_attach __P((struct device *, struct device *, void *));
     88 static	int	psycho_print __P((void *aux, const char *p));
     89 
     90 static	void	sabre_init __P((struct psycho_softc *, struct pcibus_attach_args *));
     91 static	void	psycho_init __P((struct psycho_softc *, struct pcibus_attach_args *));
     92 
     93 struct cfattach psycho_ca = {
     94         sizeof(struct psycho_softc), psycho_match, psycho_attach
     95 };
     96 
     97 /*
     98  * "sabre" is the UltraSPARC IIi onboard PCI interface, normally connected to
     99  * an APB (advanced PCI bridge), which was designed specifically for the IIi.
    100  * the APB appears as two "simba"'s underneath the sabre.  real devices
    101  * typically appear on the "simba"'s only.
    102  *
    103  * a pair of "psycho"s sit on the mainbus and have real devices attached to
    104  * them.  they implemented in the U2P (UPA to PCI).  these two devices share
    105  * register space and as such need to be configured together, even though the
    106  * autoconfiguration will attach them separately.
    107  *
    108  * each of these appears as two usable PCI busses, though the sabre itself
    109  * takes pci0 in this case, leaving real devices on pci1 and pci2.  there can
    110  * be multiple pairs of psycho's, however, in multi-board machines.
    111  */
    112 #define	ROM_PCI_NAME		"pci"
    113 #define ROM_SABRE_MODEL		"SUNW,sabre"
    114 #define ROM_SIMBA_MODEL		"SUNW,simba"
    115 #define ROM_PSYCHO_MODEL	"SUNW,psycho"
    116 
    117 static	int
    118 psycho_match(parent, match, aux)
    119 	struct device	*parent;
    120 	struct cfdata	*match;
    121 	void		*aux;
    122 {
    123 	struct mainbus_attach_args *ma = aux;
    124 	char *model = getpropstring(ma->ma_node, "model");
    125 
    126 	/* match on a name of "pci" and a sabre or a psycho */
    127 	if (strcmp(ma->ma_name, ROM_PCI_NAME) == 0 &&
    128 	    (strcmp(model, ROM_SABRE_MODEL) == 0 ||
    129 	     strcmp(model, ROM_PSYCHO_MODEL) == 0))
    130 		return (1);
    131 
    132 	return (0);
    133 }
    134 
    135 static	void
    136 psycho_attach(parent, self, aux)
    137 	struct device *parent, *self;
    138 	void *aux;
    139 {
    140 	struct psycho_softc *sc = (struct psycho_softc *)self;
    141 	struct pcibus_attach_args pba;
    142 	struct mainbus_attach_args *ma = aux;
    143 	bus_space_handle_t bh;
    144 	char *model = getpropstring(ma->ma_node, "model");
    145 
    146 	printf("\n");
    147 
    148 	sc->sc_node = ma->ma_node;
    149 	sc->sc_bustag = ma->ma_bustag;
    150 	sc->sc_dmatag = ma->ma_dmatag;
    151 
    152 	/*
    153 	 * pull in all the information about the psycho as we can.
    154 	 */
    155 
    156 	/*
    157 	 * XXX use the prom address for the psycho registers?  we do so far.
    158 	 */
    159 	sc->sc_regs = (struct psychoreg *)(u_long)ma->ma_address[0];
    160 	sc->sc_basepaddr = (paddr_t)ma->ma_reg[0].ur_paddr;
    161 
    162 	/*
    163 	 * call the model-specific initialisation routine.
    164 	 */
    165 	if (strcmp(model, ROM_SABRE_MODEL) == 0)
    166 		sabre_init(sc, &pba);
    167 	else if (strcmp(model, ROM_PSYCHO_MODEL) == 0)
    168 		psycho_init(sc, &pba);
    169 #ifdef DIAGNOSTIC
    170 	else
    171 		panic("psycho_attach: unknown model %s?", model);
    172 #endif
    173 
    174 	/*
    175 	 * get us a config space tag, and punch in the physical address
    176 	 * of the PCI configuration space.  note that we use unmapped
    177 	 * access to PCI configuration space, relying on the bus space
    178 	 * macros to provide the proper ASI based on the bus tag.
    179 	 */
    180 	sc->sc_configtag = psycho_alloc_config_tag(sc->sc_simba_a);
    181 #if 0
    182 	sc->sc_configaddr = (paddr_t)sc->sc_basepaddr + 0x01000000;
    183 #else
    184 	if (bus_space_map2(ma->ma_bustag,
    185 			  PCI_CONFIG_BUS_SPACE,
    186 			  sc->sc_basepaddr + 0x01000000,
    187 			  0x0100000,
    188 			  0,
    189 			  0,
    190 			  &bh))
    191 		panic("could not map sabre PCI configuration space");
    192 	sc->sc_configaddr = (paddr_t)bh;
    193 #endif
    194 
    195 	/*
    196 	 * attach the pci.. note we pass PCI A tags, etc., for the sabre here.
    197 	 */
    198 	pba.pba_busname = "pci";
    199 	pba.pba_flags = sc->sc_psycho_this->pp_flags;
    200 	pba.pba_dmat = sc->sc_psycho_this->pp_dmat;
    201 	pba.pba_iot = sc->sc_psycho_this->pp_iot;
    202 	pba.pba_memt = sc->sc_psycho_this->pp_memt;
    203 
    204 	config_found(self, &pba, psycho_print);
    205 }
    206 
    207 static	int
    208 psycho_print(aux, p)
    209 	void *aux;
    210 	const char *p;
    211 {
    212 
    213 	if (p == NULL)
    214 		return (UNCONF);
    215 	return (QUIET);
    216 }
    217 
    218 /*
    219  * SUNW,sabre initialisation ..
    220  *	- get the sabre's ranges.  this are used for both simba's.
    221  *	- find the two SUNW,simba's underneath (a and b)
    222  *	- work out which simba is which via the bus-range property
    223  *	- get each simba's interrupt-map and interrupt-map-mask.
    224  *	- turn on the iommu
    225  */
    226 static void
    227 sabre_init(sc, pba)
    228 	struct psycho_softc *sc;
    229 	struct pcibus_attach_args *pba;
    230 {
    231 	struct psycho_pbm *pp;
    232 	u_int64_t csr;
    233 	int node;
    234 	int sabre_br[2], simba_br[2];
    235 
    236 	/* who? said a voice, incredulous */
    237 	sc->sc_mode = PSYCHO_MODE_SABRE;
    238 	printf("sabre: ");
    239 
    240 	/* setup the PCI control register; there is only one for the sabre */
    241 	csr = bus_space_read_8(sc->sc_bustag, &sc->sc_regs->psy_pcictl[0].pci_csr, 0);
    242 	csr = PCICTL_SERR | PCICTL_ARB_PARK | PCICTL_ERRINTEN | PCICTL_4ENABLE;
    243 	bus_space_write_8(sc->sc_bustag, &sc->sc_regs->psy_pcictl[0].pci_csr, 0, csr);
    244 
    245 	/* allocate a pair of psycho_pbm's for our simba's */
    246 	sc->sc_sabre = malloc(sizeof *pp, M_DEVBUF, M_NOWAIT);
    247 	sc->sc_simba_a = malloc(sizeof *pp, M_DEVBUF, M_NOWAIT);
    248 	sc->sc_simba_b = malloc(sizeof *pp, M_DEVBUF, M_NOWAIT);
    249 	if (sc->sc_simba_a == NULL || sc->sc_simba_b == NULL)
    250 		panic("could not allocate simba pbm's");
    251 
    252 	memset(sc->sc_sabre, 0, sizeof *pp);
    253 	memset(sc->sc_simba_a, 0, sizeof *pp);
    254 	memset(sc->sc_simba_b, 0, sizeof *pp);
    255 
    256 	/* grab the sabre ranges; use them for both simba's */
    257 	psycho_get_ranges(sc->sc_node, &sc->sc_sabre->pp_range,
    258 	    &sc->sc_sabre->pp_nrange);
    259 	sc->sc_simba_b->pp_range = sc->sc_simba_a->pp_range =
    260 	    sc->sc_sabre->pp_range;
    261 	sc->sc_simba_b->pp_nrange = sc->sc_simba_a->pp_nrange =
    262 	    sc->sc_sabre->pp_nrange;
    263 
    264 	/* get the bus-range for the sabre.  we expect 0..2 */
    265 	psycho_get_bus_range(sc->sc_node, sabre_br);
    266 
    267 	pba->pba_bus = sabre_br[0];
    268 
    269 	printf("bus range %u to %u", sabre_br[0], sabre_br[1]);
    270 
    271 	for (node = firstchild(sc->sc_node); node; node = nextsibling(node)) {
    272 		char *name = getpropstring(node, "name");
    273 		char *model, who;
    274 
    275 		if (strcmp(name, ROM_PCI_NAME) != 0)
    276 			continue;
    277 
    278 		model = getpropstring(node, "model");
    279 		if (strcmp(model, ROM_SIMBA_MODEL) != 0)
    280 			continue;
    281 
    282 		psycho_get_bus_range(node, simba_br);
    283 
    284 		if (simba_br[0] == 1) {		/* PCI B */
    285 			pp = sc->sc_simba_b;
    286 			pp->pp_pcictl = &sc->sc_regs->psy_pcictl[1];
    287 			pp->pp_sb_diag = &sc->sc_regs->psy_strbufdiag[1];
    288 			who = 'b';
    289 		} else {			/* PCI A */
    290 			pp = sc->sc_simba_a;
    291 			pp->pp_pcictl = &sc->sc_regs->psy_pcictl[0];
    292 			pp->pp_sb_diag = &sc->sc_regs->psy_strbufdiag[0];
    293 			who = 'a';
    294 		}
    295 		/* link us in .. */
    296 		pp->pp_sc = sc;
    297 
    298 		printf("; simba %c, PCI bus %d", who, simba_br[0]);
    299 
    300 		/* grab the simba registers, interrupt map and map mask */
    301 		psycho_get_registers(node, &pp->pp_regs, &pp->pp_nregs);
    302 		psycho_get_intmap(node, &pp->pp_intmap, &pp->pp_nintmap);
    303 		psycho_get_intmapmask(node, &pp->pp_intmapmask);
    304 
    305 		/* allocate our tags */
    306 		pp->pp_memt = psycho_alloc_mem_tag(pp);
    307 		pp->pp_iot = psycho_alloc_io_tag(pp);
    308 		pp->pp_dmat = psycho_alloc_dma_tag(pp);
    309 		pp->pp_flags = (pp->pp_memt ? PCI_FLAGS_MEM_ENABLED : 0) |
    310 			       (pp->pp_iot ? PCI_FLAGS_IO_ENABLED : 0);
    311 
    312 		/* allocate a chipset for this */
    313 		pp->pp_pc = psycho_alloc_chipset(pp, node, &_sparc_pci_chipset);
    314 	}
    315 
    316 	/* setup the rest of the sabre pbm */
    317 	pp = sc->sc_sabre;
    318 	pp->pp_sc = sc;
    319 	pp->pp_memt = sc->sc_psycho_this->pp_memt;
    320 	pp->pp_iot = sc->sc_psycho_this->pp_iot;
    321 	pp->pp_dmat = sc->sc_psycho_this->pp_dmat;
    322 	pp->pp_flags = sc->sc_psycho_this->pp_flags;
    323 	pp->pp_intmap = NULL;
    324 	pp->pp_regs = NULL;
    325 	pp->pp_pcictl = sc->sc_psycho_this->pp_pcictl;
    326 	pp->pp_sb_diag = sc->sc_psycho_this->pp_sb_diag;
    327 	pba->pba_pc = psycho_alloc_chipset(pp, sc->sc_node,
    328 	    sc->sc_psycho_this->pp_pc);
    329 
    330 	printf("\n");
    331 
    332 	/* and finally start up the IOMMU ... */
    333 	psycho_iommu_init(sc);
    334 }
    335 
    336 /*
    337  * SUNW,psycho initialisation ..
    338  *	- XXX what do we do here?
    339  *
    340  * i think that an attaching psycho should here find it's partner psycho
    341  * and if they haven't been attached yet, allocate both psycho_pbm's and
    342  * fill them both in here, and when the partner attaches, there is little
    343  * to do... perhaps keep a static array of what psycho have been found so
    344  * far (or perhaps those that have not yet been finished).  .mrg.
    345  * note that the partner can be found via matching `ranges' properties.
    346  */
    347 static void
    348 psycho_init(sc, pba)
    349 	struct psycho_softc *sc;
    350 	struct pcibus_attach_args *pba;
    351 {
    352 
    353 	/*
    354 	 * ok, we are a psycho.
    355 	 */
    356 	panic("can't do SUNW,psycho yet");
    357 }
    358 
    359 /*
    360  * PCI bus support
    361  */
    362 
    363 /*
    364  * allocate a PCI chipset tag and set it's cookie.
    365  */
    366 static pci_chipset_tag_t
    367 psycho_alloc_chipset(pp, node, pc)
    368 	struct psycho_pbm *pp;
    369 	int node;
    370 	pci_chipset_tag_t pc;
    371 {
    372 	pci_chipset_tag_t npc;
    373 
    374 	npc = malloc(sizeof *npc, M_DEVBUF, M_NOWAIT);
    375 	if (npc == NULL)
    376 		panic("could not allocate pci_chipset_tag_t");
    377 	memcpy(npc, pc, sizeof *pc);
    378 	npc->cookie = pp;
    379 	npc->node = node;
    380 
    381 	return (npc);
    382 }
    383 
    384 /*
    385  * grovel the OBP for various psycho properties
    386  */
    387 static void
    388 psycho_get_bus_range(node, brp)
    389 	int node;
    390 	int *brp;
    391 {
    392 	int n;
    393 
    394 	if (getprop(node, "bus-range", sizeof(*brp), &n, (void **)&brp))
    395 		panic("could not get psycho bus-range");
    396 	if (n != 2)
    397 		panic("broken psycho bus-range");
    398 	DPRINTF(PDB_PROM, ("psycho debug: got `bus-range' for node %08x: %u - %u\n", node, brp[0], brp[1]));
    399 }
    400 
    401 static void
    402 psycho_get_ranges(node, rp, np)
    403 	int node;
    404 	struct psycho_ranges **rp;
    405 	int *np;
    406 {
    407 
    408 	if (getprop(node, "ranges", sizeof(**rp), np, (void **)rp))
    409 		panic("could not get psycho ranges");
    410 	DPRINTF(PDB_PROM, ("psycho debug: got `ranges' for node %08x: %d entries\n", node, *np));
    411 }
    412 
    413 static void
    414 psycho_get_registers(node, rp, np)
    415 	int node;
    416 	struct psycho_registers **rp;
    417 	int *np;
    418 {
    419 
    420 	if (getprop(node, "reg", sizeof(**rp), np, (void **)rp))
    421 		panic("could not get psycho registers");
    422 	DPRINTF(PDB_PROM, ("psycho debug: got `reg' for node %08x: %d entries\n", node, *np));
    423 }
    424 
    425 static void
    426 psycho_get_intmap(node, imp, np)
    427 	int node;
    428 	struct psycho_interrupt_map **imp;
    429 	int *np;
    430 {
    431 
    432 	if (getprop(node, "interrupt-map", sizeof(**imp), np, (void **)imp))
    433 		panic("could not get psycho interrupt-map");
    434 	DPRINTF(PDB_PROM, ("psycho debug: got `interupt-map' for node %08x\n", node));
    435 }
    436 
    437 static void
    438 psycho_get_intmapmask(node, immp)
    439 	int node;
    440 	struct psycho_interrupt_map_mask *immp;
    441 {
    442 	int n;
    443 
    444 	if (getprop(node, "interrupt-map-mask", sizeof(*immp), &n,
    445 	    (void **)&immp))
    446 		panic("could not get psycho interrupt-map-mask");
    447 	if (n != 1)
    448 		panic("broken psycho interrupt-map-mask");
    449 	DPRINTF(PDB_PROM, ("psycho debug: got `interrupt-map-mask' for node %08x\n", node));
    450 }
    451 
    452 /*
    453  * IOMMU code
    454  */
    455 
    456 /*
    457  * initialise the IOMMU..
    458  */
    459 void
    460 psycho_iommu_init(sc)
    461 	struct psycho_softc *sc;
    462 {
    463 	char *name;
    464 
    465 	/* punch in our copies */
    466 	sc->sc_is.is_bustag = sc->sc_bustag;
    467 	sc->sc_is.is_iommu = &sc->sc_regs->psy_iommu;
    468 	sc->sc_is.is_sb = &sc->sc_regs->psy_iommu_strbuf;
    469 
    470 	/* give us a nice name.. */
    471 	name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
    472 	if (name == 0)
    473 		panic("couldn't malloc iommu name");
    474 	snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname);
    475 
    476 	DPRINTF(PDB_IOMMU, ("psycho base %p phys %p\n", (long)sc->sc_regs, (long)pmap_extract(pmap_kernel(), (vaddr_t)sc->sc_regs)));
    477 
    478 	/* XXX XXX XXX FIX ME tsbsize XXX XXX XXX */
    479 	iommu_init(name, &sc->sc_is, 0);
    480 }
    481