11.38Smsaitoh/*	$NetBSD: pci_machdep.c,v 1.38 2015/10/02 05:22:50 msaitoh 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.38Smsaitoh__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.38 2015/10/02 05:22:50 msaitoh Exp $");
301.32Smatt
311.36Sskrll#define _MIPS_BUS_DMA_PRIVATE
321.1Ssoren
331.1Ssoren#include <sys/param.h>
341.32Smatt#include <sys/bus.h>
351.37Smatt#include <sys/cpu.h>
361.37Smatt#include <sys/device.h>
371.1Ssoren#include <sys/errno.h>
381.17Stsutsui#include <sys/extent.h>
391.32Smatt#include <sys/intr.h>
401.32Smatt#include <sys/systm.h>
411.32Smatt#include <sys/time.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.36Sskrllstruct mips_bus_dma_tag pci_bus_dma_tag = {
561.36Sskrll	._dmamap_ops = _BUS_DMAMAP_OPS_INITIALIZER,
571.36Sskrll	._dmamem_ops = _BUS_DMAMEM_OPS_INITIALIZER,
581.36Sskrll	._dmatag_ops = _BUS_DMATAG_OPS_INITIALIZER,
591.1Ssoren};
601.1Ssoren
611.1Ssorenvoid
621.33Schspci_attach_hook(device_t parent, device_t self, struct pcibus_attach_args *pba)
631.1Ssoren{
641.1Ssoren	/* XXX */
651.1Ssoren
661.1Ssoren	return;
671.1Ssoren}
681.1Ssoren
691.1Ssorenint
701.20Stsutsuipci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
711.1Ssoren{
721.20Stsutsui
731.6Ssoren	return 32;
741.1Ssoren}
751.1Ssoren
761.1Ssorenpcitag_t
771.20Stsutsuipci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
781.1Ssoren{
791.20Stsutsui
801.1Ssoren	return (bus << 16) | (device << 11) | (function << 8);
811.1Ssoren}
821.1Ssoren
831.1Ssorenvoid
841.20Stsutsuipci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
851.1Ssoren{
861.20Stsutsui
871.1Ssoren	if (bp != NULL)
881.1Ssoren		*bp = (tag >> 16) & 0xff;
891.1Ssoren	if (dp != NULL)
901.1Ssoren		*dp = (tag >> 11) & 0x1f;
911.1Ssoren	if (fp != NULL)
921.1Ssoren		*fp = (tag >> 8) & 0x07;
931.1Ssoren}
941.1Ssoren
951.1Ssorenpcireg_t
961.20Stsutsuipci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
971.1Ssoren{
981.1Ssoren	pcireg_t data;
991.6Ssoren	int bus, dev, func;
1001.14Stsutsui
1011.28Smatt	KASSERT(pc != NULL);
1021.28Smatt
1031.38Smsaitoh	if ((unsigned int)reg >= PCI_CONF_SIZE)
1041.38Smsaitoh		return (pcireg_t) -1;
1051.38Smsaitoh
1061.6Ssoren	pci_decompose_tag(pc, tag, &bus, &dev, &func);
1071.6Ssoren
1081.6Ssoren	/*
1091.6Ssoren	 * 2700 hardware wedges on accesses to device 6.
1101.6Ssoren	 */
1111.6Ssoren	if (bus == 0 && dev == 6)
1121.6Ssoren		return 0;
1131.6Ssoren	/*
1141.6Ssoren	 * 2800 hardware wedges on accesses to device 31.
1151.6Ssoren	 */
1161.6Ssoren	if (bus == 0 && dev == 31)
1171.6Ssoren		return 0;
1181.1Ssoren
1191.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR,
1201.21Stsutsui	    PCICFG_ENABLE | tag | reg);
1211.16Stsutsui	data = bus_space_read_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_DATA);
1221.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR, 0);
1231.1Ssoren
1241.1Ssoren	return data;
1251.1Ssoren}
1261.1Ssoren
1271.1Ssorenvoid
1281.20Stsutsuipci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
1291.1Ssoren{
1301.1Ssoren
1311.38Smsaitoh	if ((unsigned int)reg >= PCI_CONF_SIZE)
1321.38Smsaitoh		return;
1331.38Smsaitoh
1341.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR,
1351.21Stsutsui	    PCICFG_ENABLE | tag | reg);
1361.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_DATA, data);
1371.16Stsutsui	bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR, 0);
1381.1Ssoren}
1391.1Ssoren
1401.1Ssorenint
1411.29Sdyoungpci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
1421.1Ssoren{
1431.10Ssommerfe	pci_chipset_tag_t pc = pa->pa_pc;
1441.11Stsutsui	pcitag_t intrtag = pa->pa_intrtag;
1451.10Ssommerfe	int pin = pa->pa_intrpin;
1461.10Ssommerfe	int line = pa->pa_intrline;
1471.5Ssoren	int bus, dev, func;
1481.1Ssoren
1491.5Ssoren	pci_decompose_tag(pc, intrtag, &bus, &dev, &func);
1501.5Ssoren
1511.5Ssoren	/*
1521.26Stsutsui	 * The interrupt lines of the internal Tulips are connected
1531.5Ssoren	 * directly to the CPU.
1541.5Ssoren	 */
1551.25Stsutsui	if (cobalt_id == COBALT_ID_QUBE2700) {
1561.26Stsutsui		if (bus == 0 && dev == 7 && pin == PCI_INTERRUPT_PIN_A) {
1571.26Stsutsui			/* tulip is connected to CPU INT2 on Qube2700 */
1581.26Stsutsui			*ihp = NICU_INT + 2;
1591.26Stsutsui			return 0;
1601.26Stsutsui		}
1611.25Stsutsui	} else {
1621.26Stsutsui		if (bus == 0 && dev == 7 && pin == PCI_INTERRUPT_PIN_A) {
1631.26Stsutsui			/* the primary tulip is connected to CPU INT1 */
1641.26Stsutsui			*ihp = NICU_INT + 1;
1651.26Stsutsui			return 0;
1661.26Stsutsui		}
1671.26Stsutsui		if (bus == 0 && dev == 12 && pin == PCI_INTERRUPT_PIN_A) {
1681.26Stsutsui			/* the secondary tulip is connected to CPU INT2 */
1691.26Stsutsui			*ihp = NICU_INT + 2;
1701.26Stsutsui			return 0;
1711.26Stsutsui		}
1721.25Stsutsui	}
1731.1Ssoren
1741.26Stsutsui	/* sanity check */
1751.26Stsutsui	if (line == 0 || line >= NICU_INT)
1761.26Stsutsui		return -1;
1771.26Stsutsui
1781.26Stsutsui	*ihp = line;
1791.1Ssoren	return 0;
1801.1Ssoren}
1811.1Ssoren
1821.1Ssorenconst char *
1831.35Schristospci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih, char *buf, size_t len)
1841.1Ssoren{
1851.26Stsutsui	if (ih >= NICU_INT)
1861.35Schristos		snprintf(buf, len, "level %d", ih - NICU_INT);
1871.4Ssoren	else
1881.35Schristos		snprintf(buf, len, "irq %d", ih);
1891.1Ssoren
1901.35Schristos	return buf;
1911.7Scgd}
1921.7Scgd
1931.7Scgdconst struct evcnt *
1941.20Stsutsuipci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih)
1951.7Scgd{
1961.7Scgd
1971.7Scgd	/* XXX for now, no evcnt parent reported */
1981.7Scgd	return NULL;
1991.1Ssoren}
2001.1Ssoren
2011.27Sadint
2021.27Sadpci_intr_setattr(pci_chipset_tag_t pc, pci_intr_handle_t *ih,
2031.27Sad		 int attr, uint64_t data)
2041.27Sad{
2051.27Sad
2061.27Sad	switch (attr) {
2071.27Sad	case PCI_INTR_MPSAFE:
2081.27Sad		return 0;
2091.27Sad	default:
2101.27Sad		return ENODEV;
2111.27Sad	}
2121.27Sad}
2131.27Sad
2141.1Ssorenvoid *
2151.20Stsutsuipci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
2161.20Stsutsui    int (*func)(void *), void *arg)
2171.1Ssoren{
2181.20Stsutsui
2191.26Stsutsui	if (ih >= NICU_INT)
2201.26Stsutsui		return cpu_intr_establish(ih - NICU_INT, level, func, arg);
2211.4Ssoren	else
2221.4Ssoren		return icu_intr_establish(ih, IST_LEVEL, level, func, arg);
2231.1Ssoren}
2241.1Ssoren
2251.1Ssorenvoid
2261.20Stsutsuipci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
2271.1Ssoren{
2281.20Stsutsui
2291.12Saugustss	/* Try both, only the valid one will disestablish. */
2301.12Saugustss	cpu_intr_disestablish(cookie);
2311.12Saugustss	icu_intr_disestablish(cookie);
2321.1Ssoren}
2331.17Stsutsui
2341.17Stsutsuivoid
2351.17Stsutsuipci_conf_interrupt(pci_chipset_tag_t pc, int bus, int dev, int pin, int swiz,
2361.17Stsutsui    int *iline)
2371.17Stsutsui{
2381.17Stsutsui
2391.26Stsutsui	/*
2401.26Stsutsui	 * Use irq 9 on all devices on the Qube's PCI slot.
2411.26Stsutsui	 * XXX doesn't handle devices over PCI-PCI bridges
2421.26Stsutsui	 */
2431.26Stsutsui	if (bus == 0 && dev == 10 && pin != PCI_INTERRUPT_PIN_NONE)
2441.26Stsutsui		*iline = 9;
2451.17Stsutsui}
2461.17Stsutsui
2471.17Stsutsuiint
2481.17Stsutsuipci_conf_hook(pci_chipset_tag_t pc, int bus, int dev, int func, pcireg_t id)
2491.17Stsutsui{
2501.17Stsutsui
2511.22Stsutsui	/* ignore bogus IDs */
2521.22Stsutsui	if (PCI_VENDOR(id) == 0)
2531.22Stsutsui		return 0;
2541.22Stsutsui
2551.22Stsutsui	/* 2700 hardware wedges on accesses to device 6. */
2561.22Stsutsui	if (bus == 0 && dev == 6)
2571.22Stsutsui		return 0;
2581.22Stsutsui
2591.22Stsutsui	/* 2800 hardware wedges on accesses to device 31. */
2601.22Stsutsui	if (bus == 0 && dev == 31)
2611.22Stsutsui		return 0;
2621.22Stsutsui
2631.30Stsutsui	/* Don't configure the bridge and PCI probe. */
2641.24Sriz	if (PCI_VENDOR(id) == PCI_VENDOR_MARVELL &&
2651.24Sriz	    PCI_PRODUCT(id) == PCI_PRODUCT_MARVELL_GT64011)
2661.17Stsutsui	        return 0;
2671.17Stsutsui
2681.23Stsutsui	/* Don't configure on-board VIA VT82C586 (pcib, uhci) */
2691.23Stsutsui	if (bus == 0 && dev == 9 && (func == 0 || func == 2))
2701.17Stsutsui		return 0;
2711.17Stsutsui
2721.23Stsutsui	/* Enable viaide secondary port. Some firmware doesn't enable it. */
2731.23Stsutsui	if (bus == 0 && dev == 9 && func == 1) {
2741.23Stsutsui		pcitag_t tag;
2751.23Stsutsui		pcireg_t csr;
2761.23Stsutsui
2771.23Stsutsui#define	APO_VIAIDECONF	(APO_VIA_REGBASE + 0x00)
2781.23Stsutsui
2791.23Stsutsui		tag = pci_make_tag(pc, bus, dev, func);
2801.23Stsutsui		csr = pci_conf_read(pc, tag, APO_VIAIDECONF);
2811.23Stsutsui		pci_conf_write(pc, tag, APO_VIAIDECONF,
2821.23Stsutsui		    csr | APO_IDECONF_EN(1));
2831.23Stsutsui	}
2841.19Sgdamore	return PCI_CONF_DEFAULT & ~(PCI_COMMAND_SERR_ENABLE |
2851.19Sgdamore	    PCI_COMMAND_PARITY_ENABLE);
2861.17Stsutsui}
287