epia-m support
[coreboot.git] / src / arch / i386 / boot / acpi.c
1 /*
2  * LinuxBIOS ACPI Table support
3  * written by Stefan Reinauer <stepan@openbios.org>
4  * (C) 2004 SUSE LINUX AG
5  */
6 /* ACPI FADT, FACS, and DSDT table support added by 
7  * Nick Barker <nick.barker9@btinternet.com>, and those portions
8  * (C) Copyright 2004 Nick Barker
9  */
10
11 #include <console/console.h>
12 #include <string.h>
13 #include <arch/acpi.h>
14
15 #define RSDP_SIG              "RSD PTR "  /* RSDT Pointer signature */
16 #define RSDP_NAME             "RSDP"
17
18 #define RSDT_NAME             "RSDT"
19 #define HPET_NAME             "HPET"
20 #define MADT_NAME             "APIC"
21
22 #define RSDT_TABLE            "RSDT    "
23 #define HPET_TABLE            "AMD64   "
24 #define MADT_TABLE            "MADT    "
25
26 #define OEM_ID                "LXBIOS"
27 #define ASLC                  "NONE"
28
29
30 // FIX ME - define needs declaring / setting in Config files
31 #define HAVE_ACPI_FADT 
32
33 #ifdef HAVE_ACPI_FADT
34 extern unsigned char AmlCode[];
35 #endif
36
37 u8 acpi_checksum(u8 *table, u32 length)
38 {
39         u8 ret=0;
40         while (length--) {
41                 ret += *table;
42                 table++;
43         }
44         return -ret;
45 }
46
47 /*
48  * add an acpi table to rsdt structure, and recalculate checksum
49  */
50
51 static void acpi_add_table(acpi_rsdt_t *rsdt, void *table)
52 {
53         int i;
54
55         for (i=0; i<8; i++) {
56                 if(rsdt->entry[i]==0) {
57                         rsdt->entry[i]=(u32)table;
58                         /* fix length to stop kernel winging about invalid entries */
59                         rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i+1));
60                         /* fix checksum */
61                         /* hope this won't get optimized away */
62                         rsdt->header.checksum=0;
63                         rsdt->header.checksum=acpi_checksum((u8 *)rsdt,
64                                         rsdt->header.length);
65                         
66                         printk_debug("ACPI: added table %d/8 Length now %d\n",i+1,rsdt->header.length);
67                         return;
68                 }
69         }
70
71         printk_warning("ACPI: could not ACPI table. failed.\n");
72 }
73
74
75 static int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
76 {
77         lapic->type=0;
78         lapic->length=sizeof(acpi_madt_lapic_t);
79         lapic->flags=1;
80         
81         lapic->processor_id=cpu;
82         lapic->apic_id=apic;
83         
84         return(lapic->length);
85 }
86
87 static int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr) 
88 {
89         ioapic->type=1;
90         ioapic->length=sizeof(acpi_madt_ioapic_t);
91         ioapic->reserved=0x00;
92         ioapic->gsi_base=0x00000000;
93         
94         ioapic->ioapic_id=id;
95         ioapic->ioapic_addr=addr;
96         
97         return(ioapic->length);
98 }
99
100 static int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
101                 u8 bus, u8 source, u32 gsirq, u16 flags)
102 {
103         irqoverride->type=2;
104         irqoverride->length=sizeof(acpi_madt_irqoverride_t);
105         irqoverride->flags=0x0001;
106         
107         irqoverride->bus=bus;
108         irqoverride->source=source;
109         irqoverride->gsirq=gsirq;
110         irqoverride->flags=flags;
111         
112         return(irqoverride->length);
113 }
114
115 static int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
116                 u16 flags, u8 lint)
117 {
118         lapic_nmi->type=4;
119         lapic_nmi->length=sizeof(acpi_madt_lapic_nmi_t);
120         
121         lapic_nmi->flags=flags;
122         lapic_nmi->processor_id=cpu;
123         lapic_nmi->lint=lint;
124         
125         return(lapic_nmi->length);
126 }
127
128 static void acpi_create_madt(acpi_madt_t *madt)
129 {
130 #define LOCAL_APIC_ADDR 0xfee00000ULL
131 #define IO_APIC_ADDR    0xfec00000UL
132         acpi_header_t *header=&(madt->header);
133         unsigned long current=(unsigned long)madt+sizeof(acpi_madt_t);
134         
135         memset((void *)madt, 0, sizeof(acpi_madt_t));
136         
137         /* fill out header fields */
138         memcpy(header->signature, MADT_NAME, 4);
139         memcpy(header->oem_id, OEM_ID, 6);
140         memcpy(header->oem_table_id, MADT_TABLE, 8);
141         memcpy(header->asl_compiler_id, ASLC, 4);
142         
143         header->length = sizeof(acpi_madt_t);
144         header->revision = 1;
145
146         madt->lapic_addr= LOCAL_APIC_ADDR;
147         madt->flags     = 0x1; /* PCAT_COMPAT */
148         
149         /* create all subtables for 1p */
150         current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current, 0, 0);
151         current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *)current, 2,
152                         IO_APIC_ADDR);
153         current += acpi_create_madt_irqoverride( (acpi_madt_irqoverride_t *)
154                         current, 0, 0, 2, 1 /* active high */);
155         current += acpi_create_madt_irqoverride( (acpi_madt_irqoverride_t *)
156                         current, 0, 9, 9, 0xf /* active low, level triggered */);
157         current += acpi_create_madt_lapic_nmi( (acpi_madt_lapic_nmi_t *)
158                         current, 0, 5, 1);
159
160         /* recalculate length */
161         header->length= current - (unsigned long)madt;
162         
163         header->checksum        = acpi_checksum((void *)madt, header->length);
164 }
165
166
167 static void acpi_create_hpet(acpi_hpet_t *hpet)
168 {
169 #define HPET_ADDR  0xfed00000ULL
170         acpi_header_t *header=&(hpet->header);
171         acpi_addr_t *addr=&(hpet->addr);
172         
173         memset((void *)hpet, 0, sizeof(acpi_hpet_t));
174         
175         /* fill out header fields */
176         memcpy(header->signature, HPET_NAME, 4);
177         memcpy(header->oem_id, OEM_ID, 6);
178         memcpy(header->oem_table_id, HPET_TABLE, 8);
179         memcpy(header->asl_compiler_id, ASLC, 4);
180         
181         header->length = sizeof(acpi_hpet_t);
182         header->revision = 1;
183
184         /* fill out HPET address */
185         addr->space_id          = 0; /* Memory */
186         addr->bit_width         = 64;
187         addr->bit_offset        = 0;
188         addr->addrl             = HPET_ADDR & 0xffffffff;
189         addr->addrh             = HPET_ADDR >> 32;
190
191         hpet->id        = 0x102282a0; /* AMD ? */
192         hpet->number    = 0;
193         hpet->min_tick  = 4096;
194         
195         header->checksum        = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
196 }
197
198 static void acpi_create_facs(acpi_facs_t *facs)
199 {
200
201         memset( (void *)facs,0, sizeof(acpi_facs_t));
202
203         memcpy(facs->signature,"FACS",4);
204         facs->length = sizeof(acpi_facs_t);
205         facs->hardware_signature = 0;
206         facs->firmware_waking_vector = 0;
207         facs->global_lock = 0;
208         facs->flags = 0;
209         facs->x_firmware_waking_vector_l = 0;
210         facs->x_firmware_waking_vector_h = 0;
211         facs->version = 1;
212
213 }
214 static void acpi_write_rsdt(acpi_rsdt_t *rsdt)
215
216         acpi_header_t *header=&(rsdt->header);
217         
218         /* fill out header fields */
219         memcpy(header->signature, RSDT_NAME, 4);
220         memcpy(header->oem_id, OEM_ID, 6);
221         memcpy(header->oem_table_id, RSDT_TABLE, 8);
222         memcpy(header->asl_compiler_id, ASLC, 4);
223         
224         header->length = sizeof(acpi_rsdt_t);
225         header->revision = 1;
226         
227         /* fill out entries */
228
229         // entries are filled in later, we come with an empty set.
230         
231         /* fix checksum */
232         
233         header->checksum        = acpi_checksum((void *)rsdt, sizeof(acpi_rsdt_t));
234 }
235
236 static void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt)
237 {
238         memcpy(rsdp->signature, RSDP_SIG, 8);
239         memcpy(rsdp->oem_id, OEM_ID, 6);
240         
241         rsdp->length            = sizeof(acpi_rsdp_t);
242         rsdp->rsdt_address      = (u32)rsdt;
243         rsdp->checksum          = acpi_checksum((void *)rsdp, 20);
244         rsdp->ext_checksum      = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t));
245         
246 }
247
248 unsigned long write_acpi_tables(unsigned long start)
249 {
250         unsigned long current;
251         acpi_rsdp_t *rsdp;
252         acpi_rsdt_t *rsdt;
253         acpi_hpet_t *hpet;
254         acpi_madt_t *madt;
255         acpi_fadt_t *fadt;
256         acpi_facs_t *facs;
257         acpi_header_t *dsdt;
258         
259         /* Align ACPI tables to 16byte */
260         start   = ( start + 0x0f ) & -0x10;
261         current = start;
262         
263         printk_info("ACPI: Writing ACPI tables at %lx...\n", start);
264
265         /* We need at least an RSDP and an RSDT Table */
266         rsdp = (acpi_rsdp_t *) current;
267         current += sizeof(acpi_rsdp_t);
268         rsdt = (acpi_rsdt_t *) current;
269         current += sizeof(acpi_rsdt_t);
270
271         /* clear all table memory */
272         memset((void *)start, 0, current - start);
273         
274         acpi_write_rsdp(rsdp, rsdt);
275         acpi_write_rsdt(rsdt);
276         
277         /*
278          * We explicitly add these tables later on:
279          */
280 #ifdef HAVE_ACPI_HPET
281         printk_debug("ACPI:    * HPET\n");
282
283         hpet = (acpi_hpet_t *) current;
284         current += sizeof(acpi_hpet_t);
285         acpi_create_hpet(hpet);
286         acpi_add_table(rsdt,hpet);
287
288         /* If we want to use HPET Timers Linux wants an MADT */
289         printk_debug("ACPI:    * MADT\n");
290
291         madt = (acpi_madt_t *) current;
292         acpi_create_madt(madt);
293         current+=madt->header.length;
294         acpi_add_table(rsdt,madt);
295
296
297 #endif
298
299 #ifdef HAVE_ACPI_FADT
300
301
302         printk_debug("ACPI:     * FACS\n");
303         facs = (acpi_facs_t *) current;
304         current += sizeof(acpi_facs_t);
305         acpi_create_facs(facs);
306
307
308         dsdt = (acpi_header_t *)current;
309         current += ((acpi_header_t *)AmlCode)->length;
310         memcpy((void *)dsdt,(void *)AmlCode, ((acpi_header_t *)AmlCode)->length);
311         dsdt->checksum = 0; // don't trust intel iasl compiler to get this right
312         dsdt->checksum = acpi_checksum(dsdt,dsdt->length);
313         printk_debug("ACPI:     * DSDT @ %08x Length %x\n",dsdt,dsdt->length);
314         printk_debug("ACPI:     * FADT\n");
315
316         fadt = (acpi_fadt_t *) current;
317         current += sizeof(acpi_fadt_t);
318
319         acpi_create_fadt(fadt,facs,dsdt);
320         acpi_add_table(rsdt,fadt);
321
322
323 #endif  
324
325
326
327         printk_info("ACPI: done.\n");
328         return current;
329 }
330