2 * This file is part of the coreboot project.
4 * Copyright (C) 2005 Advanced Micro Devices, Inc.
5 * Copyright (C) 2010 Advanced Micro Devices, Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 * Description: Add madt lapic creat dynamically and SRAT related by yhlu
26 #include <console/console.h>
28 #include <arch/acpi.h>
29 #include <arch/acpigen.h>
30 #include <device/pci.h>
31 #include <cpu/x86/msr.h>
32 #include <cpu/amd/mtrr.h>
33 #include <cpu/amd/amdk8_sysconf.h>
34 #include "amdk8_acpi.h"
36 //it seems some functions can be moved arch/i386/boot/acpi.c
38 unsigned long acpi_create_madt_lapic_nmis(unsigned long current, u16 flags, u8 lint)
43 for(cpu = all_devices; cpu; cpu = cpu->next) {
44 if ((cpu->path.type != DEVICE_PATH_APIC) ||
45 (cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER)) {
51 current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, cpu_index, flags, lint);
57 unsigned long acpi_create_srat_lapics(unsigned long current)
62 for(cpu = all_devices; cpu; cpu = cpu->next) {
63 if ((cpu->path.type != DEVICE_PATH_APIC) ||
64 (cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER)) {
70 printk(BIOS_DEBUG, "SRAT: lapic cpu_index=%02x, node_id=%02x, apic_id=%02x\n", cpu_index, cpu->path.apic.node_id, cpu->path.apic.apic_id);
71 current += acpi_create_srat_lapic((acpi_srat_lapic_t *)current, cpu->path.apic.node_id, cpu->path.apic.apic_id);
77 static unsigned long resk(uint64_t value)
79 unsigned long resultk;
80 if (value < (1ULL << 42)) {
81 resultk = value >> 10;
88 struct acpi_srat_mem_state {
89 unsigned long current;
92 static void set_srat_mem(void *gp, struct device *dev, struct resource *res)
94 struct acpi_srat_mem_state *state = gp;
95 unsigned long basek, sizek;
96 basek = resk(res->base);
97 sizek = resk(res->size);
99 printk(BIOS_DEBUG, "set_srat_mem: dev %s, res->index=%04lx startk=%08lx, sizek=%08lx\n",
100 dev_path(dev), res->index, basek, sizek);
102 * 0-640K must be on node 0
103 * next range is from 1M---
104 * So will cut off before 1M in the mem range
106 if((basek+sizek)<1024) return;
109 sizek -= 1024 - basek;
113 // need to figure out NV
114 state->current += acpi_create_srat_mem((acpi_srat_mem_t *)state->current, (res->index & 0xf), basek, sizek, 1);
117 unsigned long acpi_fill_srat(unsigned long current)
119 struct acpi_srat_mem_state srat_mem_state;
121 /* create all subtables for processors */
122 current = acpi_create_srat_lapics(current);
124 /* create all subteble for memory range */
126 /* 0-640K must be on node 0 */
127 current += acpi_create_srat_mem((acpi_srat_mem_t *)current, 0, 0, 640, 1);//enable
129 srat_mem_state.current = current;
130 search_global_resources(
131 IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE,
132 set_srat_mem, &srat_mem_state);
134 current = srat_mem_state.current;
138 unsigned long acpi_fill_slit(unsigned long current)
140 /* need to find out the node num at first */
141 /* fill the first 8 byte with that num */
142 /* fill the next num*num byte with distance, local is 10, 1 hop mean 20, and 2 hop with 30.... */
144 /* because We has assume that we know the topology of the HT connection, So we can have set if we know the node_num */
145 static u8 hops_8[] = { 0, 1, 1, 2, 2, 3, 3, 4,
146 1, 0, 2, 1, 3, 2, 4, 3,
147 1, 2, 0, 1, 1, 2, 2, 3,
148 2, 1, 1, 0, 2, 1, 3, 2,
149 2, 3, 1, 2, 0, 1, 1, 2,
150 3, 2, 2, 1, 1, 0, 2, 1,
151 3, 4, 2, 3, 1, 2, 0, 1,
152 4, 4, 3, 2, 2, 1, 1, 0 };
156 u8 *p = (u8 *)current;
157 int nodes = sysconf.nodes;
159 memset(p, 0, 8+nodes*nodes);
160 // memset((u8 *)outer_node, 0, 8);
165 for(i=0;i<sysconf.hc_possible_num;i++) {
166 if((sysconf.pci1234[i]&1) !=1 ) continue;
167 outer_node[(sysconf.pci1234[i] >> 4) & 0xf] = 1; // mark the outer node
171 for(i=0;i<nodes;i++) {
172 for(j=0;j<nodes; j++) {
178 u8 latency_factor = 0;
187 for(k=k_start;k<=k_end; k++) {
193 p[i*nodes+j] = hops_8[i*nodes+j] * 2 + latency_factor + 10;
195 p[i*nodes+j] = hops_8[i*nodes+j] * 2 + 10;
202 current += 8+nodes*nodes;
207 static int k8acpi_write_HT(void) {
210 len = acpigen_write_name("HCLK");
211 lenp = acpigen_write_package(HC_POSSIBLE_NUM);
213 for(i=0;i<sysconf.hc_possible_num;i++) {
214 lenp += acpigen_write_dword(sysconf.pci1234[i]);
216 for(i=sysconf.hc_possible_num; i<HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8
217 lenp += acpigen_write_dword(0x0);
220 acpigen_patch_len(lenp - 1);
223 len += acpigen_write_name("HCDN");
224 lenp = acpigen_write_package(HC_POSSIBLE_NUM);
226 for(i=0;i<sysconf.hc_possible_num;i++) {
227 lenp += acpigen_write_dword(sysconf.hcdn[i]);
229 for(i=sysconf.hc_possible_num; i<HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8
230 lenp += acpigen_write_dword(0x20202020);
232 acpigen_patch_len(lenp - 1);
238 static int k8acpi_write_pci_data(int dlen, const char *name, int offset) {
243 dev = dev_find_slot(0, PCI_DEVFN(0x18, 1));
245 len = acpigen_write_name(name);
246 lenp = acpigen_write_package(dlen);
247 for(i=0; i<dlen; i++) {
248 dword = pci_read_config32(dev, offset+i*4);
249 lenp += acpigen_write_dword(dword);
252 acpigen_patch_len(lenp - 1);
256 int k8acpi_write_vars(void)
260 char pscope[] = "\\_SB.PCI0";
262 lens = acpigen_write_scope(pscope);
263 lens += k8acpi_write_pci_data(4, "BUSN", 0xe0);
264 lens += k8acpi_write_pci_data(8, "PCIO", 0xc0);
265 lens += k8acpi_write_pci_data(16, "MMIO", 0x80);
266 lens += acpigen_write_name_byte("SBLK", sysconf.sblk);
267 lens += acpigen_write_name_byte("CBST",
268 ((sysconf.pci1234[0] >> 12) & 0xff) ? 0xf : 0x0);
269 lens += acpigen_write_name_dword("SBDN", sysconf.sbdn);
270 msr = rdmsr(TOP_MEM);
271 lens += acpigen_write_name_dword("TOM1", msr.lo);
272 msr = rdmsr(TOP_MEM2);
274 * Since XP only implements parts of ACPI 2.0, we can't use a qword
276 * See http://www.acpi.info/presentations/S01USMOBS169_OS%2520new.ppt
278 * Shift value right by 20 bit to make it fit into 32bit,
279 * giving us 1MB granularity and a limit of almost 4Exabyte of memory.
281 lens += acpigen_write_name_dword("TOM2", (msr.hi << 12) | msr.lo >> 20);
283 lens += k8acpi_write_HT();
285 acpigen_patch_len(lens - 1);
289 void update_ssdtx(void *ssdtx, int i)
300 *PCI = (u8) ('4' + i - 1);
302 *PCI = (u8) ('A' + i - 1 - 6);
307 /* FIXME: need to update the GSI id in the ssdtx too */