xref: /haiku/src/add-ons/kernel/bus_managers/pci/pci_fixup.cpp (revision 5ffbe7d778424c9c59f00b37a3baff5c4c648790)
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
jmicron_fixup_ahci(PCI * pci,uint8 domain,uint8 bus,uint8 device,uint8 function,uint16 deviceId)25 jmicron_fixup_ahci(PCI *pci, uint8 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%08" B_PRIx32 "\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%08" B_PRIx32 "\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
intel_fixup_ahci(PCI * pci,uint8 domain,uint8 bus,uint8 device,uint8 function,uint16 deviceId)83 intel_fixup_ahci(PCI *pci, uint8 domain, uint8 bus, uint8 device,
84 	uint8 function, 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%08" B_PRIx32 "\n",
112 		pci->ReadConfig(domain, bus, device, function, 0x24, 4));
113 	dprintf("intel_fixup_ahci: 0x90: 0x%02" B_PRIx32 "\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%08" B_PRIx32 "\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%08" B_PRIx32 "\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%08" B_PRIx32 "\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%08" B_PRIx32 "\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%08" B_PRIx32 "\n",
152 		pci->ReadConfig(domain, bus, device, function, 0x24, 4));
153 	dprintf("intel_fixup_ahci: 0x90: 0x%02" B_PRIx32 "\n",
154 		pci->ReadConfig(domain, bus, device, function, 0x90, 1));
155 }
156 
157 
158 static void
ati_fixup_ixp(PCI * pci,uint8 domain,uint8 bus,uint8 device,uint8 function,uint16 deviceId)159 ati_fixup_ixp(PCI *pci, uint8 domain, uint8 bus, uint8 device, uint8 function,
160 	uint16 deviceId)
161 {
162 #if defined(__i386__) || defined(__x86_64__)
163 	/* ATI Technologies Inc, IXP chipset:
164 	 * This chipset seems broken, at least on my laptop I must force
165 	 * the timer IRQ trigger mode, else no interrupt comes in.
166 	 * mmu_man.
167 	 */
168 	// XXX: should I use host or isa bridges for detection ??
169 	switch (deviceId) {
170 		// Host bridges
171 		case 0x5950:	// RS480 Host Bridge
172 		case 0x5830:
173 			break;
174 		// ISA bridges
175 		case 0x4377:	// IXP SB400 PCI-ISA Bridge
176 		default:
177 			return;
178 	}
179 	dprintf("ati_fixup_ixp: domain %u, bus %u, device %u, function %u, deviceId 0x%04x\n",
180 		domain, bus, device, function, deviceId);
181 
182 	dprintf("ati_fixup_ixp: found IXP chipset, forcing IRQ 0 as level triggered.\n");
183 	// XXX: maybe use pic_*() ?
184 	arch_int_configure_io_interrupt(0, B_LEVEL_TRIGGERED);
185 
186 #endif
187 }
188 
189 
190 void
pci_fixup_device(PCI * pci,uint8 domain,uint8 bus,uint8 device,uint8 function)191 pci_fixup_device(PCI *pci, uint8 domain, uint8 bus, uint8 device,
192 	uint8 function)
193 {
194 	uint16 vendorId = pci->ReadConfig(domain, bus, device, function,
195 		PCI_vendor_id, 2);
196 	uint16 deviceId = pci->ReadConfig(domain, bus, device, function,
197 		PCI_device_id, 2);
198 
199 //	dprintf("pci_fixup_device: domain %u, bus %u, device %u, function %u\n",
200 //		domain, bus, device, function);
201 
202 	switch (vendorId) {
203 		case 0x197b:
204 			jmicron_fixup_ahci(pci, domain, bus, device, function, deviceId);
205 			break;
206 
207 		case 0x8086:
208 			intel_fixup_ahci(pci, domain, bus, device, function, deviceId);
209 			break;
210 
211 		case 0x1002:
212 			ati_fixup_ixp(pci, domain, bus, device, function, deviceId);
213 			break;
214 	}
215 }
216 
217