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