xref: /haiku/src/add-ons/kernel/bus_managers/pci/pci_fixup.cpp (revision b30304acc8c37e678a1bf66976d15bdab103f931)
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