summaryrefslogtreecommitdiff
path: root/src/mainboard/intel/eagleheights/mptable.c
blob: ae05bb9e8fca5f09db4eaf48ba1d7f033c12f155 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2007-2008 coresystems GmbH
 * Copyright (C) 2009 Thomas Jourdan <thomas.jourdan@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of
 * the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <console/console.h>
#include <arch/io.h>
#include <arch/ioapic.h>
#include <arch/smp/mpspec.h>
#include <device/pci.h>
#include <string.h>
#include <stdint.h>

// Generate MP-table IRQ numbers for PCI devices.
#define IO_APIC0 2

#define INT_A	0
#define INT_B	1
#define INT_C	2
#define INT_D	3
#define PCI_IRQ(dev, intLine)	(((dev)<<2) | intLine)

#define PIRQ_A 16
#define PIRQ_B 17
#define PIRQ_C 18
#define PIRQ_D 19
#define PIRQ_E 20
#define PIRQ_F 21
#define PIRQ_G 22
#define PIRQ_H 23

// RCBA
#define RCBA 0xF0

#define RCBA_D31IP 0x3100
#define RCBA_D30IP 0x3104
#define RCBA_D29IP 0x3108
#define RCBA_D28IP 0x310C
#define RCBA_D31IR 0x3140
#define RCBA_D30IR 0x3142
#define RCBA_D29IR 0x3144
#define RCBA_D28IR 0x3146

