Home | History | Annotate | Line # | Download | only in pci
pci_machdep.c revision 1.13
      1 /*	$NetBSD: pci_machdep.c,v 1.13 1998/08/15 03:02:35 mycroft Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1996 Leo Weppelman.  All rights reserved.
      5  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
      6  * Copyright (c) 1994 Charles M. Hannum.  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 Charles M. Hannum.
     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  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/types.h>
     35 #include <sys/param.h>
     36 #include <sys/time.h>
     37 #include <sys/systm.h>
     38 #include <sys/errno.h>
     39 #include <sys/device.h>
     40 
     41 #include <vm/vm.h>
     42 #include <vm/vm_kern.h>
     43 
     44 #include <dev/pci/pcivar.h>
     45 #include <dev/pci/pcireg.h>
     46 
     47 #include <machine/cpu.h>
     48 #include <machine/iomap.h>
     49 #include <machine/mfp.h>
     50 #include <machine/bus.h>
     51 
     52 #include <atari/atari/device.h>
     53 
     54 /*
     55  * I/O and memory we assume 'reserved' when an vga card is detected on
     56  * the PCI-bus.
     57  */
     58 #define MAX_VGA_MEM	0x1000000	/* 16 MB mem	*/
     59 #define MAX_VGA_IO	0x0010000	/* 64 KB io	*/
     60 
     61 int	pcibusprint __P((void *auxp, const char *));
     62 int	pcibusmatch __P((struct device *, struct cfdata *, void *));
     63 void	pcibusattach __P((struct device *, struct device *, void *));
     64 
     65 static int pci_config_offset __P((pcitag_t));
     66 
     67 struct cfattach pcibus_ca = {
     68 	sizeof(struct device), pcibusmatch, pcibusattach
     69 };
     70 
     71 int
     72 pcibusmatch(pdp, cfp, auxp)
     73 struct device	*pdp;
     74 struct cfdata	*cfp;
     75 void		*auxp;
     76 {
     77 	if(atari_realconfig == 0)
     78 		return (0);
     79 	if (strcmp((char *)auxp, "pcibus") || cfp->cf_unit != 0)
     80 		return(0);
     81 	return(machineid & ATARI_HADES ? 1 : 0);
     82 }
     83 
     84 void
     85 pcibusattach(pdp, dp, auxp)
     86 struct device	*pdp, *dp;
     87 void		*auxp;
     88 {
     89 	struct pcibus_attach_args	pba;
     90 	bus_space_tag_t			leb_alloc_bus_space_tag __P((void));
     91 
     92 
     93 	pba.pba_busname = "pci";
     94 	pba.pba_pc      = NULL;
     95 	pba.pba_bus     = 0;
     96 	pba.pba_flags	= PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
     97 	pba.pba_dmat	= BUS_PCI_DMA_TAG;
     98 	pba.pba_iot     = leb_alloc_bus_space_tag();
     99 	pba.pba_memt    = leb_alloc_bus_space_tag();
    100 	if ((pba.pba_iot == NULL) || (pba.pba_memt == NULL)) {
    101 		printf("leb_alloc_bus_space_tag failed!\n");
    102 		return;
    103 	}
    104 	pba.pba_iot->base  = PCI_IO_PHYS;
    105 	pba.pba_memt->base = PCI_MEM_PHYS;
    106 
    107 	MFP2->mf_aer &= ~(0x27); /* PCI interrupts: HIGH -> LOW */
    108 
    109 	printf("\n");
    110 
    111 	config_found(dp, &pba, pcibusprint);
    112 }
    113 
    114 int
    115 pcibusprint(auxp, name)
    116 void		*auxp;
    117 const char	*name;
    118 {
    119 	if(name == NULL)
    120 		return(UNCONF);
    121 	return(QUIET);
    122 }
    123 
    124 void
    125 pci_attach_hook(parent, self, pba)
    126 	struct device *parent, *self;
    127 	struct pcibus_attach_args *pba;
    128 {
    129 }
    130 
    131 /*
    132  * Initialize the PCI-bus. The Atari-BIOS does not do this, so....
    133  */
    134 void
    135 init_pci_bus()
    136 {
    137 	pci_chipset_tag_t	pc = NULL; /* XXX */
    138 	pcitag_t		tag;
    139 	pcireg_t		csr, address, mask;
    140 	int			device, id, class, maxndevs;
    141 	int			reg;
    142 	u_int32_t		membase, iobase;
    143 
    144 	tag        = 0;
    145 	id = class = 0;
    146 
    147 	membase = iobase = 0;
    148 
    149 	maxndevs = pci_bus_maxdevs(pc, 0);
    150 
    151 	/*
    152 	 * Scan the bus for prehistory (usually VGA) devices.
    153 	 */
    154 	for (device = 0; device < maxndevs; device++) {
    155 
    156 		tag = pci_make_tag(pc, 0, device, 0);
    157 		id  = pci_conf_read(pc, tag, PCI_ID_REG);
    158 		if (id == 0 || id == 0xffffffff)
    159 			continue;
    160 		class = pci_conf_read(pc, tag, PCI_CLASS_REG);
    161 		switch (PCI_CLASS(class)) {
    162 			case PCI_CLASS_PREHISTORIC:
    163 			case PCI_CLASS_DISPLAY:
    164 
    165 				membase = MAX_VGA_MEM;
    166 				iobase  = MAX_VGA_IO;
    167 		}
    168 	}
    169 
    170 	for (device = 0; device < maxndevs; device++) {
    171 
    172 		tag = pci_make_tag(pc, 0, device, 0);
    173 		id  = pci_conf_read(pc, tag, PCI_ID_REG);
    174 		if (id == 0 || id == 0xffffffff)
    175 			continue;
    176 
    177 		class = pci_conf_read(pc, tag, PCI_CLASS_REG);
    178 		switch (PCI_CLASS(class)) {
    179 			case PCI_CLASS_PREHISTORIC:
    180 			case PCI_CLASS_DISPLAY:
    181 				/*
    182 				 * XXX: We rely on the BIOS to do the
    183 				 * right thing here. Eventually, we should
    184 				 * take the initiative...
    185 				 */
    186 				continue;
    187 		}
    188 
    189 		csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
    190 		csr &= ~(PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_IO_ENABLE);
    191 		csr &= ~PCI_COMMAND_MASTER_ENABLE;
    192 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
    193 
    194 		for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) {
    195 		    int	size, type;
    196 
    197 		    address = pci_conf_read(pc, tag, reg);
    198 		    pci_conf_write(pc, tag, reg, 0xffffffff);
    199 		    mask    = pci_conf_read(pc, tag, reg);
    200 		    pci_conf_write(pc, tag, reg, address);
    201 		    if (mask == 0)
    202 			continue; /* Register unused */
    203 
    204 		    if (mask & PCI_MAPREG_TYPE_IO) {
    205 			csr |= PCI_COMMAND_IO_ENABLE;
    206 			address = PCI_MAPREG_IO_ADDR(mask);
    207 			mask    = (~address << 1) | 1;
    208 			size    = (mask & address) & 0xffffffff;
    209 			address = iobase | PCI_MAPREG_TYPE_IO;
    210 			iobase += roundup(size, 4096); /* XXX */
    211 		    }
    212 		    else {
    213 			type = PCI_MAPREG_MEM_TYPE(address);
    214 			switch (type) {
    215 			    case PCI_MAPREG_MEM_TYPE_32BIT:
    216 				break;
    217 			    case PCI_MAPREG_MEM_TYPE_64BIT:
    218 				reg++;
    219 			    case PCI_MAPREG_MEM_TYPE_32BIT_1M:
    220 				/*
    221 				 * XXX: We can do better here!
    222 				 */
    223 				if (membase >= 0x100000)
    224 					continue;
    225 			}
    226 			csr |= PCI_COMMAND_MEM_ENABLE;
    227 			size = PCI_MAPREG_MEM_SIZE(mask);
    228 			address = membase | PCI_MAPREG_TYPE_MEM;
    229 			membase += roundup(size, 4096); /* XXX */
    230 		    }
    231 		    pci_conf_write(pc, tag, reg, address);
    232 		}
    233 		csr |= PCI_COMMAND_MASTER_ENABLE;
    234 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
    235 
    236 		/*
    237 		 * Both interrupt pin & line are set to the device (== slot)
    238 		 * number. This makes sense on the atari because the
    239 		 * individual slots are hard-wired to a specific MFP-pin.
    240 		 */
    241 		csr  = (device << PCI_INTERRUPT_PIN_SHIFT);
    242 		csr |= (device << PCI_INTERRUPT_LINE_SHIFT);
    243 		pci_conf_write(pc, tag, PCI_INTERRUPT_REG, csr);
    244 	}
    245 }
    246 
    247 /*
    248  * Atari_init.c maps the config areas NBPG bytes apart....
    249  */
    250 static int pci_config_offset(tag)
    251 pcitag_t	tag;
    252 {
    253 	int	device;
    254 
    255 	device = (tag >> 11) & 0x1f;
    256 	return(device * NBPG);
    257 }
    258 
    259 int
    260 pci_bus_maxdevs(pc, busno)
    261 	pci_chipset_tag_t pc;
    262 	int busno;
    263 {
    264 	return (4);
    265 }
    266 
    267 pcitag_t
    268 pci_make_tag(pc, bus, device, function)
    269 	pci_chipset_tag_t pc;
    270 	int bus, device, function;
    271 {
    272 	return ((bus << 16) | (device << 11) | (function << 8));
    273 }
    274 
    275 pcireg_t
    276 pci_conf_read(pc, tag, reg)
    277 	pci_chipset_tag_t pc;
    278 	pcitag_t tag;
    279 	int reg;
    280 {
    281 	u_long	data;
    282 
    283 	data = *(u_long *)(pci_conf_addr + pci_config_offset(tag) + reg);
    284 	return (bswap32(data));
    285 }
    286 
    287 void
    288 pci_conf_write(pc, tag, reg, data)
    289 	pci_chipset_tag_t pc;
    290 	pcitag_t tag;
    291 	int reg;
    292 	pcireg_t data;
    293 {
    294 	*((u_long *)(pci_conf_addr + pci_config_offset(tag) + reg))
    295 		= bswap32(data);
    296 }
    297 
    298 int
    299 pci_intr_map(pc, intrtag, pin, line, ihp)
    300 	pci_chipset_tag_t pc;
    301 	pcitag_t intrtag;
    302 	int pin, line;
    303 	pci_intr_handle_t *ihp;
    304 {
    305 	/*
    306 	 * According to the PCI-spec, 255 means `unknown' or `no connection'.
    307 	 * Interpret this as 'no interrupt assigned'.
    308 	 */
    309 	if (line == 255) {
    310 		*ihp = -1;
    311 		return 1;
    312 	}
    313 
    314 	/*
    315 	 * Values are pretty useless because the on the Hades all interrupt
    316 	 * lines for a card are tied together and hardwired to the TT-MFP
    317 	 * I/O port.
    318 	 */
    319 	*ihp = line;
    320 	return 0;
    321 }
    322 
    323 const char *
    324 pci_intr_string(pc, ih)
    325 	pci_chipset_tag_t pc;
    326 	pci_intr_handle_t ih;
    327 {
    328 	static char irqstr[8];		/* 4 + 2 + NULL + sanity */
    329 
    330 	if (ih == -1)
    331 		panic("pci_intr_string: bogus handle 0x%x\n", ih);
    332 
    333 	sprintf(irqstr, "irq %d", ih);
    334 	return (irqstr);
    335 
    336 }
    337 
    338 /*
    339  * The interrupt stuff is rather ugly. On the Hades, all interrupt lines
    340  * for a slot are wired together and connected to IO 0,1,2 or 5 (slots:
    341  * (0-3) on the TT-MFP. The Pci-config code initializes the irq. number
    342  * to the slot position.
    343  */
    344 static pci_intr_info_t iinfo[4] = { { -1 }, { -1 }, { -1 }, { -1 } };
    345 
    346 static int	iifun __P((int, int));
    347 
    348 static int
    349 iifun(slot, sr)
    350 int	slot;
    351 int	sr;
    352 {
    353 	pci_intr_info_t *iinfo_p;
    354 	int		s;
    355 
    356 	iinfo_p = &iinfo[slot];
    357 
    358 	/*
    359 	 * Disable the interrupts
    360 	 */
    361 	MFP2->mf_imrb  &= ~iinfo_p->imask;
    362 
    363 	if ((sr & PSL_IPL) >= (iinfo_p->ipl & PSL_IPL)) {
    364 		/*
    365 		 * We're running at a too high priority now.
    366 		 */
    367 		add_sicallback((si_farg)iifun, (void*)slot, 0);
    368 	}
    369 	else {
    370 		s = splx(iinfo_p->ipl);
    371 		(void) (iinfo_p->ifunc)(iinfo_p->iarg);
    372 		splx(s);
    373 
    374 		/*
    375 		 * Re-enable interrupts after handling
    376 		 */
    377 		MFP2->mf_imrb |= iinfo_p->imask;
    378 	}
    379 	return 1;
    380 }
    381 
    382 void *
    383 pci_intr_establish(pc, ih, level, ih_fun, ih_arg)
    384 	pci_chipset_tag_t	pc;
    385 	pci_intr_handle_t	ih;
    386 	int			level;
    387 	int			(*ih_fun) __P((void *));
    388 	void			*ih_arg;
    389 {
    390 	pci_intr_info_t *iinfo_p;
    391 	struct intrhand	*ihand;
    392 	int		slot;
    393 
    394 	slot    = ih;
    395 	iinfo_p = &iinfo[slot];
    396 
    397 	if (iinfo_p->ipl > 0)
    398 	    panic("pci_intr_establish: interrupt was already established\n");
    399 
    400 	ihand = intr_establish((slot == 3) ? 23 : 16 + slot, USER_VEC, 0,
    401 				(hw_ifun_t)iifun, (void *)slot);
    402 	if (ihand != NULL) {
    403 		iinfo_p->ipl   = level;
    404 		iinfo_p->imask = (slot == 3) ? 0x80 : (0x01 << slot);
    405 		iinfo_p->ifunc = ih_fun;
    406 		iinfo_p->iarg  = ih_arg;
    407 		iinfo_p->ihand = ihand;
    408 
    409 		/*
    410 		 * Enable (unmask) the interrupt
    411 		 */
    412 		MFP2->mf_imrb |= iinfo_p->imask;
    413 		MFP2->mf_ierb |= iinfo_p->imask;
    414 		return(iinfo_p);
    415 	}
    416 	return NULL;
    417 }
    418 
    419 void
    420 pci_intr_disestablish(pc, cookie)
    421 	pci_chipset_tag_t pc;
    422 	void *cookie;
    423 {
    424 	pci_intr_info_t *iinfo_p = (pci_intr_info_t *)cookie;
    425 
    426 	if (iinfo->ipl < 0)
    427 	    panic("pci_intr_disestablish: interrupt was not established\n");
    428 
    429 	MFP2->mf_imrb &= ~iinfo->imask;
    430 	MFP2->mf_ierb &= ~iinfo->imask;
    431 	(void) intr_disestablish(iinfo_p->ihand);
    432 	iinfo_p->ipl = -1;
    433 }
    434