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 */
24static void
25jmicron_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
82static void
83intel_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
158static void
159ati_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
190void
191pci_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