blob: a47e98fe0ceebd62f6e5616441f68f418afbaabe [file] [log] [blame]
Stefan Reinauer688b3852004-01-28 16:56:14 +00001/*
2 * LinuxBIOS ACPI Table support
3 * written by Stefan Reinauer <stepan@openbios.org>
Stefan Reinauer777224c2005-01-19 14:06:41 +00004 * (C) 2004 SUSE LINUX AG
5 * (C) 2005 Stefan Reinauer
6 *
7 * ACPI FADT, FACS, and DSDT table support added by
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +00008 * Nick Barker <nick.barker9@btinternet.com>, and those portions
Stefan Reinauer777224c2005-01-19 14:06:41 +00009 * (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.
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +000019 */
Stefan Reinauer688b3852004-01-28 16:56:14 +000020
21#include <console/console.h>
22#include <string.h>
23#include <arch/acpi.h>
Stefan Reinauer777224c2005-01-19 14:06:41 +000024#include <device/pci.h>
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +000025
26u8 acpi_checksum(u8 *table, u32 length)
Stefan Reinauer688b3852004-01-28 16:56:14 +000027{
28 u8 ret=0;
29 while (length--) {
30 ret += *table;
31 table++;
32 }
Stefan Reinauera7648c22004-01-29 17:31:34 +000033 return -ret;
Stefan Reinauer688b3852004-01-28 16:56:14 +000034}
35
Stefan Reinauer06feb882004-02-03 16:11:35 +000036/*
37 * add an acpi table to rsdt structure, and recalculate checksum
38 */
39
Stefan Reinauer777224c2005-01-19 14:06:41 +000040void acpi_add_table(acpi_rsdt_t *rsdt, void *table)
Stefan Reinauer688b3852004-01-28 16:56:14 +000041{
42 int i;
43
44 for (i=0; i<8; i++) {
45 if(rsdt->entry[i]==0) {
46 rsdt->entry[i]=(u32)table;
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +000047 /* fix length to stop kernel winging about invalid entries */
48 rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i+1));
Stefan Reinauer688b3852004-01-28 16:56:14 +000049 /* 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
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +000055 printk_debug("ACPI: added table %d/8 Length now %d\n",i+1,rsdt->header.length);
Stefan Reinauer688b3852004-01-28 16:56:14 +000056 return;
57 }
58 }
59
Stefan Reinauer777224c2005-01-19 14:06:41 +000060 printk_warning("ACPI: could not add ACPI table to RSDT. failed.\n");
Stefan Reinauer688b3852004-01-28 16:56:14 +000061}
62
Stefan Reinauer06feb882004-02-03 16:11:35 +000063
Stefan Reinauer777224c2005-01-19 14:06:41 +000064int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
Stefan Reinauer06feb882004-02-03 16:11:35 +000065{
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
Stefan Reinauer777224c2005-01-19 14:06:41 +000076int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,u32 gsi_base)
Stefan Reinauer06feb882004-02-03 16:11:35 +000077{
78 ioapic->type=1;
79 ioapic->length=sizeof(acpi_madt_ioapic_t);
80 ioapic->reserved=0x00;
Stefan Reinauer777224c2005-01-19 14:06:41 +000081 ioapic->gsi_base=gsi_base;
Stefan Reinauer06feb882004-02-03 16:11:35 +000082
83 ioapic->ioapic_id=id;
84 ioapic->ioapic_addr=addr;
85
86 return(ioapic->length);
87}
88
Stefan Reinauer777224c2005-01-19 14:06:41 +000089int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
Stefan Reinauer06feb882004-02-03 16:11:35 +000090 u8 bus, u8 source, u32 gsirq, u16 flags)
91{
92 irqoverride->type=2;
93 irqoverride->length=sizeof(acpi_madt_irqoverride_t);
Stefan Reinauer06feb882004-02-03 16:11:35 +000094 irqoverride->bus=bus;
95 irqoverride->source=source;
96 irqoverride->gsirq=gsirq;
97 irqoverride->flags=flags;
98
99 return(irqoverride->length);
100}
101
Stefan Reinauer777224c2005-01-19 14:06:41 +0000102int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
Stefan Reinauer06feb882004-02-03 16:11:35 +0000103 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
Stefan Reinauer777224c2005-01-19 14:06:41 +0000115void acpi_create_madt(acpi_madt_t *madt)
Stefan Reinauer06feb882004-02-03 16:11:35 +0000116{
117#define LOCAL_APIC_ADDR 0xfee00000ULL
Stefan Reinauer777224c2005-01-19 14:06:41 +0000118
Stefan Reinauer06feb882004-02-03 16:11:35 +0000119 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 */
Stefan Reinauer06feb882004-02-03 16:11:35 +0000135
Stefan Reinauer777224c2005-01-19 14:06:41 +0000136 current = acpi_dump_apics(current);
137
Stefan Reinauer06feb882004-02-03 16:11:35 +0000138 /* recalculate length */
139 header->length= current - (unsigned long)madt;
140
141 header->checksum = acpi_checksum((void *)madt, header->length);
142}
143
Stefan Reinauer777224c2005-01-19 14:06:41 +0000144void acpi_create_hpet(acpi_hpet_t *hpet)
Stefan Reinauer688b3852004-01-28 16:56:14 +0000145{
146#define HPET_ADDR 0xfed00000ULL
147 acpi_header_t *header=&(hpet->header);
148 acpi_addr_t *addr=&(hpet->addr);
149
Stefan Reinauera7648c22004-01-29 17:31:34 +0000150 memset((void *)hpet, 0, sizeof(acpi_hpet_t));
151
Stefan Reinauer688b3852004-01-28 16:56:14 +0000152 /* 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
Stefan Reinauera7648c22004-01-29 17:31:34 +0000172 header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
Stefan Reinauer688b3852004-01-28 16:56:14 +0000173}
174
Stefan Reinauer777224c2005-01-19 14:06:41 +0000175void acpi_create_facs(acpi_facs_t *facs)
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +0000176{
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +0000177 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;
Ronald G. Minnich02fa3b22004-10-06 17:33:54 +0000188}
Stefan Reinauer777224c2005-01-19 14:06:41 +0000189
190void acpi_write_rsdt(acpi_rsdt_t *rsdt)
Stefan Reinauer688b3852004-01-28 16:56:14 +0000191{
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
Stefan Reinauer777224c2005-01-19 14:06:41 +0000212void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt)
Stefan Reinauer688b3852004-01-28 16:56:14 +0000213{
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;
Stefan Reinauera7648c22004-01-29 17:31:34 +0000219 rsdp->checksum = acpi_checksum((void *)rsdp, 20);
220 rsdp->ext_checksum = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t));
Stefan Reinauer688b3852004-01-28 16:56:14 +0000221}
222
Stefan Reinauer688b3852004-01-28 16:56:14 +0000223