static void *smp_write_config_table(void *v)
{
        struct mp_config_table *mc;
	unsigned char bus_chipset, bus_pci;
	unsigned char bus_pcie_a, bus_pcie_a1, bus_pcie_b;
	int bus_isa, i;
	uint32_t pin, route;
	device_t dev;
	struct resource *res;
	u8 *rcba;

	dev = dev_find_slot(0, PCI_DEVFN(0x1F,0));
	res = find_resource(dev, RCBA);
	if (!res) {
	  return NULL;
	}
	rcba = res2mmio(res, 0, 0);

        mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);

	mptable_init(mc, LOCAL_APIC_ADDR);

        smp_write_processors(mc);

	/* Get bus numbers */
	bus_chipset = 0;

	/* PCI */
	dev = dev_find_slot(0, PCI_DEVFN(0x1E,0));
	if (dev) {
	  bus_pci = pci_read_config8(dev, PCI_SECONDARY_BUS);
	} else {
	  printk(BIOS_DEBUG, "ERROR - could not find PCI 0:1e.0, using defaults\n");
	  bus_pci = 6;
	}

	dev = dev_find_slot(0, PCI_DEVFN(2,0));
	if(dev) {
	  bus_pcie_a = pci_read_config8(dev, PCI_SECONDARY_BUS);
	} else {
	  printk(BIOS_DEBUG, "ERROR - could not find PCIe Port A  0:2.0, using defaults\n");
	  bus_pcie_a = 1;
	}

	dev = dev_find_slot(0, PCI_DEVFN(3,0));
	if(dev) {
	  bus_pcie_a1 = pci_read_config8(dev, PCI_SECONDARY_BUS);
	} else {
	  printk(BIOS_DEBUG, "ERROR - could not find PCIe Port B 0:3.0, using defaults\n");
	  bus_pcie_a1 = 2;
	}

	dev = dev_find_slot(0, PCI_DEVFN(0x1C,0));
	if(dev) {
	  bus_pcie_b = pci_read_config8(dev, PCI_SECONDARY_BUS);
	} else {
	  printk(BIOS_DEBUG, "ERROR - could not find PCIe Port B 0:3.0, using defaults\n");
	  bus_pcie_b = 3;
	}

	mptable_write_buses(mc, NULL, &bus_isa);

	/*I/O APICs: APIC ID Version State Address*/
	smp_write_ioapic(mc, 2, 0x20, VIO_APIC_VADDR);

	mptable_add_isa_interrupts(mc, bus_isa, IO_APIC0, 0);

	/*Local Ints:	Type	Polarity    Trigger	Bus ID	 IRQ	APIC ID	PIN#*/
	mptable_lintsrc(mc, bus_isa);

	/* Internal PCI device for i3100 */

	/* EDMA
	 */
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_chipset, PCI_IRQ(1, INT_A), IO_APIC0, PIRQ_A);

	/* PCIe Port A
	 */
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_chipset, PCI_IRQ(2, INT_A), IO_APIC0, PIRQ_A);

	/* PCIe Port A1
	 */
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_chipset, PCI_IRQ(3, INT_A), IO_APIC0, PIRQ_A);

	/* PCIe Port B
	 */
	for(i = 0; i < 4; i++) {
	  pin = (read32(rcba + RCBA_D28IP) >> (i * 4)) & 0x0F;
	  if(pin > 0) {
	    pin -= 1;
	    route = PIRQ_A + ((read16(rcba + RCBA_D28IR) >> (pin * 4)) & 0x07);
	    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_chipset, PCI_IRQ(28, pin), IO_APIC0, route);
	  }
	}

	/* USB 1.1 : device 29, function 0, 1
	 */
	for(i = 0; i < 2; i++) {
	  pin = (read32(rcba + RCBA_D29IP) >> (i * 4)) & 0x0F;
	  if(pin > 0) {
	    pin -= 1;
	    route = PIRQ_A + ((read16(rcba + RCBA_D29IR) >> (pin * 4)) & 0x07);
	    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_chipset, PCI_IRQ(29, pin), IO_APIC0, route);
	  }
	}

	/* USB 2.0 : device 29, function 7
	*/
	pin = (read32(rcba + RCBA_D29IP) >> (7 * 4)) & 0x0F;
	if(pin > 0) {
	  pin -= 1;
	  route = PIRQ_A + ((read16(rcba + RCBA_D29IR) >> (pin * 4)) & 0x07);
	  smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_chipset, PCI_IRQ(29, pin), IO_APIC0, route);
	}

	/* SATA : device 31 function 2
	   SMBus : device 31 function 3
	   Performance counters : device 31 function 4
	 */
	for(i = 2; i < 5; i++) {
	  pin = (read32(rcba + RCBA_D31IP) >> (i * 4)) & 0x0F;
	  if(pin > 0) {
	    pin -= 1;
	    route = PIRQ_A + ((read16(rcba + RCBA_D31IR) >> (pin * 4)) & 0x07);
	    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_chipset, PCI_IRQ(31, pin), IO_APIC0, route);
	  }
	}

	/* SLOTS */

	/* PCIe 4x slot A
	 */
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_a, PCI_IRQ(0, INT_A), IO_APIC0, PIRQ_A);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_a, PCI_IRQ(0, INT_B), IO_APIC0, PIRQ_B);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_a, PCI_IRQ(0, INT_C), IO_APIC0, PIRQ_C);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_a, PCI_IRQ(0, INT_D), IO_APIC0, PIRQ_D);

	/* PCIe 4x slot A1
	 */
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_a1, PCI_IRQ(0, INT_A), IO_APIC0, PIRQ_A);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_a1, PCI_IRQ(0, INT_B), IO_APIC0, PIRQ_B);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_a1, PCI_IRQ(0, INT_C), IO_APIC0, PIRQ_C);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_a1, PCI_IRQ(0, INT_D), IO_APIC0, PIRQ_D);

	/* PCIe 4x slot B
	 */
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_b, PCI_IRQ(0, INT_A), IO_APIC0, PIRQ_A);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_b, PCI_IRQ(0, INT_B), IO_APIC0, PIRQ_B);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_b, PCI_IRQ(0, INT_C), IO_APIC0, PIRQ_C);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pcie_b, PCI_IRQ(0, INT_D), IO_APIC0, PIRQ_D);

	/* PCI slot
	 */
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, PCI_IRQ(0, INT_A), IO_APIC0, PIRQ_A);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, PCI_IRQ(0, INT_B), IO_APIC0, PIRQ_B);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, PCI_IRQ(0, INT_C), IO_APIC0, PIRQ_C);
	smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, PCI_IRQ(0, INT_D), IO_APIC0, PIRQ_D);

	/* There is no extension information... */

	/* Compute the checksums */
	return mptable_finalize(mc);
}

unsigned long write_smp_table(unsigned long addr)
{
	void *v;
	v = smp_write_floating_table(addr, 0);
	return (unsigned long)smp_write_config_table(v);
}