- make acpi usable for more than one motherboard.
[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  *  (C) 2005 Stefan Reinauer
6  *
7  * ACPI FADT, FACS, and DSDT table support added by 
8  * Nick Barker <nick.barker9@btinternet.com>, and those portions
9  *  (C) Copyright 2004 Nick Barker
10  */
11
12 /* 
13  * Each system port implementing ACPI has to provide two functions:
14  * 
15  *   write_acpi_tables()
16  *   acpi_dump_apics()
17  *   
18  * See Solo or Epia port on more details.
19  */
20
21 #include <console/console.h>
22 #include <string.h>
23 #include <arch/acpi.h>
24 #include <device/pci.h>
25
26 u8 acpi_checksum(u8 *table, u32 length)
27 {
28         u8 ret=0;
29         while (length--) {
30                 ret += *table;
31                 table++;
32         }
33         return -ret;
34 }
35
36 /*
37  * add an acpi table to rsdt structure, and recalculate checksum
38  */
39
40 void acpi_add_table(acpi_rsdt_t *rsdt, void *table)
41 {
42         int i;
43
44         for (i=0; i<8; i++) {
45                 if(rsdt->entry[i]==0) {
46                         rsdt->entry[i]=(u32)table;
47                         /* fix length to stop kernel winging about invalid entries */
48                         rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i+1));
49                         /* fix checksum */
50                         /* hope this won't get optimized away */
51                         rsdt->header.checksum=0;
52                         rsdt->header.checksum=acpi_checksum((u8 *)rsdt,
53                                         rsdt->header.length);
54                         
55                         printk_debug("ACPI: added table %d/8 Length now %d\n",i+1,rsdt->header.length);
56                         return;
57                 }
58         }
59
60         printk_warning("ACPI: could not add ACPI table to RSDT. failed.\n");
61 }
62
63
64 int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
65 {
66         lapic->type=0;
67         lapic->length=sizeof(acpi_madt_lapic_t);
68         lapic->flags=1;
69         
70         lapic->processor_id=cpu;
71         lapic->apic_id=apic;
72         
73         return(lapic->length);
74 }
75
76 int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,u32 gsi_base) 
77 {
78         ioapic->type=1;
79         ioapic->length=sizeof(acpi_madt_ioapic_t);
80         ioapic->reserved=0x00;
81         ioapic->gsi_base=gsi_base;
82         
83         ioapic->ioapic_id=id;
84         ioapic->ioapic_addr=addr;
85         
86         return(ioapic->length);
87 }
88
89 int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
90                 u8 bus, u8 source, u32 gsirq, u16 flags)
91 {
92         irqoverride->type=2;
93         irqoverride->length=sizeof(acpi_madt_irqoverride_t);
94         irqoverride->bus=bus;
95         irqoverride->source=source;
96         irqoverride->gsirq=gsirq;
97         irqoverride->flags=flags;
98         
99         return(irqoverride->length);
100 }
101
102 int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
103                 u16 flags, u8 lint)
104 {
105         lapic_nmi->type=4;
106         lapic_nmi->length=sizeof(acpi_madt_lapic_nmi_t);
107         
108         lapic_nmi->flags=flags;
109         lapic_nmi->processor_id=cpu;
110         lapic_nmi->lint=lint;
111         
112         return(lapic_nmi->length);
113 }
114
115 void acpi_create_madt(acpi_madt_t *madt)
116 {
117 #define LOCAL_APIC_ADDR 0xfee00000ULL
118         
119         acpi_header_t *header=&(madt->header);
120         unsigned long current=(unsigned long)madt+sizeof(acpi_madt_t);
121         
122         memset((void *)madt, 0, sizeof(acpi_madt_t));
123         
124         /* fill out header fields */
125         memcpy(header->signature, MADT_NAME, 4);
126         memcpy(header->oem_id, OEM_ID, 6);
127         memcpy(header->oem_table_id, MADT_TABLE, 8);
128         memcpy(header->asl_compiler_id, ASLC, 4);
129         
130         header->length = sizeof(acpi_madt_t);
131         header->revision = 1;
132
133         madt->lapic_addr= LOCAL_APIC_ADDR;
134         madt->flags     = 0x1; /* PCAT_COMPAT */
135
136         current = acpi_dump_apics(current);
137         
138         /* recalculate length */
139         header->length= current - (unsigned long)madt;
140         
141         header->checksum        = acpi_checksum((void *)madt, header->length);
142 }
143
144 void acpi_create_hpet(acpi_hpet_t *hpet)
145 {
146 #define HPET_ADDR  0xfed00000ULL
147         acpi_header_t *header=&(hpet->header);
148         acpi_addr_t *addr=&(hpet->addr);
149         
150         memset((void *)hpet, 0, sizeof(acpi_hpet_t));
151         
152         /* fill out header fields */
153         memcpy(header->signature, HPET_NAME, 4);
154         memcpy(header->oem_id, OEM_ID, 6);
155         memcpy(header->oem_table_id, HPET_TABLE, 8);
156         memcpy(header->asl_compiler_id, ASLC, 4);
157         
158         header->length = sizeof(acpi_hpet_t);
159         header->revision = 1;
160
161         /* fill out HPET address */
162         addr->space_id          = 0; /* Memory */
163         addr->bit_width         = 64;
164         addr->bit_offset        = 0;
165         addr->addrl             = HPET_ADDR & 0xffffffff;
166         addr->addrh             = HPET_ADDR >> 32;
167
168         hpet->id        = 0x102282a0; /* AMD ? */
169         hpet->number    = 0;
170         hpet->min_tick  = 4096;
171         
172         header->checksum        = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
173 }
174
175 void acpi_create_facs(acpi_facs_t *facs)
176 {
177         memset( (void *)facs,0, sizeof(acpi_facs_t));
178
179         memcpy(facs->signature,"FACS",4);
180         facs->length = sizeof(acpi_facs_t);
181         facs->hardware_signature = 0;
182         facs->firmware_waking_vector = 0;
183         facs->global_lock = 0;
184         facs->flags = 0;
185         facs->x_firmware_waking_vector_l = 0;
186         facs->x_firmware_waking_vector_h = 0;
187         facs->version = 1;
188 }
189
190 void acpi_write_rsdt(acpi_rsdt_t *rsdt)
191
192         acpi_header_t *header=&(rsdt->header);
193         
194         /* fill out header fields */
195         memcpy(header->signature, RSDT_NAME, 4);
196         memcpy(header->oem_id, OEM_ID, 6);
197         memcpy(header->oem_table_id, RSDT_TABLE, 8);
198         memcpy(header->asl_compiler_id, ASLC, 4);
199         
200         header->length = sizeof(acpi_rsdt_t);
201         header->revision = 1;
202         
203         /* fill out entries */
204
205         // entries are filled in later, we come with an empty set.
206         
207         /* fix checksum */
208         
209         header->checksum        = acpi_checksum((void *)rsdt, sizeof(acpi_rsdt_t));
210 }
211
212 void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt)
213 {
214         memcpy(rsdp->signature, RSDP_SIG, 8);
215         memcpy(rsdp->oem_id, OEM_ID, 6);
216         
217         rsdp->length            = sizeof(acpi_rsdp_t);
218         rsdp->rsdt_address      = (u32)rsdt;
219         rsdp->checksum          = acpi_checksum((void *)rsdp, 20);
220         rsdp->ext_checksum      = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t));
221 }
222
223