1103959Smarkm/*
2103959Smarkm * BeOS Driver for Intel ICH AC'97 Link interface
3103959Smarkm *
4 * Copyright (c) 2002-2005 Marcus Overhagen <marcus@overhagen.de>
5 *
6 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * - Redistributions of source code must retain the above copyright notice,
11 *   this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright notice,
13 *   this list of conditions and the following disclaimer in the documentation
14 *   and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28#include <KernelExport.h>
29#include <config_manager.h>
30#include <PCI.h>
31#include <OS.h>
32#include <malloc.h>
33
34#include "debug.h"
35#include "config.h"
36#include "ich.h"
37
38extern pci_module_info *pci;
39
40device_config c;
41device_config *config = &c;
42
43struct device_item {
44	uint16			vendor_id;
45	uint16			device_id;
46	uint8			type;
47	const char *	name;
48} device_list[] = {
49	{ 0x8086, 0x7195, TYPE_DEFAULT, "Intel 82443MX" },
50	{ 0x8086, 0x2415, TYPE_DEFAULT, "Intel 82801AA (ICH)" },
51	{ 0x8086, 0x2425, TYPE_DEFAULT, "Intel 82801AB (ICH0)" },
52	{ 0x8086, 0x2445, TYPE_DEFAULT, "Intel 82801BA (ICH2), Intel 82801BAM (ICH2-M)" },
53	{ 0x8086, 0x2485, TYPE_DEFAULT, "Intel 82801CA (ICH3-S), Intel 82801CAM (ICH3-M)" },
54	{ 0x8086, 0x24C5, TYPE_ICH4,	"Intel 82801DB (ICH4)" },
55	{ 0x8086, 0x24D5, TYPE_ICH4,	"Intel 82801EB (ICH5), Intel 82801ER (ICH5R)" },
56	{ 0x8086, 0x266E, TYPE_ICH4,	"Intel 82801FB/FR/FW/FRW (ICH6)" },
57	{ 0x8086, 0x27DE, TYPE_ICH4,	"Intel unknown (ICH7)" },
58	{ 0x8086, 0x2698, TYPE_ICH4,	"Intel unknown (ESB2)" },
59	{ 0x8086, 0x25A6, TYPE_ICH4,	"Intel unknown (ESB5)" },
60	{ 0x1039, 0x7012, TYPE_SIS7012,	"SiS SI7012" },
61	{ 0x10DE, 0x01B1, TYPE_DEFAULT,	"NVIDIA nForce (MCP)" },
62	{ 0x10DE, 0x006A, TYPE_DEFAULT, "NVIDIA nForce 2 (MCP2)" },
63	{ 0x10DE, 0x00DA, TYPE_DEFAULT,	"NVIDIA nForce 3 (MCP3)" },
64	{ 0x10DE, 0x003A, TYPE_DEFAULT,	"NVIDIA unknown (MCP04)" },
65	{ 0x10DE, 0x0059, TYPE_DEFAULT,	"NVIDIA unknown (CK804)" },
66	{ 0x10DE, 0x008A, TYPE_DEFAULT,	"NVIDIA unknown (CK8)" },
67	{ 0x10DE, 0x00EA, TYPE_DEFAULT,	"NVIDIA unknown (CK8S)" },
68	{ 0x1022, 0x746D, TYPE_DEFAULT, "AMD AMD8111" },
69	{ 0x1022, 0x7445, TYPE_DEFAULT, "AMD AMD768" },
70//	{ 0x10B9, 0x5455, TYPE_DEFAULT, "Ali 5455" }, not yet supported
71	{ },
72};
73
74
75/**
76 * search for the ICH AC97 controller, and initialize the global config
77 */
78status_t
79probe_device(void)
80{
81	struct pci_info info;
82	struct pci_info *pciinfo = &info;
83	int index;
84	int i;
85	status_t result;
86	uint32 value;
87
88	// initialize whole config to 0
89	memset(config, 0, sizeof(*config));
90
91	result = B_OK;
92
93	for (index = 0; B_OK == pci->get_nth_pci_info(index, pciinfo); index++) {
94		LOG(("Checking PCI device, vendor 0x%04x, id 0x%04x, bus 0x%02x, dev 0x%02x, func 0x%02x, rev 0x%02x, api 0x%02x, sub 0x%02x, base 0x%02x\n",
95			pciinfo->vendor_id, pciinfo->device_id, pciinfo->bus, pciinfo->device, pciinfo->function,
96			pciinfo->revision, pciinfo->class_api, pciinfo->class_sub, pciinfo->class_base));
97		for (i = 0; device_list[i].vendor_id; i++) {
98			if (device_list[i].vendor_id == pciinfo->vendor_id && device_list[i].device_id == pciinfo->device_id) {
99				config->name = device_list[i].name;
100				config->type = device_list[i].type;
101				goto probe_ok;
102			}
103		}
104	}
105	LOG(("No compatible hardware found\n"));
106	result = B_ERROR;
107	goto probe_done;
108
109probe_ok:
110	LOG(("found %s\n",config->name));
111	LOG(("revision = %d\n",pciinfo->revision));
112
113	#if DEBUG
114		LOG(("bus = %d, device = %d, function = %d\n", pciinfo->bus, pciinfo->device, pciinfo->function));
115		value = pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, PCI_vendor_id, 2);
116		LOG(("vendor id = 0x%04x\n",value));
117		value = pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, PCI_device_id, 2);
118		LOG(("device id = 0x%04x\n",value));
119		value = pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, PCI_revision, 1);
120		LOG(("revision = 0x%02x\n",value));
121		value = pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, PCI_subsystem_vendor_id, 2);
122		LOG(("subsystem vendor = 0x%04x\n",value));
123		value = pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, PCI_subsystem_id, 2);
124		LOG(("subsystem device = 0x%04x\n",value));
125		value = pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, 0x04, 2);
126		LOG(("PCICMD = %#04x\n",value));
127		value = pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, 0x06, 2);
128		LOG(("PCISTS = %#04x\n",value));
129	#endif
130
131	/* for ICH4 enable memory mapped IO and busmaster access,
132	 * for old ICHs enable programmed IO and busmaster access
133	 */
134	value = pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, PCI_PCICMD, 2);
135	if (config->type & TYPE_ICH4)
136		value |= PCI_PCICMD_MSE | PCI_PCICMD_BME;
137	else
138		value |= PCI_PCICMD_IOS | PCI_PCICMD_BME;
139	pci->write_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, PCI_PCICMD, 2, value);
140
141	#if DEBUG
142		value = pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, PCI_PCICMD, 2);
143		LOG(("PCICMD = %#04x\n",value));
144	#endif
145
146	/* read memory-io and port-io bars
147	 */
148	config->nambar	= pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, 0x10, 4);
149	config->nabmbar	= pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, 0x14, 4);
150	config->mmbar	= pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, 0x18, 4);
151	config->mbbar	= pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, 0x1C, 4);
152	config->irq		= pci->read_pci_config(pciinfo->bus, pciinfo->device, pciinfo->function, 0x3C, 1);
153
154	config->nambar  &= PCI_address_io_mask;
155	config->nabmbar &= PCI_address_io_mask;
156	config->mmbar   &= PCI_address_memory_32_mask;
157	config->mbbar   &= PCI_address_memory_32_mask;
158
159	if (config->irq == 0 || config->irq == 0xff) {
160		PRINT(("WARNING: no interrupt configured\n"));
161		/* we can continue without an interrupt, as another
162		 * workaround to handle this is also implemented
163		 * force irq to be 0, not 0xff if no irq assigned
164		 */
165		config->irq = 0;
166	}
167
168	/* the ICH4 uses memory mapped IO */
169	if ((config->type & TYPE_ICH4) && ((config->mmbar == 0) || (config->mbbar == 0))) {
170		PRINT(("ERROR: memory mapped IO not configured\n"));
171		result = B_ERROR;
172	}
173	/* all other ICHs use programmed IO */
174	if (!(config->type & TYPE_ICH4) && ((config->nambar == 0) || (config->nabmbar == 0))) {
175		PRINT(("ERROR: IO space not configured\n"));
176		result = B_ERROR;
177	}
178
179	LOG(("nambar  = 0x%08x\n", config->nambar));
180	LOG(("nabmbar = 0x%08x\n", config->nabmbar));
181	LOG(("mmbar   = 0x%08x\n", config->mmbar));
182	LOG(("mbbar   = 0x%08x\n", config->mbbar));
183	LOG(("irq     = %d\n",    config->irq));
184
185probe_done:
186	return result;
187}
188