Home | History | Annotate | Line # | Download | only in pci
pci_machdep.c revision 1.10
      1 /*	$NetBSD: pci_machdep.c,v 1.10 1998/03/10 11:43:11 leo 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 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 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 
     91 	pba.pba_busname = "pci";
     92 	pba.pba_pc      = NULL;
     93 	pba.pba_bus     = 0;
     94 	pba.pba_iot     = PCI_IO_PHYS;
     95 	pba.pba_memt    = PCI_MEM_PHYS;
     96 	pba.pba_flags	= PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
     97 	pba.pba_dmat	= BUS_PCI_DMA_TAG;
     98 
     99 	MFP2->mf_aer &= ~(0x27); /* PCI interrupts: HIGH -> LOW */
    100 
    101 	printf("\n");
    102 
    103 	config_found(dp, &pba, pcibusprint);
    104 }
    105 
    106 int
    107 pcibusprint(auxp, name)
    108 void		*auxp;
    109 const char	*name;
    110 {
    111 	if(name == NULL)
    112 		return(UNCONF);
    113 	return(QUIET);
    114 }
    115 
    116 void
    117 pci_attach_hook(parent, self, pba)
    118 	struct device *parent, *self;
    119 	struct pcibus_attach_args *pba;
    120 {
    121 }
    122 
    123 /*
    124  * Initialize the PCI-bus. The Atari-BIOS does not do this, so....
    125  */
    126 void
    127 init_pci_bus()
    128 {
    129 	pci_chipset_tag_t	pc = NULL; /* XXX */
    130 	pcitag_t		tag;
    131 	pcireg_t		csr, address, mask;
    132 	int			device, id, class, maxndevs;
    133 	int			reg;
    134 	u_int32_t		membase, iobase;
    135 
    136 	tag        = 0;
    137 	id = class = 0;
    138 
    139 	membase = iobase = 0;
    140 
    141 	maxndevs = pci_bus_maxdevs(pc, 0);
    142 
    143 	/*
    144 	 * Scan the bus for prehistory (usually VGA) devices.
    145 	 */
    146 	for (device = 0; device < maxndevs; device++) {
    147 
    148 		tag = pci_make_tag(pc, 0, device, 0);
    149 		id  = pci_conf_read(pc, tag, PCI_ID_REG);
    150 		if (id == 0 || id == 0xffffffff)
    151 			continue;
    152 		class = pci_conf_read(pc, tag, PCI_CLASS_REG);
    153 		switch (PCI_CLASS(class)) {
    154 			case PCI_CLASS_PREHISTORIC:
    155 			case PCI_CLASS_DISPLAY:
    156 
    157 				membase = MAX_VGA_MEM;
    158 				iobase  = MAX_VGA_IO;
    159 		}
    160 	}
    161 
    162 	for (device = 0; device < maxndevs; device++) {
    163 
    164 		tag = pci_make_tag(pc, 0, device, 0);
    165 		id  = pci_conf_read(pc, tag, PCI_ID_REG);
    166 		if (id == 0 || id == 0xffffffff)
    167 			continue;
    168 
    169 		class = pci_conf_read(pc, tag, PCI_CLASS_REG);
    170 		switch (PCI_CLASS(class)) {
    171 			case PCI_CLASS_PREHISTORIC:
    172 			case PCI_CLASS_DISPLAY:
    173 				/*
    174 				 * XXX: We rely on the BIOS to do the
    175 				 * right thing here. Eventually, we should
    176 				 * take the initiative...
    177 				 */
    178 				continue;
    179 		}
    180 
    181 		csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
    182 		csr &= ~(PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_IO_ENABLE);
    183 		csr &= ~PCI_COMMAND_MASTER_ENABLE;
    184 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
    185 
    186 		for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) {
    187 		    int	size, type;
    188 
    189 		    address = pci_conf_read(pc, tag, reg);
    190 		    pci_conf_write(pc, tag, reg, 0xffffffff);
    191 		    mask    = pci_conf_read(pc, tag, reg);
    192 		    pci_conf_write(pc, tag, reg, address);
    193 		    if (mask == 0)
    194 			continue; /* Register unused */
    195 
    196 		    if (mask & PCI_MAPREG_TYPE_IO) {
    197 			csr |= PCI_COMMAND_IO_ENABLE;
    198 			address = PCI_MAPREG_IO_ADDR(mask);
    199 			mask    = (~address << 1) | 1;
    200 			size    = (mask & address) & 0xffffffff;
    201 			address = iobase | PCI_MAPREG_TYPE_IO;
    202 			iobase += roundup(size, 4096); /* XXX */
    203 		    }
    204 		    else {
    205 			type = PCI_MAPREG_MEM_TYPE(address);
    206 			switch (type) {
    207 			    case PCI_MAPREG_MEM_TYPE_32BIT:
    208 				break;
    209 			    case PCI_MAPREG_MEM_TYPE_64BIT:
    210 				reg++;
    211 			    case PCI_MAPREG_MEM_TYPE_32BIT_1M:
    212 				/*
    213 				 * XXX: We can do better here!
    214 				 */
    215 				if (membase >= 0x100000)
    216 					continue;
    217 			}
    218 			csr |= PCI_COMMAND_MEM_ENABLE;
    219 			size = PCI_MAPREG_MEM_SIZE(mask);
    220 			address = membase | PCI_MAPREG_TYPE_MEM;
    221 			membase += roundup(size, 4096); /* XXX */
    222 		    }
    223 		    pci_conf_write(pc, tag, reg, address);
    224 		}
    225 		csr |= PCI_COMMAND_MASTER_ENABLE;
    226 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
    227 
    228 		/*
    229 		 * Both interrupt pin & line are set to the device (== slot)
    230 		 * number. This makes sense on the atari because the
    231 		 * individual slots are hard-wired to a specific MFP-pin.
    232 		 */
    233 		csr  = (device << PCI_INTERRUPT_PIN_SHIFT);
    234 		csr |= (device << PCI_INTERRUPT_LINE_SHIFT);
    235 		pci_conf_write(pc, tag, PCI_INTERRUPT_REG, csr);
    236 	}
    237 }
    238 
    239 /*
    240  * Atari_init.c maps the config areas NBPG bytes apart....
    241  */
    242 static int pci_config_offset(tag)
    243 pcitag_t	tag;
    244 {
    245 	int	device;
    246 
    247 	device = (tag >> 11) & 0x1f;
    248 	return(device * NBPG);
    249 }
    250 
    251 int
    252 pci_bus_maxdevs(pc, busno)
    253 	pci_chipset_tag_t pc;
    254 	int busno;
    255 {
    256 	return (4);
    257 }
    258 
    259 pcitag_t
    260 pci_make_tag(pc, bus, device, function)
    261 	pci_chipset_tag_t pc;
    262 	int bus, device, function;
    263 {
    264 	return ((bus << 16) | (device << 11) | (function << 8));
    265 }
    266 
    267 pcireg_t
    268 pci_conf_read(pc, tag, reg)
    269 	pci_chipset_tag_t pc;
    270 	pcitag_t tag;
    271 	int reg;
    272 {
    273 	u_long	data;
    274 
    275 	data = *(u_long *)(pci_conf_addr + pci_config_offset(tag) + reg);
    276 	return (bswap32(data));
    277 }
    278 
    279 void
    280 pci_conf_write(pc, tag, reg, data)
    281 	pci_chipset_tag_t pc;
    282 	pcitag_t tag;
    283 	int reg;
    284 	pcireg_t data;
    285 {
    286 	*((u_long *)(pci_conf_addr + pci_config_offset(tag) + reg))
    287 		= bswap32(data);
    288 }
    289 
    290 int
    291 pci_intr_map(pc, intrtag, pin, line, ihp)
    292 	pci_chipset_tag_t pc;
    293 	pcitag_t intrtag;
    294 	int pin, line;
    295 	pci_intr_handle_t *ihp;
    296 {
    297 	/*
    298 	 * According to the PCI-spec, 255 means `unknown' or `no connection'.
    299 	 * Interpret this as 'no interrupt assigned'.
    300 	 */
    301 	if (line == 255) {
    302 		*ihp = -1;
    303 		return 1;
    304 	}
    305 
    306 	/*
    307 	 * Values are pretty useless because the on the Hades all interrupt
    308 	 * lines for a card are tied together and hardwired to the TT-MFP
    309 	 * I/O port.
    310 	 */
    311 	*ihp = line;
    312 	return 0;
    313 }
    314 
    315 const char *
    316 pci_intr_string(pc, ih)
    317 	pci_chipset_tag_t pc;
    318 	pci_intr_handle_t ih;
    319 {
    320 	static char irqstr[8];		/* 4 + 2 + NULL + sanity */
    321 
    322 	if (ih == -1)
    323 		panic("pci_intr_string: bogus handle 0x%x\n", ih);
    324 
    325 	sprintf(irqstr, "irq %d", ih);
    326 	return (irqstr);
    327 
    328 }
    329 
    330 /*
    331  * The interrupt stuff is rather ugly. On the Hades, all interrupt lines
    332  * for a slot are wired together and connected to IO 0,1,2 or 5 (slots:
    333  * (0-3) on the TT-MFP. The Pci-config code initializes the irq. number
    334  * to the slot position.
    335  */
    336 static pci_intr_info_t iinfo[4] = { { -1 }, { -1 }, { -1 }, { -1 } };
    337 
    338 static int	iifun __P((int, int));
    339 
    340 static int
    341 iifun(slot, sr)
    342 int	slot;
    343 int	sr;
    344 {
    345 	pci_intr_info_t *iinfo_p;
    346 	int		s;
    347 
    348 	iinfo_p = &iinfo[slot];
    349 
    350 	/*
    351 	 * Disable the interrupts
    352 	 */
    353 	MFP2->mf_imrb  &= ~iinfo_p->imask;
    354 
    355 	if ((sr & PSL_IPL) >= iinfo_p->ipl) {
    356 		/*
    357 		 * We're running at a too high priority now.
    358 		 */
    359 		add_sicallback((si_farg)iifun, (void*)slot, 0);
    360 	}
    361 	else {
    362 		s = splx(iinfo_p->ipl);
    363 		(void) (iinfo_p->ifunc)(iinfo_p->iarg);
    364 		splx(s);
    365 
    366 		/*
    367 		 * Re-enable interrupts after handling
    368 		 */
    369 		MFP2->mf_imrb |= iinfo_p->imask;
    370 	}
    371 	return 1;
    372 }
    373 
    374 void *
    375 pci_intr_establish(pc, ih, level, ih_fun, ih_arg)
    376 	pci_chipset_tag_t	pc;
    377 	pci_intr_handle_t	ih;
    378 	int			level;
    379 	int			(*ih_fun) __P((void *));
    380 	void			*ih_arg;
    381 {
    382 	pci_intr_info_t *iinfo_p;
    383 	struct intrhand	*ihand;
    384 	int		slot;
    385 
    386 	slot    = ih;
    387 	iinfo_p = &iinfo[slot];
    388 
    389 	if (iinfo_p->ipl > 0)
    390 	    panic("pci_intr_establish: interrupt was already established\n");
    391 
    392 	ihand = intr_establish((slot == 3) ? 23 : 16 + slot, USER_VEC, 0,
    393 				(hw_ifun_t)iifun, (void *)slot);
    394 	if (ihand != NULL) {
    395 		iinfo_p->ipl   = level;
    396 		iinfo_p->imask = (slot == 3) ? 0x80 : (0x01 << slot);
    397 		iinfo_p->ifunc = ih_fun;
    398 		iinfo_p->iarg  = ih_arg;
    399 		iinfo_p->ihand = ihand;
    400 
    401 		/*
    402 		 * Enable (unmask) the interrupt
    403 		 */
    404 		MFP2->mf_imrb |= iinfo_p->imask;
    405 		MFP2->mf_ierb |= iinfo_p->imask;
    406 		return(iinfo_p);
    407 	}
    408 	return NULL;
    409 }
    410 
    411 void
    412 pci_intr_disestablish(pc, cookie)
    413 	pci_chipset_tag_t pc;
    414 	void *cookie;
    415 {
    416 	pci_intr_info_t *iinfo_p = (pci_intr_info_t *)cookie;
    417 
    418 	if (iinfo->ipl < 0)
    419 	    panic("pci_intr_disestablish: interrupt was not established\n");
    420 
    421 	MFP2->mf_imrb &= ~iinfo->imask;
    422 	MFP2->mf_ierb &= ~iinfo->imask;
    423 	(void) intr_disestablish(iinfo_p->ihand);
    424 	iinfo_p->ipl = -1;
    425 }
    426