1*c88420b3Sdmick /* 2*c88420b3Sdmick * CDDL HEADER START 3*c88420b3Sdmick * 4*c88420b3Sdmick * The contents of this file are subject to the terms of the 5*c88420b3Sdmick * Common Development and Distribution License, Version 1.0 only 6*c88420b3Sdmick * (the "License"). You may not use this file except in compliance 7*c88420b3Sdmick * with the License. 8*c88420b3Sdmick * 9*c88420b3Sdmick * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*c88420b3Sdmick * or http://www.opensolaris.org/os/licensing. 11*c88420b3Sdmick * See the License for the specific language governing permissions 12*c88420b3Sdmick * and limitations under the License. 13*c88420b3Sdmick * 14*c88420b3Sdmick * When distributing Covered Code, include this CDDL HEADER in each 15*c88420b3Sdmick * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*c88420b3Sdmick * If applicable, add the following below this CDDL HEADER, with the 17*c88420b3Sdmick * fields enclosed by brackets "[]" replaced with your own identifying 18*c88420b3Sdmick * information: Portions Copyright [yyyy] [name of copyright owner] 19*c88420b3Sdmick * 20*c88420b3Sdmick * CDDL HEADER END 21*c88420b3Sdmick */ 22*c88420b3Sdmick /* 23*c88420b3Sdmick * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*c88420b3Sdmick * Use is subject to license terms. 25*c88420b3Sdmick */ 26*c88420b3Sdmick 27*c88420b3Sdmick #pragma ident "%Z%%M% %I% %E% SMI" 28*c88420b3Sdmick 29*c88420b3Sdmick /* 30*c88420b3Sdmick * Support for Intel "Neptune" PCI chip set 31*c88420b3Sdmick */ 32*c88420b3Sdmick 33*c88420b3Sdmick #include <sys/types.h> 34*c88420b3Sdmick #include <sys/pci.h> 35*c88420b3Sdmick #include <sys/pci_impl.h> 36*c88420b3Sdmick #include <sys/sunddi.h> 37*c88420b3Sdmick #include <sys/pci_cfgspace_impl.h> 38*c88420b3Sdmick 39*c88420b3Sdmick /* 40*c88420b3Sdmick * This variable is a place holder for the initial value in PCI_PMC register 41*c88420b3Sdmick * of neptune chipset. 42*c88420b3Sdmick */ 43*c88420b3Sdmick static unsigned char neptune_BIOS_cfg_method = 0; 44*c88420b3Sdmick 45*c88420b3Sdmick /* 46*c88420b3Sdmick * Special hack for Intel's Neptune chipset, 82433NX and 82434NX. 47*c88420b3Sdmick * 48*c88420b3Sdmick * The motherboards I've seen still use a version of the BIOS 49*c88420b3Sdmick * that operates using Configuration Mechanism #2 like the older 50*c88420b3Sdmick * Mercury BIOS and chipset (the 82433LX and 82434LX). 51*c88420b3Sdmick * 52*c88420b3Sdmick */ 53*c88420b3Sdmick boolean_t 54*c88420b3Sdmick pci_check_neptune(void) 55*c88420b3Sdmick { 56*c88420b3Sdmick uint8_t oldstatus; 57*c88420b3Sdmick uint32_t tmp; 58*c88420b3Sdmick 59*c88420b3Sdmick /* enable the config address space, bus=0 function=0 */ 60*c88420b3Sdmick oldstatus = inb(PCI_CSE_PORT); 61*c88420b3Sdmick outb(PCI_CSE_PORT, PCI_MECH2_CONFIG_ENABLE); 62*c88420b3Sdmick outb(PCI_FORW_PORT, 0); 63*c88420b3Sdmick 64*c88420b3Sdmick /* 65*c88420b3Sdmick * First check the vendor and device ids of the Host to 66*c88420b3Sdmick * PCI bridge. But it isn't sufficient just to do this check 67*c88420b3Sdmick * because the same device ID can refer to either 68*c88420b3Sdmick * the Neptune or Mercury chipset. 69*c88420b3Sdmick */ 70*c88420b3Sdmick 71*c88420b3Sdmick /* check the vendor id, the device id, and the revision id */ 72*c88420b3Sdmick /* the Neptune revision ID == 0x11, allow 0x1? */ 73*c88420b3Sdmick if ((inl(PCI_CADDR2(0, PCI_CONF_VENID)) != 0x04a38086) || 74*c88420b3Sdmick (inb(PCI_CADDR2(0, PCI_CONF_REVID)) & 0xf0) != 0x10) { 75*c88420b3Sdmick /* disable mechanism #2 config address space */ 76*c88420b3Sdmick outb(PCI_CSE_PORT, oldstatus); 77*c88420b3Sdmick return (B_FALSE); 78*c88420b3Sdmick } 79*c88420b3Sdmick 80*c88420b3Sdmick /* disable mechanism #2 config address space */ 81*c88420b3Sdmick outb(PCI_CSE_PORT, oldstatus); 82*c88420b3Sdmick 83*c88420b3Sdmick /* 84*c88420b3Sdmick * Now I know that the bridge *might* be a Neptune (it could be 85*c88420b3Sdmick * a Mercury chip.) Try enabling mechanism #1 to differentiate 86*c88420b3Sdmick * between the two chipsets. 87*c88420b3Sdmick */ 88*c88420b3Sdmick 89*c88420b3Sdmick /* 90*c88420b3Sdmick * save the old value in case it's not Neptune (the Mercury 91*c88420b3Sdmick * chip has the deturbo and reset bits in the 0xcf9 register 92*c88420b3Sdmick * and the forward register at 0xcfa) 93*c88420b3Sdmick */ 94*c88420b3Sdmick tmp = inl(PCI_CONFADD); 95*c88420b3Sdmick 96*c88420b3Sdmick /* 97*c88420b3Sdmick * The Intel Neptune chipset defines this extra register 98*c88420b3Sdmick * to enable Config Mechanism #1. 99*c88420b3Sdmick */ 100*c88420b3Sdmick neptune_BIOS_cfg_method = inb(PCI_PMC); 101*c88420b3Sdmick outb(PCI_PMC, neptune_BIOS_cfg_method | 1); 102*c88420b3Sdmick 103*c88420b3Sdmick /* make certain mechanism #1 works correctly */ 104*c88420b3Sdmick /* check the vendor and device id's of the Host to PCI bridge */ 105*c88420b3Sdmick outl(PCI_CONFADD, PCI_CADDR1(0, 0, 0, PCI_CONF_VENID)); 106*c88420b3Sdmick if (inl(PCI_CONFDATA) != ((0x04a3 << 16) | 0x8086)) { 107*c88420b3Sdmick outb(PCI_PMC, neptune_BIOS_cfg_method); 108*c88420b3Sdmick outl(PCI_CONFADD, tmp); 109*c88420b3Sdmick return (B_FALSE); 110*c88420b3Sdmick } 111*c88420b3Sdmick outb(PCI_PMC, neptune_BIOS_cfg_method); 112*c88420b3Sdmick return (B_TRUE); 113*c88420b3Sdmick } 114*c88420b3Sdmick 115*c88420b3Sdmick static void 116*c88420b3Sdmick pci_neptune_enable() 117*c88420b3Sdmick { 118*c88420b3Sdmick /* 119*c88420b3Sdmick * Switch the chipset to use Mechanism 1. 120*c88420b3Sdmick */ 121*c88420b3Sdmick mutex_enter(&pcicfg_chipset_mutex); 122*c88420b3Sdmick outb(PCI_PMC, neptune_BIOS_cfg_method | 1); 123*c88420b3Sdmick } 124*c88420b3Sdmick 125*c88420b3Sdmick static void 126*c88420b3Sdmick pci_neptune_disable() 127*c88420b3Sdmick { 128*c88420b3Sdmick /* 129*c88420b3Sdmick * The Neptune chipset has a bug that if you write the PMC, 130*c88420b3Sdmick * it erroneously looks at some of the bits in the latches for 131*c88420b3Sdmick * adjacent registers... like, say, the "reset" bit. We zero 132*c88420b3Sdmick * out the config address register to work around this bug. 133*c88420b3Sdmick */ 134*c88420b3Sdmick outl(PCI_CONFADD, PCI_CADDR1(0, 0, 0, 0)); 135*c88420b3Sdmick outb(PCI_PMC, neptune_BIOS_cfg_method); 136*c88420b3Sdmick mutex_exit(&pcicfg_chipset_mutex); 137*c88420b3Sdmick } 138*c88420b3Sdmick 139*c88420b3Sdmick uint8_t 140*c88420b3Sdmick pci_neptune_getb(int bus, int device, int function, int reg) 141*c88420b3Sdmick { 142*c88420b3Sdmick uint8_t val; 143*c88420b3Sdmick 144*c88420b3Sdmick pci_neptune_enable(); 145*c88420b3Sdmick 146*c88420b3Sdmick val = pci_mech1_getb(bus, device, function, reg); 147*c88420b3Sdmick 148*c88420b3Sdmick pci_neptune_disable(); 149*c88420b3Sdmick return (val); 150*c88420b3Sdmick } 151*c88420b3Sdmick 152*c88420b3Sdmick uint16_t 153*c88420b3Sdmick pci_neptune_getw(int bus, int device, int function, int reg) 154*c88420b3Sdmick { 155*c88420b3Sdmick uint16_t val; 156*c88420b3Sdmick 157*c88420b3Sdmick pci_neptune_enable(); 158*c88420b3Sdmick 159*c88420b3Sdmick val = pci_mech1_getw(bus, device, function, reg); 160*c88420b3Sdmick 161*c88420b3Sdmick pci_neptune_disable(); 162*c88420b3Sdmick return (val); 163*c88420b3Sdmick } 164*c88420b3Sdmick 165*c88420b3Sdmick uint32_t 166*c88420b3Sdmick pci_neptune_getl(int bus, int device, int function, int reg) 167*c88420b3Sdmick { 168*c88420b3Sdmick uint32_t val; 169*c88420b3Sdmick 170*c88420b3Sdmick pci_neptune_enable(); 171*c88420b3Sdmick 172*c88420b3Sdmick val = pci_mech1_getl(bus, device, function, reg); 173*c88420b3Sdmick 174*c88420b3Sdmick pci_neptune_disable(); 175*c88420b3Sdmick return (val); 176*c88420b3Sdmick } 177*c88420b3Sdmick 178*c88420b3Sdmick void 179*c88420b3Sdmick pci_neptune_putb(int bus, int device, int function, int reg, uint8_t val) 180*c88420b3Sdmick { 181*c88420b3Sdmick pci_neptune_enable(); 182*c88420b3Sdmick 183*c88420b3Sdmick pci_mech1_putb(bus, device, function, reg, val); 184*c88420b3Sdmick 185*c88420b3Sdmick pci_neptune_disable(); 186*c88420b3Sdmick } 187*c88420b3Sdmick 188*c88420b3Sdmick void 189*c88420b3Sdmick pci_neptune_putw(int bus, int device, int function, int reg, uint16_t val) 190*c88420b3Sdmick { 191*c88420b3Sdmick pci_neptune_enable(); 192*c88420b3Sdmick 193*c88420b3Sdmick pci_mech1_putw(bus, device, function, reg, val); 194*c88420b3Sdmick 195*c88420b3Sdmick pci_neptune_disable(); 196*c88420b3Sdmick } 197*c88420b3Sdmick 198*c88420b3Sdmick void 199*c88420b3Sdmick pci_neptune_putl(int bus, int device, int function, int reg, uint32_t val) 200*c88420b3Sdmick { 201*c88420b3Sdmick pci_neptune_enable(); 202*c88420b3Sdmick 203*c88420b3Sdmick pci_mech1_putl(bus, device, function, reg, val); 204*c88420b3Sdmick 205*c88420b3Sdmick pci_neptune_disable(); 206*c88420b3Sdmick } 207