1 /* 2 * Copyright 2007, Marcus Overhagen. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "pci.h" 7 #include "pci_fixup.h" 8 9 #include <arch/int.h> 10 11 #include <KernelExport.h> 12 13 14 /* 15 * We need to force controllers that have both SATA and PATA controllers to use 16 * the split mode with the SATA controller at function 0 and the PATA 17 * controller at function 1. This way the SATA controller will be picked up by 18 * the AHCI driver and the IDE controller by the generic IDE driver. 19 * 20 * TODO(bga): This does not work when the SATA controller is configured for IDE 21 * mode but this seems to be a problem with the device manager (it tries to load 22 * the IDE driver for the AHCI controller for some reason). 23 */ 24 static void 25 jmicron_fixup_ahci(PCI *pci, int domain, uint8 bus, uint8 device, 26 uint8 function, uint16 deviceId) 27 { 28 // We only care about function 0. 29 if (function != 0) 30 return; 31 32 // And only devices with combined SATA/PATA. 33 switch (deviceId) { 34 case 0x2361: // 1 SATA, 1 PATA 35 case 0x2363: // 2 SATA, 1 PATA 36 case 0x2366: // 2 SATA, 2 PATA 37 break; 38 default: 39 return; 40 } 41 42 dprintf("jmicron_fixup_ahci: domain %u, bus %u, device %u, function %u, " 43 "deviceId 0x%04x\n", domain, bus, device, function, deviceId); 44 45 // Read controller control register (0x40). 46 uint32 val = pci->ReadConfig(domain, bus, device, function, 0x40, 4); 47 dprintf("jmicron_fixup_ahci: Register 0x40 : 0x%08lx\n", val); 48 49 // Clear bits. 50 val &= ~(1 << 1); 51 val &= ~(1 << 9); 52 val &= ~(1 << 13); 53 val &= ~(1 << 15); 54 val &= ~(1 << 16); 55 val &= ~(1 << 17); 56 val &= ~(1 << 18); 57 val &= ~(1 << 19); 58 val &= ~(1 << 22); 59 60 //Set bits. 61 val |= (1 << 0); 62 val |= (1 << 4); 63 val |= (1 << 5); 64 val |= (1 << 7); 65 val |= (1 << 8); 66 val |= (1 << 12); 67 val |= (1 << 14); 68 val |= (1 << 23); 69 70 dprintf("jmicron_fixup_ahci: Register 0x40 : 0x%08lx\n", val); 71 pci->WriteConfig(domain, bus, device, function, 0x40, 4, val); 72 73 // Read IRQ from controller at function 0 and assign this IRQ to the 74 // controller at function 1. 75 uint8 irq = pci->ReadConfig(domain, bus, device, function, 0x3c, 1); 76 dprintf("jmicron_fixup_ahci: Assigning IRQ %d at device " 77 "function 1.\n", irq); 78 pci->WriteConfig(domain, bus, device, 1, 0x3c, 1, irq); 79 } 80 81 82 static void 83 intel_fixup_ahci(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function, 84 uint16 deviceId) 85 { 86 // TODO(bga): disabled until the PCI manager can assign new resources. 87 return; 88 89 switch (deviceId) { 90 case 0x2825: // ICH8 Desktop when in IDE emulation mode 91 dprintf("intel_fixup_ahci: WARNING found ICH8 device id 0x2825\n"); 92 return; 93 case 0x2926: // ICH9 Desktop when in IDE emulation mode 94 dprintf("intel_fixup_ahci: WARNING found ICH9 device id 0x2926\n"); 95 return; 96 97 case 0x27c0: // ICH7 Desktop non-AHCI and non-RAID mode 98 case 0x27c4: // ICH7 Mobile non-AHCI and non-RAID mode 99 case 0x2820: // ICH8 Desktop non-AHCI and non-RAID mode 100 case 0x2828: // ICH8 Mobile non-AHCI and non-RAID mode 101 case 0x2920: // ICH9 Desktop non-AHCI and non-RAID mode (4 ports) 102 case 0x2921: // ICH9 Desktop non-AHCI and non-RAID mode (2 ports) 103 break; 104 default: 105 return; 106 } 107 108 dprintf("intel_fixup_ahci: domain %u, bus %u, device %u, function %u, " 109 "deviceId 0x%04x\n", domain, bus, device, function, deviceId); 110 111 dprintf("intel_fixup_ahci: 0x24: 0x%08lx\n", 112 pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 113 dprintf("intel_fixup_ahci: 0x90: 0x%02lx\n", 114 pci->ReadConfig(domain, bus, device, function, 0x90, 1)); 115 116 uint8 map = pci->ReadConfig(domain, bus, device, function, 0x90, 1); 117 if ((map >> 6) == 0) { 118 uint32 bar5 = pci->ReadConfig(domain, bus, device, function, 0x24, 4); 119 uint16 pcicmd = pci->ReadConfig(domain, bus, device, function, 120 PCI_command, 2); 121 122 dprintf("intel_fixup_ahci: switching from IDE to AHCI mode\n"); 123 124 pci->WriteConfig(domain, bus, device, function, PCI_command, 2, 125 pcicmd & ~(PCI_command_io | PCI_command_memory)); 126 127 pci->WriteConfig(domain, bus, device, function, 0x24, 4, 0xffffffff); 128 dprintf("intel_fixup_ahci: ide-bar5 bits-1: 0x%08lx\n", 129 pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 130 pci->WriteConfig(domain, bus, device, function, 0x24, 4, 0); 131 dprintf("intel_fixup_ahci: ide-bar5 bits-0: 0x%08lx\n", 132 pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 133 134 map &= ~0x03; 135 map |= 0x40; 136 pci->WriteConfig(domain, bus, device, function, 0x90, 1, map); 137 138 pci->WriteConfig(domain, bus, device, function, 0x24, 4, 0xffffffff); 139 dprintf("intel_fixup_ahci: ahci-bar5 bits-1: 0x%08lx\n", 140 pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 141 pci->WriteConfig(domain, bus, device, function, 0x24, 4, 0); 142 dprintf("intel_fixup_ahci: ahci-bar5 bits-0: 0x%08lx\n", 143 pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 144 145 if (deviceId == 0x27c0 || deviceId == 0x27c4) // restore on ICH7 146 pci->WriteConfig(domain, bus, device, function, 0x24, 4, bar5); 147 148 pci->WriteConfig(domain, bus, device, function, PCI_command, 2, pcicmd); 149 } 150 151 dprintf("intel_fixup_ahci: 0x24: 0x%08lx\n", 152 pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 153 dprintf("intel_fixup_ahci: 0x90: 0x%02lx\n", 154 pci->ReadConfig(domain, bus, device, function, 0x90, 1)); 155 } 156 157 158 static void 159 ati_fixup_ixp(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function, uint16 deviceId) 160 { 161 #ifdef __INTEL__ 162 /* ATI Technologies Inc, IXP chipset: 163 * This chipset seems broken, at least on my laptop I must force 164 * the timer IRQ trigger mode, else no interrupt comes in. 165 * mmu_man. 166 */ 167 // XXX: should I use host or isa bridges for detection ?? 168 switch (deviceId) { 169 // Host bridges 170 case 0x5950: // RS480 Host Bridge 171 case 0x5830: 172 break; 173 // ISA bridges 174 case 0x4377: // IXP SB400 PCI-ISA Bridge 175 default: 176 return; 177 } 178 dprintf("ati_fixup_ixp: domain %u, bus %u, device %u, function %u, deviceId 0x%04x\n", 179 domain, bus, device, function, deviceId); 180 181 dprintf("ati_fixup_ixp: found IXP chipset, forcing IRQ 0 as level triggered.\n"); 182 // XXX: maybe use pic_*() ? 183 arch_int_configure_io_interrupt(0, B_LEVEL_TRIGGERED); 184 185 #endif 186 } 187 188 189 void 190 pci_fixup_device(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function) 191 { 192 uint16 vendorId = pci->ReadConfig(domain, bus, device, function, 193 PCI_vendor_id, 2); 194 uint16 deviceId = pci->ReadConfig(domain, bus, device, function, 195 PCI_device_id, 2); 196 197 // dprintf("pci_fixup_device: domain %u, bus %u, device %u, function %u\n", 198 // domain, bus, device, function); 199 200 switch (vendorId) { 201 case 0x197b: 202 jmicron_fixup_ahci(pci, domain, bus, device, function, deviceId); 203 break; 204 205 case 0x8086: 206 intel_fixup_ahci(pci, domain, bus, device, function, deviceId); 207 break; 208 209 case 0x1002: 210 ati_fixup_ixp(pci, domain, bus, device, function, deviceId); 211 break; 212 } 213 } 214 215