After this has been brought up many times before, rename src/arch/i386 to
[coreboot.git] / src / northbridge / amd / amdk8 / acpi.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2005 Advanced Micro Devices, Inc.
5  * Copyright (C) 2010 Advanced Micro Devices, Inc.
6  *
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.
11  *
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.
16  *
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
20  */
21
22 /*
23  * Description: Add madt lapic creat dynamically and SRAT related by yhlu
24 */
25
26 #include <console/console.h>
27 #include <string.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 "acpi.h"
35
36 //it seems some functions can be moved arch/x86/boot/acpi.c
37
38 unsigned long acpi_create_madt_lapic_nmis(unsigned long current, u16 flags, u8 lint)
39 {
40         device_t cpu;
41         int cpu_index = 0;
42
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)) {
46                         continue;
47                 }
48                 if (!cpu->enabled) {
49                         continue;
50                 }
51                 current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, cpu_index, flags, lint);
52                 cpu_index++;
53         }
54         return current;
55 }
56
57 unsigned long acpi_create_srat_lapics(unsigned long current)
58 {
59         device_t cpu;
60         int cpu_index = 0;
61
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)) {
65                         continue;
66                 }
67                 if (!cpu->enabled) {
68                         continue;
69                 }
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);
72                 cpu_index++;
73         }
74         return current;
75 }
76
77 static unsigned long resk(uint64_t value)
78 {
79         unsigned long resultk;
80         if (value < (1ULL << 42)) {
81                 resultk = value >> 10;
82         } else {
83                 resultk = 0xffffffff;
84         }
85         return resultk;
86 }
87
88 struct acpi_srat_mem_state {
89         unsigned long current;
90 };
91
92 static void set_srat_mem(void *gp, struct device *dev, struct resource *res)
93 {
94         struct acpi_srat_mem_state *state = gp;
95         unsigned long basek, sizek;
96         basek = resk(res->base);
97         sizek = resk(res->size);
98
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);
101         /*
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
105          */
106         if((basek+sizek)<1024) return;
107
108         if(basek<1024) {
109                 sizek -= 1024 - basek;
110                 basek = 1024;
111         }
112
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);
115 }
116
117 unsigned long acpi_fill_srat(unsigned long current)
118 {
119         struct acpi_srat_mem_state srat_mem_state;
120
121         /* create all subtables for processors */
122         current = acpi_create_srat_lapics(current);
123
124         /* create all subteble for memory range */
125
126         /* 0-640K must be on node 0 */
127         current += acpi_create_srat_mem((acpi_srat_mem_t *)current, 0, 0, 640, 1);//enable
128
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);
133
134         current = srat_mem_state.current;
135         return current;
136 }
137
138 unsigned long acpi_fill_slit(unsigned long current)
139 {
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.... */
143
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 };
153
154 //      u8 outer_node[8];
155
156         u8 *p = (u8 *)current;
157         int nodes = sysconf.nodes;
158         int i,j;
159         memset(p, 0, 8+nodes*nodes);
160 //      memset((u8 *)outer_node, 0, 8);
161         *p = (u8) nodes;
162         p += 8;
163
164 #if 0
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
168         }
169 #endif
170
171         for(i=0;i<nodes;i++) {
172                 for(j=0;j<nodes; j++) {
173                         if(i==j) {
174                                 p[i*nodes+j] = 10;
175                         } else {
176 #if 0
177                                 int k;
178                                 u8 latency_factor = 0;
179                                 int k_start, k_end;
180                                 if(i<j) {
181                                         k_start = i;
182                                         k_end = j;
183                                 } else {
184                                         k_start = j;
185                                         k_end = i;
186                                 }
187                                 for(k=k_start;k<=k_end; k++) {
188                                         if(outer_node[k]) {
189                                                 latency_factor = 1;
190                                                 break;
191                                         }
192                                 }
193                                 p[i*nodes+j] = hops_8[i*nodes+j] * 2 + latency_factor + 10;
194 #else
195                                 p[i*nodes+j] = hops_8[i*nodes+j] * 2 + 10;
196 #endif
197
198                         }
199                 }
200         }
201
202         current += 8+nodes*nodes;
203
204         return current;
205 }
206
207 static int k8acpi_write_HT(void) {
208         int len, lenp, i;
209
210         len = acpigen_write_name("HCLK");
211         lenp = acpigen_write_package(HC_POSSIBLE_NUM);
212
213         for(i=0;i<sysconf.hc_possible_num;i++) {
214                 lenp += acpigen_write_dword(sysconf.pci1234[i]);
215         }
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);
218         }
219
220         acpigen_patch_len(lenp - 1);
221         len += lenp;
222
223         len += acpigen_write_name("HCDN");
224         lenp = acpigen_write_package(HC_POSSIBLE_NUM);
225
226         for(i=0;i<sysconf.hc_possible_num;i++) {
227                 lenp += acpigen_write_dword(sysconf.hcdn[i]);
228         }
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);
231         }
232         acpigen_patch_len(lenp - 1);
233         len += lenp;
234
235         return len;
236 }
237
238 static int k8acpi_write_pci_data(int dlen, const char *name, int offset) {
239         device_t dev;
240         uint32_t dword;
241         int len, lenp, i;
242
243         dev = dev_find_slot(0, PCI_DEVFN(0x18, 1));
244
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);
250         }
251         // minus the opcode
252         acpigen_patch_len(lenp - 1);
253         return len + lenp;
254 }
255
256 int k8acpi_write_vars(void)
257 {
258         int lens;
259         msr_t msr;
260         char pscope[] = "\\_SB.PCI0";
261
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);
273         /*
274          * Since XP only implements parts of ACPI 2.0, we can't use a qword
275          * here.
276          * See http://www.acpi.info/presentations/S01USMOBS169_OS%2520new.ppt
277          * slide 22ff.
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.
280          */
281         lens += acpigen_write_name_dword("TOM2", (msr.hi << 12) | msr.lo >> 20);
282
283         lens += k8acpi_write_HT();
284         //minus opcode
285         acpigen_patch_len(lens - 1);
286         return lens;
287 }
288
289 void update_ssdtx(void *ssdtx, int i)
290 {
291         u8 *PCI;
292         u8 *HCIN;
293         u8 *UID;
294
295         PCI = ssdtx + 0x32;
296         HCIN = ssdtx + 0x39;
297         UID = ssdtx + 0x40;
298
299         if (i < 7) {
300                 *PCI = (u8) ('4' + i - 1);
301         } else {
302                 *PCI = (u8) ('A' + i - 1 - 6);
303         }
304         *HCIN = (u8) i;
305         *UID = (u8) (i + 3);
306
307         /* FIXME: need to update the GSI id in the ssdtx too */
308
309 }
310