From 293b5f52253ec0e5edb38e9f7113afc7e8f8ba6e Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Sun, 1 Feb 2009 18:35:15 +0000 Subject: [PATCH] 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 Acked-by: Peter Stuge git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3925 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- src/arch/i386/boot/Config.lb | 2 +- src/arch/i386/boot/acpi.c | 29 +++++ src/arch/i386/boot/acpigen.c | 138 +++++++++++++++++++++ src/arch/i386/include/arch/acpi.h | 3 + src/arch/i386/include/arch/acpigen.h | 37 ++++++ src/mainboard/asus/m2v-mx_se/acpi_tables.c | 19 +-- src/northbridge/amd/amdk8/amdk8_acpi.c | 75 ++++++++++- src/northbridge/amd/amdk8/amdk8_acpi.h | 25 ++++ 8 files changed, 318 insertions(+), 10 deletions(-) create mode 100644 src/arch/i386/boot/acpigen.c create mode 100644 src/arch/i386/include/arch/acpigen.h create mode 100644 src/northbridge/amd/amdk8/amdk8_acpi.h diff --git a/src/arch/i386/boot/Config.lb b/src/arch/i386/boot/Config.lb index bacd1b018..6526a2f3f 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 4c2123146..40fdf3d36 100644 --- a/src/arch/i386/boot/acpi.c +++ b/src/arch/i386/boot/acpi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include 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 000000000..203f5a0f3 --- /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 + * + * 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 +#include +#include + +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 a71fb319f..beb1d5f5b 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 000000000..710593c00 --- /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 + * + * 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 +#include +#include + +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 4fb27dbbf..33540e09b 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 #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 e3709c475..16739c475 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> 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 000000000..faf0474e6 --- /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 + * + * 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 + +int k8acpi_write_vars(void); + +#endif -- 2.25.1