diff options
author | Rudolf Marek <r.marek@assembler.cz> | 2009-02-01 18:35:15 +0000 |
---|---|---|
committer | Rudolf Marek <r.marek@assembler.cz> | 2009-02-01 18:35:15 +0000 |
commit | 293b5f52253ec0e5edb38e9f7113afc7e8f8ba6e (patch) | |
tree | d0ab38cd89f3ceace9ee3de1cddd6bb5d9acea1a | |
parent | 1c49bc9744c2e9044ddd1c8d20a1728f57eda85c (diff) |
Following patch adds dynamic ACPI AML code generator which can be used to
generate run-time ACPI ASL code.
Moreover it demonstrates its use on Asus M2V-MX SE where the SSDT table is
generated by new function k8acpi_write_vars (technically similar to
update_ssdt). But lot of nicer.
x
Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
Acked-by: Peter Stuge <peter@stuge.se>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3925 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
-rw-r--r-- | src/arch/i386/boot/Config.lb | 2 | ||||
-rw-r--r-- | src/arch/i386/boot/acpi.c | 29 | ||||
-rw-r--r-- | src/arch/i386/boot/acpigen.c | 138 | ||||
-rw-r--r-- | src/arch/i386/include/arch/acpi.h | 3 | ||||
-rw-r--r-- | src/arch/i386/include/arch/acpigen.h | 37 | ||||
-rw-r--r-- | src/mainboard/asus/m2v-mx_se/acpi_tables.c | 19 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/amdk8_acpi.c | 75 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/amdk8_acpi.h | 25 |
8 files changed, 318 insertions, 10 deletions
diff --git a/src/arch/i386/boot/Config.lb b/src/arch/i386/boot/Config.lb index bacd1b0181..6526a2f3f6 100644 --- a/src/arch/i386/boot/Config.lb +++ b/src/arch/i386/boot/Config.lb @@ -13,5 +13,5 @@ object pirq_routing.o end if HAVE_ACPI_TABLES object acpi.o +object acpigen.o end - diff --git a/src/arch/i386/boot/acpi.c b/src/arch/i386/boot/acpi.c index 4c21231467..40fdf3d368 100644 --- a/src/arch/i386/boot/acpi.c +++ b/src/arch/i386/boot/acpi.c @@ -24,6 +24,7 @@ #include <console/console.h> #include <string.h> #include <arch/acpi.h> +#include <arch/acpigen.h> #include <device/pci.h> u8 acpi_checksum(u8 *table, u32 length) @@ -181,6 +182,34 @@ void acpi_create_mcfg(acpi_mcfg_t *mcfg) header->checksum = acpi_checksum((void *)mcfg, header->length); } +/* this can be overriden by platform ACPI setup code, + if it calls acpi_create_ssdt_generator */ +unsigned long __attribute__((weak)) acpi_fill_ssdt_generator(unsigned long current, + char *oem_table_id) { + return current; +} + +void acpi_create_ssdt_generator(acpi_header_t *ssdt, char *oem_table_id) +{ + unsigned long current=(unsigned long)ssdt+sizeof(acpi_header_t); + memset((void *)ssdt, 0, sizeof(acpi_header_t)); + memcpy(&ssdt->signature, SSDT_NAME, 4); + ssdt->revision = 2; + memcpy(&ssdt->oem_id, OEM_ID, 6); + memcpy(&ssdt->oem_table_id, oem_table_id, 8); + ssdt->oem_revision = 42; + memcpy(&ssdt->asl_compiler_id, "GENAML", 4); + ssdt->asl_compiler_revision = 42; + ssdt->length = sizeof(acpi_header_t); + + acpigen_set_current((unsigned char *) current); + current = acpi_fill_ssdt_generator(current, oem_table_id); + + /* recalculate length */ + ssdt->length = current - (unsigned long)ssdt; + ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length); +} + int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic) { lapic->type=0; diff --git a/src/arch/i386/boot/acpigen.c b/src/arch/i386/boot/acpigen.c new file mode 100644 index 0000000000..203f5a0f3b --- /dev/null +++ b/src/arch/i386/boot/acpigen.c @@ -0,0 +1,138 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* how many nesting we support */ +#define ACPIGEN_LENSTACK_SIZE 10 + +/* if you need to change this, change the acpigen_write_f and + acpigen_patch_len */ + +#define ACPIGEN_MAXLEN 0xfff + +#include <string.h> +#include <arch/acpigen.h> +#include <console/console.h> + +static char *gencurrent; + +char *len_stack[ACPIGEN_LENSTACK_SIZE]; +int ltop = 0; + +static int acpigen_write_len_f() +{ + ASSERT(ltop < (ACPIGEN_LENSTACK_SIZE - 1)) + len_stack[ltop++] = gencurrent; + acpigen_emit_byte(0); + acpigen_emit_byte(0); + return 2; +} + +void acpigen_patch_len(int len) +{ + ASSERT(len <= ACPIGEN_MAXLEN) + ASSERT(ltop > 0) + char *p = len_stack[--ltop]; + /* generate store length for 0xfff max */ + p[0] = (0x40 | (len & 0xf)); + p[1] = (len >> 4 & 0xff); + +} + +void acpigen_set_current(char *curr) { + gencurrent = curr; +} + +char *acpigen_get_current(void) { + return gencurrent; +} + +int acpigen_emit_byte(unsigned char b) +{ + (*gencurrent++) = b; + return 1; +} + +int acpigen_write_package(int nr_el) +{ + int len; + /* package op */ + acpigen_emit_byte(0x12); + len = acpigen_write_len_f(); + acpigen_emit_byte(nr_el); + return len + 2; +} + +int acpigen_write_byte(unsigned int data) +{ + /* byte op */ + acpigen_emit_byte(0xa); + acpigen_emit_byte(data & 0xff); + return 2; +} + +int acpigen_write_dword(unsigned int data) +{ + /* dword op */ + acpigen_emit_byte(0xc); + acpigen_emit_byte(data & 0xff); + acpigen_emit_byte((data >> 8) & 0xff); + acpigen_emit_byte((data >> 16) & 0xff); + acpigen_emit_byte((data >> 24) & 0xff); + return 5; +} + +int acpigen_write_name_byte(char *name, uint8_t val) { + int len; + len = acpigen_write_name(name); + len += acpigen_write_byte(val); + return len; +} + +int acpigen_write_name_dword(char *name, uint32_t val) { + int len; + len = acpigen_write_name(name); + len += acpigen_write_dword(val); + return len; +} + +int acpigen_emit_stream(char *data, int size) { + int i; + for (i = 0; i < size; i++) { + acpigen_emit_byte(data[i]); + } + return size; +} + +int acpigen_write_name(char *name) +{ + int len = strlen(name); + /* name op */ + acpigen_emit_byte(0x8); + acpigen_emit_stream(name, len); + return len + 1; +} + +int acpigen_write_scope(char *name) +{ + int len; + /* scope op */ + acpigen_emit_byte(0x10); + len = acpigen_write_len_f(); + return len + acpigen_emit_stream(name, strlen(name)) + 1; +} diff --git a/src/arch/i386/include/arch/acpi.h b/src/arch/i386/include/arch/acpi.h index a71fb319f5..beb1d5f5b5 100644 --- a/src/arch/i386/include/arch/acpi.h +++ b/src/arch/i386/include/arch/acpi.h @@ -29,6 +29,7 @@ typedef unsigned long long u64; #define MCFG_NAME "MCFG" #define SRAT_NAME "SRAT" #define SLIT_NAME "SLIT" +#define SSDT_NAME "SSDT" #define RSDT_TABLE "RSDT " #define HPET_TABLE "AMD64 " @@ -293,6 +294,8 @@ unsigned long write_acpi_tables(unsigned long addr); unsigned long acpi_fill_madt(unsigned long current); unsigned long acpi_fill_mcfg(unsigned long current); unsigned long acpi_fill_srat(unsigned long current); +unsigned long acpi_fill_ssdt_generator(unsigned long current, char *oem_table_id); +void acpi_create_ssdt_generator(acpi_header_t *ssdt, char *oem_table_id); void acpi_create_fadt(acpi_fadt_t *fadt,acpi_facs_t *facs,void *dsdt); /* These can be used by the target port */ diff --git a/src/arch/i386/include/arch/acpigen.h b/src/arch/i386/include/arch/acpigen.h new file mode 100644 index 0000000000..710593c005 --- /dev/null +++ b/src/arch/i386/include/arch/acpigen.h @@ -0,0 +1,37 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef LIBACPI_H +#define LIBACPI_H +#include <assert.h> +#include <stdlib.h> +#include <stdint.h> + +void acpigen_patch_len(int len); +void acpigen_set_current(char *curr); +char *acpigen_get_current(void); +int acpigen_write_package(int nr_el); +int acpigen_write_byte(unsigned int data); +int acpigen_emit_byte(unsigned char data); +int acpigen_emit_stream(char *data, int size); +int acpigen_write_dword(unsigned int data); +int acpigen_write_name(char *name); +int acpigen_write_name_dword(char *name, uint32_t val); +int acpigen_write_name_byte(char *name, uint8_t val); +int acpigen_write_scope(char *name); +#endif diff --git a/src/mainboard/asus/m2v-mx_se/acpi_tables.c b/src/mainboard/asus/m2v-mx_se/acpi_tables.c index 4fb27dbbfb..33540e09b8 100644 --- a/src/mainboard/asus/m2v-mx_se/acpi_tables.c +++ b/src/mainboard/asus/m2v-mx_se/acpi_tables.c @@ -30,9 +30,9 @@ #include <device/pci_ids.h> #include <../../../southbridge/via/vt8237r/vt8237r.h> #include <../../../southbridge/via/k8t890/k8t890.h> +#include <../../../northbridge/amd/amdk8/amdk8_acpi.h> extern unsigned char AmlCode[]; -extern unsigned char AmlCode_ssdt[]; unsigned long acpi_fill_mcfg(unsigned long current) { @@ -81,6 +81,12 @@ unsigned long acpi_fill_madt(unsigned long current) return current; } +unsigned long acpi_fill_ssdt_generator(unsigned long current, char *oem_table_id) { + k8acpi_write_vars(); + /* put PSTATES generator call here */ + return (unsigned long) (acpigen_get_current()); +} + unsigned long write_acpi_tables(unsigned long start) { unsigned long current; @@ -175,13 +181,10 @@ unsigned long write_acpi_tables(unsigned long start) /* SSDT */ printk_debug("ACPI: * SSDT\n"); ssdt = (acpi_header_t *)current; - current += ((acpi_header_t *)AmlCode_ssdt)->length; - memcpy((void *)ssdt, (void *)AmlCode_ssdt, ((acpi_header_t *)AmlCode_ssdt)->length); - update_ssdt((void*)ssdt); - /* recalculate checksum */ - ssdt->checksum = 0; - ssdt->checksum = acpi_checksum((unsigned char *)ssdt,ssdt->length); - acpi_add_table(rsdt,ssdt); + + acpi_create_ssdt_generator(ssdt, "DYNADATA"); + current += ssdt->length; + acpi_add_table(rsdt, ssdt); printk_info("ACPI: done.\n"); return current; diff --git a/src/northbridge/amd/amdk8/amdk8_acpi.c b/src/northbridge/amd/amdk8/amdk8_acpi.c index e3709c4753..16739c4751 100644 --- a/src/northbridge/amd/amdk8/amdk8_acpi.c +++ b/src/northbridge/amd/amdk8/amdk8_acpi.c @@ -226,7 +226,6 @@ unsigned long acpi_fill_slit(unsigned long current) p[i*nodes+j] = hops_8[i*nodes+j] * 2 + 10; #endif - } } } @@ -236,6 +235,80 @@ unsigned long acpi_fill_slit(unsigned long current) return current; } +static int k8acpi_write_HT(void) { + device_t dev; + uint32_t dword; + int len, lenp, i; + + len = acpigen_write_name("HCLK"); + lenp = acpigen_write_package(HC_POSSIBLE_NUM); + + for(i=0;i<sysconf.hc_possible_num;i++) { + lenp += acpigen_write_dword(sysconf.pci1234[i]); + } + for(i=sysconf.hc_possible_num; i<HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8 + lenp += acpigen_write_dword(0x0); + } + + acpigen_patch_len(lenp - 1); + len += lenp; + + len += acpigen_write_name("HCDN"); + lenp = acpigen_write_package(HC_POSSIBLE_NUM); + + for(i=0;i<sysconf.hc_possible_num;i++) { + lenp += acpigen_write_dword(sysconf.hcdn[i]); + } + for(i=sysconf.hc_possible_num; i<HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8 + lenp += acpigen_write_dword(0x20202020); + } + acpigen_patch_len(lenp - 1); + len += lenp; + + return len; +} + +static int k8acpi_write_pci_data(int dlen, char *name, int offset) { + device_t dev; + uint32_t dword; + int len, lenp, i; + + dev = dev_find_slot(0, PCI_DEVFN(0x18, 1)); + + len = acpigen_write_name(name); + lenp = acpigen_write_package(dlen); + for(i=0; i<dlen; i++) { + dword = pci_read_config32(dev, offset+i*4); + lenp += acpigen_write_dword(dword); + } + // minus the opcode + acpigen_patch_len(lenp - 1); + return len + lenp; +} + +int k8acpi_write_vars(void) +{ + int lens; + msr_t msr; + char pscope[] = "\\._SB_PCI0"; + + lens = acpigen_write_scope(pscope); + lens += k8acpi_write_pci_data(4, "BUSN", 0xe0); + lens += k8acpi_write_pci_data(8, "PCIO", 0xc0); + lens += k8acpi_write_pci_data(16, "MMIO", 0x80); + lens += acpigen_write_name_byte("SBLK", sysconf.sblk); + lens += acpigen_write_name_byte("CBST", + ((sysconf.pci1234[0] >> 12) & 0xff) ? 0xf : 0x0); + lens += acpigen_write_name_dword("SBDN", sysconf.sbdn); + msr = rdmsr(TOP_MEM); + lens += acpigen_write_name_dword("TOM1", msr.lo); + + lens += k8acpi_write_HT(); + //minus opcode + acpigen_patch_len(lens - 1); + return lens; +} + // moved from mb acpi_tables.c static void intx_to_stream(u32 val, u32 len, u8 *dest) { diff --git a/src/northbridge/amd/amdk8/amdk8_acpi.h b/src/northbridge/amd/amdk8/amdk8_acpi.h new file mode 100644 index 0000000000..faf0474e65 --- /dev/null +++ b/src/northbridge/amd/amdk8/amdk8_acpi.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AMDK8_ACPI_H +#define AMDK8_ACPI_H +#include <arch/acpigen.h> + +int k8acpi_write_vars(void); + +#endif |