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