2 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
4 * Adapted from coreboot src/arch/x86/boot/mpspec.c
6 * SPDX-License-Identifier: GPL-2.0+
16 #include <asm/ioapic.h>
17 #include <asm/lapic.h>
18 #include <asm/mpspec.h>
19 #include <asm/tables.h>
20 #include <dm/uclass-internal.h>
22 DECLARE_GLOBAL_DATA_PTR
;
24 static bool isa_irq_occupied
[16];
26 struct mp_config_table
*mp_write_floating_table(struct mp_floating_table
*mf
)
30 memcpy(mf
->mpf_signature
, MPF_SIGNATURE
, 4);
31 mf
->mpf_physptr
= (u32
)mf
+ sizeof(struct mp_floating_table
);
33 mf
->mpf_spec
= MPSPEC_V14
;
35 /* We don't use the default configuration table */
37 /* Indicate that virtual wire mode is always implemented */
42 mf
->mpf_checksum
= table_compute_checksum(mf
, mf
->mpf_length
* 16);
44 mc
= (u32
)mf
+ sizeof(struct mp_floating_table
);
45 return (struct mp_config_table
*)mc
;
48 void mp_config_table_init(struct mp_config_table
*mc
)
50 memcpy(mc
->mpc_signature
, MPC_SIGNATURE
, 4);
51 mc
->mpc_length
= sizeof(struct mp_config_table
);
52 mc
->mpc_spec
= MPSPEC_V14
;
56 mc
->mpc_entry_count
= 0;
57 mc
->mpc_lapic
= LAPIC_DEFAULT_BASE
;
62 /* The oem/product id fields are exactly 8/12 bytes long */
63 table_fill_string(mc
->mpc_oem
, CONFIG_SYS_VENDOR
, 8, ' ');
64 table_fill_string(mc
->mpc_product
, CONFIG_SYS_BOARD
, 12, ' ');
67 void mp_write_processor(struct mp_config_table
*mc
)
69 struct mpc_config_processor
*mpc
;
71 u8 boot_apicid
, apicver
;
72 u32 cpusignature
, cpufeature
;
73 struct cpuid_result result
;
75 boot_apicid
= lapicid();
76 apicver
= lapic_read(LAPIC_LVR
) & 0xff;
78 cpusignature
= result
.eax
;
79 cpufeature
= result
.edx
;
81 for (uclass_find_first_device(UCLASS_CPU
, &dev
);
83 uclass_find_next_device(&dev
)) {
84 struct cpu_platdata
*plat
= dev_get_parent_platdata(dev
);
85 u8 cpuflag
= MPC_CPU_EN
;
87 if (!device_active(dev
))
90 mpc
= (struct mpc_config_processor
*)mp_next_mpc_entry(mc
);
91 mpc
->mpc_type
= MP_PROCESSOR
;
92 mpc
->mpc_apicid
= plat
->cpu_id
;
93 mpc
->mpc_apicver
= apicver
;
94 if (boot_apicid
== plat
->cpu_id
)
95 cpuflag
|= MPC_CPU_BP
;
96 mpc
->mpc_cpuflag
= cpuflag
;
97 mpc
->mpc_cpusignature
= cpusignature
;
98 mpc
->mpc_cpufeature
= cpufeature
;
99 mpc
->mpc_reserved
[0] = 0;
100 mpc
->mpc_reserved
[1] = 0;
101 mp_add_mpc_entry(mc
, sizeof(*mpc
));
105 void mp_write_bus(struct mp_config_table
*mc
, int id
, const char *bustype
)
107 struct mpc_config_bus
*mpc
;
109 mpc
= (struct mpc_config_bus
*)mp_next_mpc_entry(mc
);
110 mpc
->mpc_type
= MP_BUS
;
112 memcpy(mpc
->mpc_bustype
, bustype
, 6);
113 mp_add_mpc_entry(mc
, sizeof(*mpc
));
116 void mp_write_ioapic(struct mp_config_table
*mc
, int id
, int ver
, u32 apicaddr
)
118 struct mpc_config_ioapic
*mpc
;
120 mpc
= (struct mpc_config_ioapic
*)mp_next_mpc_entry(mc
);
121 mpc
->mpc_type
= MP_IOAPIC
;
122 mpc
->mpc_apicid
= id
;
123 mpc
->mpc_apicver
= ver
;
124 mpc
->mpc_flags
= MPC_APIC_USABLE
;
125 mpc
->mpc_apicaddr
= apicaddr
;
126 mp_add_mpc_entry(mc
, sizeof(*mpc
));
129 void mp_write_intsrc(struct mp_config_table
*mc
, int irqtype
, int irqflag
,
130 int srcbus
, int srcbusirq
, int dstapic
, int dstirq
)
132 struct mpc_config_intsrc
*mpc
;
134 mpc
= (struct mpc_config_intsrc
*)mp_next_mpc_entry(mc
);
135 mpc
->mpc_type
= MP_INTSRC
;
136 mpc
->mpc_irqtype
= irqtype
;
137 mpc
->mpc_irqflag
= irqflag
;
138 mpc
->mpc_srcbus
= srcbus
;
139 mpc
->mpc_srcbusirq
= srcbusirq
;
140 mpc
->mpc_dstapic
= dstapic
;
141 mpc
->mpc_dstirq
= dstirq
;
142 mp_add_mpc_entry(mc
, sizeof(*mpc
));
145 void mp_write_pci_intsrc(struct mp_config_table
*mc
, int irqtype
,
146 int srcbus
, int dev
, int pin
, int dstapic
, int dstirq
)
148 u8 srcbusirq
= (dev
<< 2) | (pin
- 1);
150 mp_write_intsrc(mc
, irqtype
, MP_IRQ_TRIGGER_LEVEL
| MP_IRQ_POLARITY_LOW
,
151 srcbus
, srcbusirq
, dstapic
, dstirq
);
154 void mp_write_lintsrc(struct mp_config_table
*mc
, int irqtype
, int irqflag
,
155 int srcbus
, int srcbusirq
, int destapic
, int destlint
)
157 struct mpc_config_lintsrc
*mpc
;
159 mpc
= (struct mpc_config_lintsrc
*)mp_next_mpc_entry(mc
);
160 mpc
->mpc_type
= MP_LINTSRC
;
161 mpc
->mpc_irqtype
= irqtype
;
162 mpc
->mpc_irqflag
= irqflag
;
163 mpc
->mpc_srcbusid
= srcbus
;
164 mpc
->mpc_srcbusirq
= srcbusirq
;
165 mpc
->mpc_destapic
= destapic
;
166 mpc
->mpc_destlint
= destlint
;
167 mp_add_mpc_entry(mc
, sizeof(*mpc
));
170 void mp_write_address_space(struct mp_config_table
*mc
,
171 int busid
, int addr_type
,
172 u32 addr_base_low
, u32 addr_base_high
,
173 u32 addr_length_low
, u32 addr_length_high
)
175 struct mp_ext_system_address_space
*mpe
;
177 mpe
= (struct mp_ext_system_address_space
*)mp_next_mpe_entry(mc
);
178 mpe
->mpe_type
= MPE_SYSTEM_ADDRESS_SPACE
;
179 mpe
->mpe_length
= sizeof(*mpe
);
180 mpe
->mpe_busid
= busid
;
181 mpe
->mpe_addr_type
= addr_type
;
182 mpe
->mpe_addr_base_low
= addr_base_low
;
183 mpe
->mpe_addr_base_high
= addr_base_high
;
184 mpe
->mpe_addr_length_low
= addr_length_low
;
185 mpe
->mpe_addr_length_high
= addr_length_high
;
186 mp_add_mpe_entry(mc
, (struct mp_ext_config
*)mpe
);
189 void mp_write_bus_hierarchy(struct mp_config_table
*mc
,
190 int busid
, int bus_info
, int parent_busid
)
192 struct mp_ext_bus_hierarchy
*mpe
;
194 mpe
= (struct mp_ext_bus_hierarchy
*)mp_next_mpe_entry(mc
);
195 mpe
->mpe_type
= MPE_BUS_HIERARCHY
;
196 mpe
->mpe_length
= sizeof(*mpe
);
197 mpe
->mpe_busid
= busid
;
198 mpe
->mpe_bus_info
= bus_info
;
199 mpe
->mpe_parent_busid
= parent_busid
;
200 mpe
->reserved
[0] = 0;
201 mpe
->reserved
[1] = 0;
202 mpe
->reserved
[2] = 0;
203 mp_add_mpe_entry(mc
, (struct mp_ext_config
*)mpe
);
206 void mp_write_compat_address_space(struct mp_config_table
*mc
, int busid
,
207 int addr_modifier
, u32 range_list
)
209 struct mp_ext_compat_address_space
*mpe
;
211 mpe
= (struct mp_ext_compat_address_space
*)mp_next_mpe_entry(mc
);
212 mpe
->mpe_type
= MPE_COMPAT_ADDRESS_SPACE
;
213 mpe
->mpe_length
= sizeof(*mpe
);
214 mpe
->mpe_busid
= busid
;
215 mpe
->mpe_addr_modifier
= addr_modifier
;
216 mpe
->mpe_range_list
= range_list
;
217 mp_add_mpe_entry(mc
, (struct mp_ext_config
*)mpe
);
220 u32
mptable_finalize(struct mp_config_table
*mc
)
224 mc
->mpe_checksum
= table_compute_checksum((void *)mp_next_mpc_entry(mc
),
226 mc
->mpc_checksum
= table_compute_checksum(mc
, mc
->mpc_length
);
227 end
= mp_next_mpe_entry(mc
);
229 debug("Write the MP table at: %x - %x\n", (u32
)mc
, end
);
234 static void mptable_add_isa_interrupts(struct mp_config_table
*mc
, int bus_isa
,
235 int apicid
, int external_int2
)
239 mp_write_intsrc(mc
, external_int2
? MP_INT
: MP_EXTINT
,
240 MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
,
241 bus_isa
, 0, apicid
, 0);
242 mp_write_intsrc(mc
, MP_INT
, MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
,
243 bus_isa
, 1, apicid
, 1);
244 mp_write_intsrc(mc
, external_int2
? MP_EXTINT
: MP_INT
,
245 MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
,
246 bus_isa
, 0, apicid
, 2);
248 for (i
= 3; i
< 16; i
++) {
250 * Do not write ISA interrupt entry if it is already occupied
251 * by the platform devices.
253 if (isa_irq_occupied
[i
])
256 mp_write_intsrc(mc
, MP_INT
,
257 MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
,
258 bus_isa
, i
, apicid
, i
);
263 * Check duplicated I/O interrupt assignment table entry, to make sure
264 * there is only one entry with the given bus, device and interrupt pin.
266 static bool check_dup_entry(struct mpc_config_intsrc
*intsrc_base
,
267 int entry_num
, int bus
, int device
, int pin
)
269 struct mpc_config_intsrc
*intsrc
= intsrc_base
;
272 for (i
= 0; i
< entry_num
; i
++) {
273 if (intsrc
->mpc_srcbus
== bus
&&
274 intsrc
->mpc_srcbusirq
== ((device
<< 2) | (pin
- 1)))
279 return (i
== entry_num
) ? false : true;
282 /* TODO: move this to driver model */
283 __weak
int mp_determine_pci_dstirq(int bus
, int dev
, int func
, int pirq
)
285 /* PIRQ[A-H] are connected to I/O APIC INTPIN#16-23 */
289 static int mptable_add_intsrc(struct mp_config_table
*mc
,
290 int bus_isa
, int apicid
)
292 struct mpc_config_intsrc
*intsrc_base
;
293 int intsrc_entries
= 0;
294 const void *blob
= gd
->fdt_blob
;
300 ret
= uclass_first_device_err(UCLASS_IRQ
, &dev
);
301 if (ret
&& ret
!= -ENODEV
) {
302 debug("%s: Cannot find irq router node\n", __func__
);
306 /* Get I/O interrupt information from device tree */
307 cell
= fdt_getprop(blob
, dev
->of_offset
, "intel,pirq-routing", &len
);
311 if ((len
% sizeof(struct pirq_routing
)) == 0)
312 count
= len
/ sizeof(struct pirq_routing
);
316 intsrc_base
= (struct mpc_config_intsrc
*)mp_next_mpc_entry(mc
);
318 for (i
= 0; i
< count
; i
++) {
319 struct pirq_routing pr
;
323 pr
.bdf
= fdt_addr_to_cpu(cell
[0]);
324 pr
.pin
= fdt_addr_to_cpu(cell
[1]);
325 pr
.pirq
= fdt_addr_to_cpu(cell
[2]);
326 bus
= PCI_BUS(pr
.bdf
);
327 dev
= PCI_DEV(pr
.bdf
);
328 func
= PCI_FUNC(pr
.bdf
);
330 if (check_dup_entry(intsrc_base
, intsrc_entries
,
332 debug("found entry for bus %d device %d INT%c, skipping\n",
333 bus
, dev
, 'A' + pr
.pin
- 1);
334 cell
+= sizeof(struct pirq_routing
) / sizeof(u32
);
338 dstirq
= mp_determine_pci_dstirq(bus
, dev
, func
, pr
.pirq
);
340 * For PIRQ which is connected to I/O APIC interrupt pin#0-15,
341 * mark it as occupied so that we can skip it later.
344 isa_irq_occupied
[dstirq
] = true;
345 mp_write_pci_intsrc(mc
, MP_INT
, bus
, dev
, pr
.pin
,
348 cell
+= sizeof(struct pirq_routing
) / sizeof(u32
);
351 /* Legacy Interrupts */
352 debug("Writing ISA IRQs\n");
353 mptable_add_isa_interrupts(mc
, bus_isa
, apicid
, 0);
358 static void mptable_add_lintsrc(struct mp_config_table
*mc
, int bus_isa
)
360 mp_write_lintsrc(mc
, MP_EXTINT
,
361 MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
,
362 bus_isa
, 0, MP_APIC_ALL
, 0);
363 mp_write_lintsrc(mc
, MP_NMI
,
364 MP_IRQ_TRIGGER_EDGE
| MP_IRQ_POLARITY_HIGH
,
365 bus_isa
, 0, MP_APIC_ALL
, 1);
368 u32
write_mp_table(u32 addr
)
370 struct mp_config_table
*mc
;
371 int ioapic_id
, ioapic_ver
;
376 /* 16 byte align the table address */
377 addr
= ALIGN(addr
, 16);
379 /* Write floating table */
380 mc
= mp_write_floating_table((struct mp_floating_table
*)addr
);
382 /* Write configuration table header */
383 mp_config_table_init(mc
);
385 /* Write processor entry */
386 mp_write_processor(mc
);
388 /* Write bus entry */
389 mp_write_bus(mc
, bus_isa
, BUSTYPE_ISA
);
391 /* Write I/O APIC entry */
392 ioapic_id
= io_apic_read(IO_APIC_ID
) >> 24;
393 ioapic_ver
= io_apic_read(IO_APIC_VER
) & 0xff;
394 mp_write_ioapic(mc
, ioapic_id
, ioapic_ver
, IO_APIC_ADDR
);
396 /* Write I/O interrupt assignment entry */
397 ret
= mptable_add_intsrc(mc
, bus_isa
, ioapic_id
);
399 debug("Failed to write I/O interrupt assignment table\n");
401 /* Write local interrupt assignment entry */
402 mptable_add_lintsrc(mc
, bus_isa
);
404 /* Finalize the MP table */
405 end
= mptable_finalize(mc
);