1 /* 2 * Copyright 2007, Marcus Overhagen. All rights reserved. 3 * 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include "pci.h" 8 #include "pci_fixup.h" 9 10 #include <KernelExport.h> 11 12 /* The Jmicron AHCI controller has a mode that combines IDE and AHCI functionality 13 * into a single PCI device at function 0. This happens when the controller is set 14 * in the BIOS to "basic" or "IDE" mode (but not in "RAID" or "AHCI" mode). 15 * To avoid needing two drivers to handle a single PCI device, we switch to the 16 * multifunction (split device) AHCI mode. This will set PCI device at function 0 17 * to AHCI, and PCI device at function 1 to IDE controller. 18 */ 19 static void 20 jmicron_fixup_ahci(PCI *pci, int domain, uint8 bus, uint8 device, 21 uint8 function, uint16 deviceId) 22 { 23 switch (deviceId) { 24 case 0x2361: // 1 SATA, 1 PATA 25 case 0x2363: // 2 SATA, 1 PATA 26 case 0x2366: // 2 SATA, 2 PATA 27 break; 28 // case 0x2360: // 1 SATA 29 // case 0x2362: // 2 SATA 30 default: 31 return; 32 } 33 34 dprintf("jmicron_fixup_ahci: domain %u, bus %u, device %u, function %u, deviceId 0x%04x\n", 35 domain, bus, device, function, deviceId); 36 37 if (function == 0) { 38 dprintf("jmicron_fixup_ahci: 0x40: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0x40, 4)); 39 dprintf("jmicron_fixup_ahci: 0xdc: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0xdc, 4)); 40 uint32 val = pci->ReadConfig(domain, bus, device, function, 0xdc, 4); 41 if (!(val & (1 << 30))) { 42 uint8 irq = pci->ReadConfig(domain, bus, device, function, 0x3c, 1); 43 dprintf("jmicron_fixup_ahci: enabling split device mode\n"); 44 val &= ~(1 << 24); 45 val |= (1 << 25) | (1 << 30); 46 pci->WriteConfig(domain, bus, device, function, 0xdc, 4, val); 47 val = pci->ReadConfig(domain, bus, device, function, 0x40, 4); 48 val &= ~(1 << 16); 49 val |= (1 << 1) | (1 << 17) | (1 << 22); 50 pci->WriteConfig(domain, bus, device, function, 0x40, 4, val); 51 if (function == 0) 52 pci->WriteConfig(domain, bus, device, 1, 0x3c, 1, irq); 53 else 54 dprintf("jmicron_fixup_ahci: can't assign IRQ\n"); 55 } 56 dprintf("jmicron_fixup_ahci: 0x40: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0x40, 4)); 57 dprintf("jmicron_fixup_ahci: 0xdc: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0xdc, 4)); 58 } 59 } 60 61 62 static void 63 intel_fixup_ahci(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function, uint16 deviceId) 64 { 65 return; /* disabled until the PCI manager can assign new resources */ 66 67 switch (deviceId) { 68 case 0x2825: // ICH8 Desktop when in IDE emulation mode 69 dprintf("intel_fixup_ahci: WARNING found ICH8 device id 0x2825\n"); 70 return; 71 case 0x2926: // ICH9 Desktop when in IDE emulation mode 72 dprintf("intel_fixup_ahci: WARNING found ICH9 device id 0x2926\n"); 73 return; 74 75 case 0x27c0: // ICH7 Desktop non-AHCI and non-RAID mode 76 case 0x27c4: // ICH7 Mobile non-AHCI and non-RAID mode 77 case 0x2820: // ICH8 Desktop non-AHCI and non-RAID mode 78 case 0x2828: // ICH8 Mobile non-AHCI and non-RAID mode 79 case 0x2920: // ICH9 Desktop non-AHCI and non-RAID mode (4 ports) 80 case 0x2921: // ICH9 Desktop non-AHCI and non-RAID mode (2 ports) 81 break; 82 default: 83 return; 84 } 85 86 dprintf("intel_fixup_ahci: domain %u, bus %u, device %u, function %u, deviceId 0x%04x\n", 87 domain, bus, device, function, deviceId); 88 89 dprintf("intel_fixup_ahci: 0x24: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 90 dprintf("intel_fixup_ahci: 0x90: 0x%02lx\n", pci->ReadConfig(domain, bus, device, function, 0x90, 1)); 91 92 uint8 map = pci->ReadConfig(domain, bus, device, function, 0x90, 1); 93 if ((map >> 6) == 0) { 94 uint32 bar5 = pci->ReadConfig(domain, bus, device, function, 0x24, 4); 95 uint16 pcicmd = pci->ReadConfig(domain, bus, device, function, PCI_command, 2); 96 97 dprintf("intel_fixup_ahci: switching from IDE to AHCI mode\n"); 98 99 pci->WriteConfig(domain, bus, device, function, PCI_command, 2, 100 pcicmd & ~(PCI_command_io | PCI_command_memory)); 101 102 pci->WriteConfig(domain, bus, device, function, 0x24, 4, 0xffffffff); 103 dprintf("intel_fixup_ahci: ide-bar5 bits-1: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 104 pci->WriteConfig(domain, bus, device, function, 0x24, 4, 0); 105 dprintf("intel_fixup_ahci: ide-bar5 bits-0: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 106 107 map &= ~0x03; 108 map |= 0x40; 109 pci->WriteConfig(domain, bus, device, function, 0x90, 1, map); 110 111 pci->WriteConfig(domain, bus, device, function, 0x24, 4, 0xffffffff); 112 dprintf("intel_fixup_ahci: ahci-bar5 bits-1: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 113 pci->WriteConfig(domain, bus, device, function, 0x24, 4, 0); 114 dprintf("intel_fixup_ahci: ahci-bar5 bits-0: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 115 116 if (deviceId == 0x27c0 || deviceId == 0x27c4) // restore on ICH7 117 pci->WriteConfig(domain, bus, device, function, 0x24, 4, bar5); 118 119 pci->WriteConfig(domain, bus, device, function, PCI_command, 2, pcicmd); 120 } 121 122 dprintf("intel_fixup_ahci: 0x24: 0x%08lx\n", pci->ReadConfig(domain, bus, device, function, 0x24, 4)); 123 dprintf("intel_fixup_ahci: 0x90: 0x%02lx\n", pci->ReadConfig(domain, bus, device, function, 0x90, 1)); 124 } 125 126 127 void 128 pci_fixup_device(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function) 129 { 130 uint16 vendorId = pci->ReadConfig(domain, bus, device, function, PCI_vendor_id, 2); 131 uint16 deviceId = pci->ReadConfig(domain, bus, device, function, PCI_device_id, 2); 132 133 // dprintf("pci_fixup_device: domain %u, bus %u, device %u, function %u\n", domain, bus, device, function); 134 135 switch (vendorId) { 136 case 0x197b: 137 jmicron_fixup_ahci(pci, domain, bus, device, function, deviceId); 138 break; 139 140 case 0x8086: 141 intel_fixup_ahci(pci, domain, bus, device, function, deviceId); 142 break; 143 } 144 } 145 146