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