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