pci_machdep.c revision 1.25
11.25Stsutsui/*	$NetBSD: pci_machdep.c,v 1.25 2007/02/18 12:22:16 tsutsui Exp $	*/
21.1Ssoren
31.1Ssoren/*
41.1Ssoren * Copyright (c) 2000 Soren S. Jorvang.  All rights reserved.
51.1Ssoren *
61.1Ssoren * Redistribution and use in source and binary forms, with or without
71.1Ssoren * modification, are permitted provided that the following conditions
81.1Ssoren * are met:
91.1Ssoren * 1. Redistributions of source code must retain the above copyright
101.1Ssoren *    notice, this list of conditions, and the following disclaimer.
111.1Ssoren * 2. Redistributions in binary form must reproduce the above copyright
121.1Ssoren *    notice, this list of conditions and the following disclaimer in the
131.1Ssoren *    documentation and/or other materials provided with the distribution.
141.1Ssoren *
151.1Ssoren * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161.1Ssoren * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171.1Ssoren * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181.1Ssoren * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191.1Ssoren * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201.1Ssoren * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211.1Ssoren * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221.1Ssoren * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231.1Ssoren * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241.1Ssoren * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251.1Ssoren * SUCH DAMAGE.
261.1Ssoren */
271.13Slukem
281.13Slukem#include <sys/cdefs.h>
291.25Stsutsui__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.25 2007/02/18 12:22:16 tsutsui Exp $");
301.1Ssoren
311.1Ssoren#include <sys/types.h>
321.1Ssoren#include <sys/param.h>
331.1Ssoren#include <sys/time.h>
341.1Ssoren#include <sys/systm.h>
351.1Ssoren#include <sys/errno.h>
361.1Ssoren#include <sys/device.h>
371.17Stsutsui#include <sys/extent.h>
381.1Ssoren
391.1Ssoren#define _COBALT_BUS_DMA_PRIVATE
401.1Ssoren#include <machine/bus.h>
411.4Ssoren#include <machine/intr.h>
421.1Ssoren
431.1Ssoren#include <dev/pci/pcivar.h>
441.1Ssoren#include <dev/pci/pcireg.h>
451.1Ssoren#include <dev/pci/pcidevs.h>
461.17Stsutsui#include <dev/pci/pciconf.h>
471.23Stsutsui#include <dev/pci/pciide_apollo_reg.h>
481.1Ssoren
491.16Stsutsui#include <cobalt/dev/gtreg.h>
501.16Stsutsui
511.1Ssoren/*
521.1Ssoren * PCI doesn't have any special needs; just use
531.1Ssoren * the generic versions of these functions.
541.1Ssoren */
551.1Ssorenstruct cobalt_bus_dma_tag pci_bus_dma_tag = {
561.14Stsutsui	_bus_dmamap_create,
571.1Ssoren	_bus_dmamap_destroy,
581.1Ssoren	_bus_dmamap_load,
591.1Ssoren	_bus_dmamap_load_mbuf,
601.1Ssoren	_bus_dmamap_load_uio,
611.1Ssoren	_bus_dmamap_load_raw,
621.1Ssoren	_bus_dmamap_unload,
631.1Ssoren	_bus_dmamap_sync,
641.1Ssoren	_bus_dmamem_alloc,
651.1Ssoren	_bus_dmamem_free,
661.1Ssoren	_bus_dmamem_map,
671.1Ssoren	_bus_dmamem_unmap,
681.1Ssoren	_bus_dmamem_mmap,
691.1Ssoren};
701.1Ssoren
711.1Ssorenvoid
721.20Stsutsuipci_attach_hook(struct device *parent, struct device *self,
731.20Stsutsui    struct pcibus_attach_args *pba)
741.1Ssoren{
751.1Ssoren	/* XXX */
761.1Ssoren
771.1Ssoren	return;
781.1Ssoren}
791.1Ssoren
801.1Ssorenint
811.20Stsutsuipci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
821.1Ssoren{
831.20Stsutsui
841.6Ssoren	return 32;
851.1Ssoren}
861.1Ssoren
871.1Ssorenpcitag_t
881.20Stsutsuipci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
891.1Ssoren{
901.20Stsutsui
911.1Ssoren	return (bus << 16) | (device << 11) | (function << 8);
921.1Ssoren}
931.1Ssoren
941.1Ssorenvoid
951.20Stsutsuipci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
961.1Ssoren{
971.20Stsutsui
981.1Ssoren	if (bp != NULL)
991.1Ssoren		*bp = (tag >> 16) & 0xff;
1001.1Ssoren	if (dp != NULL)
1011.1Ssoren		*dp = (tag >> 11) & 0x1f;
1021.1Ssoren	if (fp != NULL)
1031.1Ssoren		*fp = (tag >> 8) & 0x07;
1041.1Ssoren}
1051.1Ssoren
1061.1Ssorenpcireg_t
1071.20Stsutsuipci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
1081.1Ssoren{
1091.1Ssoren	pcireg_t data;
1101.6Ssoren	int bus, dev, func;
1111.14Stsutsui
1121.6Ssoren	pci_decompose_tag(pc, tag, &bus, &dev, &func);
1131.6Ssoren
1141.6Ssoren	/*
1151.6Ssoren	 * 2700 hardware wedges on accesses to device 6.
1161.6Ssoren	 */
1171.6Ssoren	if (bus == 0 && dev == 6)
1181.6Ssoren		return 0;
1191.6Ssoren	/*
1201.6Ssoren	 * 2800 hardware wedges on accesses to device 31.
1211.6Ssoren	 */
1221.6Ssoren	if (bus == 0 && dev == 31)
1231.6Ssoren		return 0;
1241.1Ssoren
1251.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR,
1261.21Stsutsui	    PCICFG_ENABLE | tag | reg);
1271.16Stsutsui	data = bus_space_read_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_DATA);
1281.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR, 0);
1291.1Ssoren
1301.1Ssoren	return data;
1311.1Ssoren}
1321.1Ssoren
1331.1Ssorenvoid
1341.20Stsutsuipci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
1351.1Ssoren{
1361.1Ssoren
1371.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR,
1381.21Stsutsui	    PCICFG_ENABLE | tag | reg);
1391.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_DATA, data);
1401.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR, 0);
1411.1Ssoren}
1421.1Ssoren
1431.1Ssorenint
1441.20Stsutsuipci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
1451.1Ssoren{
1461.10Ssommerfe	pci_chipset_tag_t pc = pa->pa_pc;
1471.11Stsutsui	pcitag_t intrtag = pa->pa_intrtag;
1481.10Ssommerfe	int pin = pa->pa_intrpin;
1491.10Ssommerfe	int line = pa->pa_intrline;
1501.5Ssoren	int bus, dev, func;
1511.1Ssoren
1521.5Ssoren	pci_decompose_tag(pc, intrtag, &bus, &dev, &func);
1531.5Ssoren
1541.5Ssoren	/*
1551.5Ssoren	 * The interrupt lines of the two Tulips are connected
1561.5Ssoren	 * directly to the CPU.
1571.5Ssoren	 */
1581.5Ssoren
1591.25Stsutsui	if (cobalt_id == COBALT_ID_QUBE2700) {
1601.25Stsutsui		if (bus == 0 && dev == 7 && pin == PCI_INTERRUPT_PIN_A)
1611.25Stsutsui			*ihp = 16 + 2;
1621.25Stsutsui		else
1631.25Stsutsui			*ihp = line;
1641.25Stsutsui	} else {
1651.25Stsutsui		if (bus == 0 && dev == 7 && pin == PCI_INTERRUPT_PIN_A)
1661.25Stsutsui			*ihp = 16 + 1;
1671.25Stsutsui		else if (bus == 0 && dev == 12 && pin == PCI_INTERRUPT_PIN_A)
1681.25Stsutsui			*ihp = 16 + 2;
1691.25Stsutsui		else
1701.25Stsutsui			*ihp = line;
1711.25Stsutsui	}
1721.1Ssoren
1731.1Ssoren	return 0;
1741.1Ssoren}
1751.1Ssoren
1761.1Ssorenconst char *
1771.20Stsutsuipci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
1781.1Ssoren{
1791.4Ssoren	static char irqstr[8];
1801.4Ssoren
1811.5Ssoren	if (ih >= 16)
1821.5Ssoren		sprintf(irqstr, "level %d", ih - 16);
1831.4Ssoren	else
1841.4Ssoren		sprintf(irqstr, "irq %d", ih);
1851.1Ssoren
1861.1Ssoren	return irqstr;
1871.7Scgd}
1881.7Scgd
1891.7Scgdconst struct evcnt *
1901.20Stsutsuipci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih)
1911.7Scgd{
1921.7Scgd
1931.7Scgd	/* XXX for now, no evcnt parent reported */
1941.7Scgd	return NULL;
1951.1Ssoren}
1961.1Ssoren
1971.1Ssorenvoid *
1981.20Stsutsuipci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
1991.20Stsutsui    int (*func)(void *), void *arg)
2001.1Ssoren{
2011.20Stsutsui
2021.5Ssoren	if (ih >= 16)
2031.5Ssoren		return cpu_intr_establish(ih - 16, level, func, arg);
2041.4Ssoren	else
2051.4Ssoren		return icu_intr_establish(ih, IST_LEVEL, level, func, arg);
2061.1Ssoren}
2071.1Ssoren
2081.1Ssorenvoid
2091.20Stsutsuipci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
2101.1Ssoren{
2111.20Stsutsui
2121.12Saugustss	/* Try both, only the valid one will disestablish. */
2131.12Saugustss	cpu_intr_disestablish(cookie);
2141.12Saugustss	icu_intr_disestablish(cookie);
2151.1Ssoren}
2161.17Stsutsui
2171.17Stsutsuivoid
2181.17Stsutsuipci_conf_interrupt(pci_chipset_tag_t pc, int bus, int dev, int pin, int swiz,
2191.17Stsutsui    int *iline)
2201.17Stsutsui{
2211.17Stsutsui
2221.17Stsutsui	/* not yet... */
2231.17Stsutsui}
2241.17Stsutsui
2251.17Stsutsuiint
2261.17Stsutsuipci_conf_hook(pci_chipset_tag_t pc, int bus, int dev, int func, pcireg_t id)
2271.17Stsutsui{
2281.17Stsutsui
2291.22Stsutsui	/* ignore bogus IDs */
2301.22Stsutsui	if (PCI_VENDOR(id) == 0)
2311.22Stsutsui		return 0;
2321.22Stsutsui
2331.22Stsutsui	/* 2700 hardware wedges on accesses to device 6. */
2341.22Stsutsui	if (bus == 0 && dev == 6)
2351.22Stsutsui		return 0;
2361.22Stsutsui
2371.22Stsutsui	/* 2800 hardware wedges on accesses to device 31. */
2381.22Stsutsui	if (bus == 0 && dev == 31)
2391.22Stsutsui		return 0;
2401.22Stsutsui
2411.17Stsutsui	/* Don't configure the bridge and PCI probe. */
2421.24Sriz	if (PCI_VENDOR(id) == PCI_VENDOR_MARVELL &&
2431.24Sriz	    PCI_PRODUCT(id) == PCI_PRODUCT_MARVELL_GT64011)
2441.17Stsutsui	        return 0;
2451.17Stsutsui
2461.23Stsutsui	/* Don't configure on-board VIA VT82C586 (pcib, uhci) */
2471.23Stsutsui	if (bus == 0 && dev == 9 && (func == 0 || func == 2))
2481.17Stsutsui		return 0;
2491.17Stsutsui
2501.23Stsutsui	/* Enable viaide secondary port. Some firmware doesn't enable it. */
2511.23Stsutsui	if (bus == 0 && dev == 9 && func == 1) {
2521.23Stsutsui		pcitag_t tag;
2531.23Stsutsui		pcireg_t csr;
2541.23Stsutsui
2551.23Stsutsui#define	APO_VIAIDECONF	(APO_VIA_REGBASE + 0x00)
2561.23Stsutsui
2571.23Stsutsui		tag = pci_make_tag(pc, bus, dev, func);
2581.23Stsutsui		csr = pci_conf_read(pc, tag, APO_VIAIDECONF);
2591.23Stsutsui		pci_conf_write(pc, tag, APO_VIAIDECONF,
2601.23Stsutsui		    csr | APO_IDECONF_EN(1));
2611.23Stsutsui	}
2621.19Sgdamore	return PCI_CONF_DEFAULT & ~(PCI_COMMAND_SERR_ENABLE |
2631.19Sgdamore	    PCI_COMMAND_PARITY_ENABLE);
2641.17Stsutsui}
265