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, uint8 function, uint16 deviceId) 21 { 22 switch (deviceId) { 23 case 0x2361: // 1 SATA, 1 PATA 24 case 0x2363: // 2 SATA, 1 PATA 25 case 0x2366: // 2 SATA, 2 PATA 26 break; 27 // case 0x2360: // 1 SATA 28 // case 0x2362: // 2 SATA 29 default: 30 return; 31 } 32 33 dprintf("jmicron_fixup_ahci: domain %u, bus %u, device %u, function %u, deviceId 0x%04x\n", 34 domain, bus, device, function, deviceId); 35 36 if (function == 0) { 37 dprintf("jmicron_fixup_ahci: 0x40: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x40, 4)); 38 dprintf("jmicron_fixup_ahci: 0xdc: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0xdc, 4)); 39 uint32 val = pci->ReadPciConfig(domain, bus, device, function, 0xdc, 4); 40 if (!(val & (1 << 30))) { 41 uint8 irq = pci->ReadPciConfig(domain, bus, device, function, 0x3c, 1); 42 dprintf("jmicron_fixup_ahci: enabling split device mode\n"); 43 val &= ~(1 << 24); 44 val |= (1 << 25) | (1 << 30); 45 pci->WritePciConfig(domain, bus, device, function, 0xdc, 4, val); 46 val = pci->ReadPciConfig(domain, bus, device, function, 0x40, 4); 47 val &= ~(1 << 16); 48 val |= (1 << 1) | (1 << 17) | (1 << 22); 49 pci->WritePciConfig(domain, bus, device, function, 0x40, 4, val); 50 if (function == 0) 51 pci->WritePciConfig(domain, bus, device, 1, 0x3c, 1, irq); 52 else 53 dprintf("jmicron_fixup_ahci: can't assign IRQ\n"); 54 } 55 dprintf("jmicron_fixup_ahci: 0x40: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x40, 4)); 56 dprintf("jmicron_fixup_ahci: 0xdc: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0xdc, 4)); 57 } 58 } 59 60 61 static void 62 intel_fixup_ahci(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function, uint16 deviceId) 63 { 64 return; /* disabled until the PCI manager can assign new resources */ 65 66 switch (deviceId) { 67 case 0x2825: // ICH8 Desktop when in IDE emulation mode 68 dprintf("intel_fixup_ahci: WARNING found ICH8 device id 0x2825\n"); 69 return; 70 case 0x2926: // ICH9 Desktop when in IDE emulation mode 71 dprintf("intel_fixup_ahci: WARNING found ICH9 device id 0x2926\n"); 72 return; 73 74 case 0x27c0: // ICH7 Desktop non-AHCI and non-RAID mode 75 case 0x27c4: // ICH7 Mobile non-AHCI and non-RAID mode 76 case 0x2820: // ICH8 Desktop non-AHCI and non-RAID mode 77 case 0x2828: // ICH8 Mobile non-AHCI and non-RAID mode 78 case 0x2920: // ICH9 Desktop non-AHCI and non-RAID mode (4 ports) 79 case 0x2921: // ICH9 Desktop non-AHCI and non-RAID mode (2 ports) 80 break; 81 default: 82 return; 83 } 84 85 dprintf("intel_fixup_ahci: domain %u, bus %u, device %u, function %u, deviceId 0x%04x\n", 86 domain, bus, device, function, deviceId); 87 88 dprintf("intel_fixup_ahci: 0x24: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x24, 4)); 89 dprintf("intel_fixup_ahci: 0x90: 0x%02lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x90, 1)); 90 91 uint8 map = pci->ReadPciConfig(domain, bus, device, function, 0x90, 1); 92 if ((map >> 6) == 0) { 93 uint32 bar5 = pci->ReadPciConfig(domain, bus, device, function, 0x24, 4); 94 uint16 pcicmd = pci->ReadPciConfig(domain, bus, device, function, PCI_command, 2); 95 96 dprintf("intel_fixup_ahci: switching from IDE to AHCI mode\n"); 97 98 pci->WritePciConfig(domain, bus, device, function, PCI_command, 2, 99 pcicmd & ~(PCI_command_io | PCI_command_memory)); 100 101 pci->WritePciConfig(domain, bus, device, function, 0x24, 4, 0xffffffff); 102 dprintf("intel_fixup_ahci: ide-bar5 bits-1: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x24, 4)); 103 pci->WritePciConfig(domain, bus, device, function, 0x24, 4, 0); 104 dprintf("intel_fixup_ahci: ide-bar5 bits-0: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x24, 4)); 105 106 map &= ~0x03; 107 map |= 0x40; 108 pci->WritePciConfig(domain, bus, device, function, 0x90, 1, map); 109 110 pci->WritePciConfig(domain, bus, device, function, 0x24, 4, 0xffffffff); 111 dprintf("intel_fixup_ahci: ahci-bar5 bits-1: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x24, 4)); 112 pci->WritePciConfig(domain, bus, device, function, 0x24, 4, 0); 113 dprintf("intel_fixup_ahci: ahci-bar5 bits-0: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x24, 4)); 114 115 if (deviceId == 0x27c0 || deviceId == 0x27c4) // restore on ICH7 116 pci->WritePciConfig(domain, bus, device, function, 0x24, 4, bar5); 117 118 pci->WritePciConfig(domain, bus, device, function, PCI_command, 2, pcicmd); 119 } 120 121 dprintf("intel_fixup_ahci: 0x24: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x24, 4)); 122 dprintf("intel_fixup_ahci: 0x90: 0x%02lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x90, 1)); 123 } 124 125 126 void 127 pci_fixup_device(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function) 128 { 129 uint16 vendorId = pci->ReadPciConfig(domain, bus, device, function, PCI_vendor_id, 2); 130 uint16 deviceId = pci->ReadPciConfig(domain, bus, device, function, PCI_device_id, 2); 131 132 // dprintf("pci_fixup_device: domain %u, bus %u, device %u, function %u\n", domain, bus, device, function); 133 134 switch (vendorId) { 135 case 0x197b: 136 jmicron_fixup_ahci(pci, domain, bus, device, function, deviceId); 137 break; 138 139 case 0x8086: 140 intel_fixup_ahci(pci, domain, bus, device, function, deviceId); 141 break; 142 } 143 } 144 145