Hi all, I'm pleased to announce that I got S3 working with LinuxBIOSv2 on ASUS A8V-E SE (K8 + VT8237 + K8T890)!
I'm attaching the patch which is a big mess, but perhaps all are curious how is it done. To be able to do S3 we must first set the register values used for sleep in ACPI DSDT table: + Name (\_S3, Package () {0x01, 0x01, 0x00, 0x00 }) Plus we need some callbacks to SB code which tells LinuxBIOS if it is normal startup or Wakeup and if it is a wakeup we need to know the vector to return to OS. This vector is stored in one ACPI table and because LinuxBIOSv2 puts tables on same place I will take the vector value just before I overwrite it ;) So how it works? LinuxBIOS will boot as usual if S3, but not executing payload but jumping to real mode waking vector from OS. During memory initialization we need to exit the self-refresh mode instead of training the memory again. Plus we need to adjust the K8 registers to listen for SMAF messages from SB that we go S3. The serious problem is that LinuxBIOS overwrites a lot of memory - lowmem, highmem (1M above). So how to protect it for OS? I booted linux with custom memory map 2M-1GB and LinuxBIOS had 0M-2M for its own stuff. But If I reserved memory for linux this way, ACPI code refuses to work, because OS waking code must be in 1MB range. I decided to patch the kernel and put always waking code to 0xE000:0000 /linux-2.6.23.1/arch/x86_64/kernel/acpi/sleep.c void __init acpi_reserve_bootmem(void) { acpi_wakeup_address = phys_to_virt(0xE0000); //(unsigned long)alloc_bootmem_low(PAGE_SIZE*2); printk("ACpi wakeup %x\n", acpi_wakeup_address); if ((&wakeup_end - &wakeup_start) > (PAGE_SIZE*2)) printk(KERN_CRIT "ACPI: Wakeup code way too big, will crash on attempt" " to suspend\n"); } Getting close to have working implementation but one thing was still missing. The exit from Self refresh seemed not to work. But, booting with original BIOS, rebooting to LB and then suspend/resume in LB did work! Hum something was wrong with some chip, but not with memory itself. Today I found out. There seems to be some undocumented bit in Winbond W83627EHF which will leave power to right parts of the system :) The attached script fix_ehf has a workaround ;) In the meanwhile I found out how to blink with the power LED and how to overclock the motherboard + most GPIO meaning, so I updated the Wiki page with that too. So what needs to be done? 1) consolidate the memory usage of LinuxBIOSv2 2) dont clean arbitrary memory Perhaps we could reserve last 1MB of RAM or something after 8MB of mem and put linuxBIOS heap there when using S3 we would just reserve the region + (some region bellow the 1MB for AP CPU boot + ACPI tables etc) The patch has some errata update of code too, I will publish this as separate patch - I did it because I thought I got still some memory related problem. Unfortunately I do not have much time for this fun, very busy with other stuff, but I needed some break ;) Oh I forgot - the real mode switcher and A20 handler are from Linux kernel. Thanks, Rudolf
Index: src/southbridge/via/vt8237r/vt8237r_early_smbus.c =================================================================== --- src/southbridge/via/vt8237r/vt8237r_early_smbus.c (revision 2978) +++ src/southbridge/via/vt8237r/vt8237r_early_smbus.c (working copy) @@ -212,3 +212,57 @@ else PRINT_DEBUG("Done\r\n"); } + +int acpi_is_wakeup_early(void) { + device_t dev; + u16 tmp; + + print_debug("IN TEST WAKEUP\n"); + /* Power management controller */ + dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VT8237R_LPC), 0); + + if (dev == PCI_DEV_INVALID) + die("Power management controller not found\r\n"); + + /* Set ACPI base address to I/O VT8237R_ACPI_IO_BASE. */ + pci_write_config16(dev, 0x88, VT8237R_ACPI_IO_BASE | 0x1); + + /* Enable ACPI accessm RTC signal gated with PSON. */ + pci_write_config8(dev, 0x81, 0x84); + + tmp = inw(VT8237R_ACPI_IO_BASE + 0x04); + + print_debug_hex8(tmp); + return ((tmp & (7 << 10)) >> 10) == 1 ? 3 : 0 ; +} + +void acpi_clear_sleep(void) { + device_t dev; + u16 tmp; + + print_debug("IN clear acpi sleep\n"); + /* Power management controller */ + dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VT8237R_LPC), 0); + + if (dev == PCI_DEV_INVALID) + die("Power management controller not found\r\n"); + + /* Set ACPI base address to I/O VT8237R_ACPI_IO_BASE. */ + pci_write_config16(dev, 0x88, VT8237R_ACPI_IO_BASE | 0x1); + + /* Enable ACPI accessm RTC signal gated with PSON. */ + pci_write_config8(dev, 0x81, 0x84); + + tmp = inw(VT8237R_ACPI_IO_BASE + 0x04); + + print_debug_hex8(tmp); +// return ((tmp & (7 << 10)) >> 10) == 1 ? 3 : 0 ; + + tmp &= 0xe3ff; //clear sleep to normal ON + tmp |= 0x2000; + outb(tmp, VT8237R_ACPI_IO_BASE + 0x04); + print_debug_hex8(tmp); + +} \ No newline at end of file Index: src/southbridge/via/vt8237r/vt8237r_lpc.c =================================================================== --- src/southbridge/via/vt8237r/vt8237r_lpc.c (revision 2978) +++ src/southbridge/via/vt8237r/vt8237r_lpc.c (working copy) @@ -145,8 +145,12 @@ * Set up the power management capabilities directly into ACPI mode. * This avoids having to handle any System Management Interrupts (SMIs). */ + + u8 acpi_sleep_type; + static void setup_pm(device_t dev) { + u16 tmp; /* Debounce LID and PWRBTN# Inputs for 16ms. */ pci_write_config8(dev, 0x80, 0x20); @@ -219,8 +223,12 @@ /* Disable extended IO traps. */ outb(0x0, VT8237R_ACPI_IO_BASE + 0x42); + tmp = inw(VT8237R_ACPI_IO_BASE + 0x04); + acpi_sleep_type = ((tmp & (7 << 10)) >> 10) == 1 ? 3 : 0 ; + printk_debug("SLEEP type was %x %x\n", tmp, acpi_sleep_type); /* SCI is generated for RTC/pwrBtn/slpBtn. */ - outw(0x001, VT8237R_ACPI_IO_BASE + 0x04); + tmp |= 1; + outw(tmp, VT8237R_ACPI_IO_BASE + 0x04); /* FIXME: Intel needs more bit set for C2/C3. */ Index: src/cpu/amd/car/clear_init_ram.c =================================================================== --- src/cpu/amd/car/clear_init_ram.c (revision 2978) +++ src/cpu/amd/car/clear_init_ram.c (working copy) @@ -6,13 +6,14 @@ // gcc 3.4.5 will inline the copy_and_run and clear_init_ram in post_cache_as_ram // will reuse %edi as 0 from clear_memory for copy_and_run part, actually it is increased already // so noline clear_init_ram - clear_memory(0, ((CONFIG_LB_MEM_TOPK<<10) - DCACHE_RAM_SIZE)); + clear_memory(0x0, 0xA0000 ); +// clear_memory(0xF0000, ((CONFIG_LB_MEM_TOPK<<10) - DCACHE_RAM_SIZE)); } /* be warned, this file will be used by core other than core 0/node 0 or core0/node0 when cpu_reset*/ static void set_init_ram_access(void) { - set_var_mtrr(0, 0x00000000, CONFIG_LB_MEM_TOPK << 10, MTRR_TYPE_WRBACK); + set_var_mtrr(0, 0x0, CONFIG_LB_MEM_TOPK << 10, MTRR_TYPE_WRBACK); } Index: src/cpu/amd/car/post_cache_as_ram.c =================================================================== --- src/cpu/amd/car/post_cache_as_ram.c (revision 2978) +++ src/cpu/amd/car/post_cache_as_ram.c (working copy) @@ -5,6 +5,8 @@ #include "cpu/amd/car/clear_init_ram.c" +#include "ram/ramtest.c" + static inline void print_debug_pcar(const char *strval, uint32_t val) { #if CONFIG_USE_PRINTK_IN_CAR @@ -28,6 +30,8 @@ static void post_cache_as_ram(void) { + + #if 1 { /* Check value of esp to verify if we have enough rom for stack in Cache as RAM */ @@ -87,6 +91,9 @@ print_debug("Disabling cache as ram now \r\n"); disable_cache_as_ram_bsp(); + ram_check(0, 4 * 1024); + + print_debug("Clearing initial memory region: "); clear_init_ram(); //except the range from [(CONFIG_LB_MEM_TOPK<<10) - DCACHE_RAM_SIZE, (CONFIG_LB_MEM_TOPK<<10)) print_debug("Done\r\n"); Index: src/cpu/amd/model_fxx/fidvid.c =================================================================== --- src/cpu/amd/model_fxx/fidvid.c (revision 2978) +++ src/cpu/amd/model_fxx/fidvid.c (working copy) @@ -71,7 +71,7 @@ // dword = 0x00070000; //enable FID/VID change pci_write_config32(PCI_DEV(0, 0x18+i, 3), 0x80, dword); - dword = 0x00132113; + dword = 0x61133113; pci_write_config32(PCI_DEV(0, 0x18+i, 3), 0x84, dword); } Index: src/cpu/amd/model_fxx/model_fxx_init.c =================================================================== --- src/cpu/amd/model_fxx/model_fxx_init.c (revision 2978) +++ src/cpu/amd/model_fxx/model_fxx_init.c (working copy) @@ -368,6 +368,7 @@ static inline void k8_errata(void) { msr_t msr; + u32 cpuid; #if K8_REV_F_SUPPORT == 0 if (is_cpu_pre_c0()) { /* Erratum 63... */ @@ -439,7 +440,7 @@ #endif #if K8_REV_F_SUPPORT == 0 - if (!is_cpu_pre_e0()) + if (!is_cpu_pre_d0()) #endif { /* Erratum 110 ... */ @@ -453,13 +454,19 @@ msr.lo |= 1 << 6; wrmsr(HWCR_MSR, msr); -#if K8_REV_F_SUPPORT == 1 - /* Erratum 131... */ + /* Erratum 131 is fixed together with erratum 169 */ msr = rdmsr(NB_CFG_MSR); - msr.lo |= 1 << 20; + msr.lo |= 1 << 32; wrmsr(NB_CFG_MSR, msr); -#endif + cpuid = cpuid_eax(0x1); + + /* Fixme erratum 113 JH-E1 DH-E3 */ + if ((cpuid == 0x20f10) || (cpuid == 0x20FF0) || (cpuid == 0x20FC0)) { + msr = rdmsr_amd(BU_CFG_MSR); + msr.hi |= (1 << (48 - 32)); + wrmsr_amd(BU_CFG_MSR, msr); + } } extern void model_fxx_update_microcode(unsigned cpu_deviceid); Index: src/mainboard/asus/a8v-e_se/Config.lb =================================================================== --- src/mainboard/asus/a8v-e_se/Config.lb (revision 2978) +++ src/mainboard/asus/a8v-e_se/Config.lb (working copy) @@ -63,6 +63,7 @@ ## driver mainboard.o +driver wakeup.o if HAVE_ACPI_TABLES object acpi_tables.o @@ -195,6 +196,7 @@ register "fn_ctrl_hi" = "0xad" device pci 0.0 on end # HT + device pci f.0 on end # SATA device pci f.1 on end # IDE device pci 11.0 on # LPC chip drivers/generic/generic #dimm 0-0-0 Index: src/mainboard/asus/a8v-e_se/acpi_tables.c =================================================================== --- src/mainboard/asus/a8v-e_se/acpi_tables.c (revision 2978) +++ src/mainboard/asus/a8v-e_se/acpi_tables.c (working copy) @@ -109,6 +109,7 @@ current += sizeof(acpi_rsdt_t); /* clear all table memory */ + memset((void *) start, 0, current - start); acpi_write_rsdp(rsdp, rsdt); @@ -167,3 +168,10 @@ printk_info("ACPI: done.\n"); return current; } + +extern u32 wake_vec; +extern u8 acpi_sleep_type; + +int acpi_is_wakeup(void) { + return (acpi_sleep_type == 3); +} Index: src/mainboard/asus/a8v-e_se/dsdt.asl =================================================================== --- src/mainboard/asus/a8v-e_se/dsdt.asl (revision 2978) +++ src/mainboard/asus/a8v-e_se/dsdt.asl (working copy) @@ -44,6 +179,7 @@ */ Name (\_S0, Package () {0x00, 0x00, 0x00, 0x00 }) Name (\_S5, Package () {0x02, 0x02, 0x00, 0x00 }) + Name (\_S3, Package () {0x01, 0x01, 0x00, 0x00 }) /* Root of the bus hierarchy */ Scope (\_SB) Index: src/mainboard/asus/a8v-e_se/wakeup.c =================================================================== --- src/mainboard/asus/a8v-e_se/wakeup.c (revision 0) +++ src/mainboard/asus/a8v-e_se/wakeup.c (revision 0) @@ -0,0 +1,267 @@ +//reboot.c from linux + +#include <stdint.h> +#include <string.h> +#include <arch/io.h> +#include <console/console.h> + + + +int enable_a20(void); + +/* The following code and data reboots the machine by switching to real + mode and jumping to the BIOS reset entry point, as if the CPU has + really been reset. The previous version asked the keyboard + controller to pulse the CPU reset line, which is more thorough, but + doesn't work with at least one type of 486 motherboard. It is easy + to stop this code working; hence the copious comments. */ + +static unsigned long long +real_mode_gdt_entries [3] = +{ + 0x0000000000000000ULL, /* Null descriptor */ + 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ +}; + +struct Xgt_desc_struct { + unsigned short size; + unsigned long address __attribute__((packed)); + unsigned short pad; + } __attribute__ ((packed)); + +static struct Xgt_desc_struct +real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries }, +real_mode_idt = { 0x3ff, 0 }, +no_idt = { 0, 0 }; + + +/* This is 16-bit protected mode code to disable paging and the cache, + switch to real mode and jump to the BIOS reset code. + + The instruction that switches to real mode by writing to CR0 must be + followed immediately by a far jump instruction, which set CS to a + valid value for real mode, and flushes the prefetch queue to avoid + running instructions that have already been decoded in protected + mode. + + Clears all the flags except ET, especially PG (paging), PE + (protected-mode enable) and TS (task switch for coprocessor state + save). Flushes the TLB after paging has been disabled. Sets CD and + NW, to disable the cache on a 486, and invalidates the cache. This + is more like the state of a 486 after reset. I don't know if + something else should be done for other chips. + + More could be done here to set up the registers as if a CPU reset had + occurred; hopefully real BIOSs don't assume much. */ + + +// 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ + +static unsigned char real_mode_switch [] = +{ + 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ + 0x24, 0xfe, /* andb $0xfe,al */ + 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ +}; +static unsigned char jump_to_wakeup [] = +{ + 0xea, 0x00, 0x00, 0x00, 0xe0 /* ljmp $0xffff,$0x0000 */ +}; + +/* + * Switch to real mode and then execute the code + * specified by the code and length parameters. + * We assume that length will aways be less that 100! + */ + +void acpi_jump_wake(u32 vector) +{ +u8 tmp; + printk_debug("IN ACPI JUMP WAKE TO %x\n", vector); + if (enable_a20()) + die("failed to enable A20\n"); + printk_debug("IN ACPI JUMP WAKE TO 2 %x\n", vector); + +// * ((u32 *) (jump_to_wakeup+1)) = vector; + printk_debug("%x %x %x %x %x\n", jump_to_wakeup[0], jump_to_wakeup[1], jump_to_wakeup[2], jump_to_wakeup[3],jump_to_wakeup[4]); + + memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), + real_mode_switch, sizeof (real_mode_switch)); + memcpy ((void *) (0x1000 - 100), jump_to_wakeup, sizeof(jump_to_wakeup)); + + /* Set up the IDT for real mode. */ + + asm volatile("lidt %0"::"m" (real_mode_idt)); + + /* Set up a GDT from which we can load segment descriptors for real + mode. The GDT is not used in real mode; it is just needed here to + prepare the descriptors. */ + + asm volatile("lgdt %0"::"m" (real_mode_gdt)); + + /* Load the data segment registers, and thus the descriptors ready for + real mode. The base address of each segment is 0x100, 16 times the + selector value being loaded here. This is so that the segment + registers don't have to be reloaded after switching to real mode: + the values are consistent for real mode operation already. */ + + __asm__ __volatile__ ("movl $0x0010,%%eax\n" + "\tmovl %%eax,%%ds\n" + "\tmovl %%eax,%%es\n" + "\tmovl %%eax,%%fs\n" + "\tmovl %%eax,%%gs\n" + "\tmovl %%eax,%%ss" : : : "eax"); + + /* Jump to the 16-bit code that we copied earlier. It disables paging + and the cache, switches to real mode, and jumps to the BIOS reset + entry point. */ + + __asm__ __volatile__ ("ljmp $0x0008,%0" + : + : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); +} + + +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/a20.c + * + * Enable A20 gate (return -1 on failure) + */ + +//#include "boot.h" + +#define MAX_8042_LOOPS 100000 + +static int empty_8042(void) +{ + u8 status; + int loops = MAX_8042_LOOPS; + + while (loops--) { + udelay(1); + + status = inb(0x64); + if (status & 1) { + /* Read and discard input data */ + udelay(1); + (void)inb(0x60); + } else if (!(status & 2)) { + /* Buffers empty, finished! */ + return 0; + } + } + + return -1; +} + +/* Returns nonzero if the A20 line is enabled. The memory address + used as a test is the int $0x80 vector, which should be safe. */ + +#define A20_TEST_ADDR (4*0x80) +#define A20_TEST_SHORT 32 +#define A20_TEST_LONG 2097152 /* 2^21 */ + +static int a20_test(int loops) +{ + int ok = 0; + int saved, ctr; + +// set_fs(0x0000); +// set_gs(0xffff); + + saved = ctr = *((u32*) A20_TEST_ADDR); + + while (loops--) { + //wrfs32(++ctr, A20_TEST_ADDR); + + *((u32*) A20_TEST_ADDR) = ++ctr; + + udelay(1); /* Serialize and make delay constant */ + + ok = *((u32 *) A20_TEST_ADDR+0xffff0+0x10) ^ ctr; + if (ok) + break; + } + + *((u32*) A20_TEST_ADDR) = saved; + return ok; +} + +/* Quick test to see if A20 is already enabled */ +static int a20_test_short(void) +{ + return a20_test(A20_TEST_SHORT); +} + +/* Longer test that actually waits for A20 to come on line; this + is useful when dealing with the KBC or other slow external circuitry. */ +static int a20_test_long(void) +{ + return a20_test(A20_TEST_LONG); +} + +static void enable_a20_kbc(void) +{ + empty_8042(); + + outb(0xd1, 0x64); /* Command write */ + empty_8042(); + + outb(0xdf, 0x60); /* A20 on */ + empty_8042(); +} + +static void enable_a20_fast(void) +{ + u8 port_a; + + port_a = inb(0x92); /* Configuration port A */ + port_a |= 0x02; /* Enable A20 */ + port_a &= ~0x01; /* Do not reset machine */ + outb(port_a, 0x92); +} + +/* + * Actual routine to enable A20; return 0 on ok, -1 on failure + */ + +#define A20_ENABLE_LOOPS 255 /* Number of times to try */ + +int enable_a20(void) +{ + int loops = A20_ENABLE_LOOPS; + + while (loops--) { + /* First, check to see if A20 is already enabled + (legacy free, etc.) */ + if (a20_test_short()) + return 0; + + /* Try enabling A20 through the keyboard controller */ + empty_8042(); +//if (a20_test_short()) +// return 0; /* BIOS worked, but with delayed reaction */ + + enable_a20_kbc(); + if (a20_test_long()) + return 0; + + /* Finally, try enabling the "fast A20 gate" */ + enable_a20_fast(); + if (a20_test_long()) + return 0; + } + + return -1; +} Index: src/boot/hardwaremain.c =================================================================== --- src/boot/hardwaremain.c (revision 2978) +++ src/boot/hardwaremain.c (working copy) @@ -46,6 +46,9 @@ * Device Enumeration: * In the dev_enumerate() phase, */ + + extern u32 wake_vec; + void hardwaremain(int boot_complete) { struct lb_memory *lb_mem; @@ -87,7 +90,8 @@ * write our configuration tables. */ lb_mem = write_tables(); - + if (wake_vec) + acpi_jump_wake(wake_vec); #if CONFIG_FS_PAYLOAD == 1 filo(lb_mem); #else Index: src/northbridge/amd/amdk8/coherent_ht.c =================================================================== --- src/northbridge/amd/amdk8/coherent_ht.c (revision 2978) +++ src/northbridge/amd/amdk8/coherent_ht.c (working copy) @@ -1704,6 +1704,12 @@ needs_reset = 1; /* Needed? */ } } + /* Errata 169 */ + dev = NODE_HT(node); + cmd = pci_read_config32(dev, 0x68); + cmd &= ~(3 << 21); + cmd |= (1 << 21); + pci_write_config32(dev, 0x68, cmd); #endif } return needs_reset; Index: src/northbridge/amd/amdk8/raminit.c =================================================================== --- src/northbridge/amd/amdk8/raminit.c (revision 2978) +++ src/northbridge/amd/amdk8/raminit.c (working copy) @@ -2268,6 +2268,8 @@ #endif { int i; + u32 whatWAIT; + int a = acpi_is_wakeup_early(); /* Error if I don't have memory */ if (memory_end_k(ctrl, controllers) == 0) { @@ -2307,6 +2309,9 @@ if (!(dch & DCH_MEMCLK_VALID)) { continue; } + enable_lapic(); + init_timer(); + delay(1); /* Toggle DisDqsHys to get it working */ dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); @@ -2320,15 +2325,36 @@ } pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc); } - dcl |= DCL_DisDqsHys; - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); + + if (!a) { + dcl |= DCL_DisDqsHys; + pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); + } dcl &= ~DCL_DisDqsHys; dcl &= ~DCL_DLL_Disable; dcl &= ~DCL_D_DRV; dcl &= ~DCL_QFC_EN; - dcl |= DCL_DramInit; + + if (a) { + print_debug("Exiting self-refreSH2\n\r"); + dcl |= (DCL_ESR | DCL_SRS); + /* Handle errata 85 - 85 Insufficient Delay Between MEMCLK Startup and CKE Assertion During Resume From S3 */ + delay(1); /* for unregistered */ + if (is_registered(&ctrl[i])) { + udelay(90); /* 100us for registered */ + } + print_debug("Exiting self-refresh - after delay\n\r"); + whatWAIT = DCL_ESR; + + } else { + dcl |= DCL_DramInit; + whatWAIT = DCL_DramInit; + } +// print_debug("Initializing memory delay... "); +// delay(5); /* for unregistered */ +// print_debug("done\n "); + pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - } for(i = 0; i < controllers; i++) { uint32_t dcl, dch; @@ -2340,16 +2366,18 @@ continue; } - print_debug("Initializing memory: "); + print_debug("Initializing memory XXX: "); int loops = 0; do { dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); loops += 1; + print_debug_hex32(dcl); + print_debug(" "); if ((loops & 1023) == 0) { print_debug("."); } - } while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS)); + } while(((dcl & whatWAIT) != 0) && (loops < TIMEOUT_LOOPS)); if (loops >= TIMEOUT_LOOPS) { print_debug(" failed\r\n"); continue; @@ -2357,16 +2385,23 @@ if (!is_cpu_pre_c0()) { /* Wait until it is safe to touch memory */ - dcl &= ~(DCL_MemClrStatus | DCL_DramEnable); - pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); +// dcl &= ~(DCL_MemClrStatus | DCL_DramEnable); +// pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); do { dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); - } while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) ); + print_debug("DCL\r\n"); + print_debug_hex32(dcl); + + } while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) || + ((dcl & DCL_SRS))); } - print_debug(" done\r\n"); } + if (a) { + acpi_clear_sleep(); + } + #if HW_MEM_HOLE_SIZEK != 0 // init hw mem hole here /* DramHoleValid bit only can be set after MemClrStatus is set by Hardware */ Index: src/northbridge/amd/amdk8/amdk8.h =================================================================== --- src/northbridge/amd/amdk8/amdk8.h (revision 2978) +++ src/northbridge/amd/amdk8/amdk8.h (working copy) @@ -135,6 +135,8 @@ #define DCL_QFC_EN (1<<2) #define DCL_DisDqsHys (1<<3) #define DCL_Burst2Opt (1<<5) +/* Check errata 115 for JH-E1 */ +/* Check errata 116 */ #define DCL_DramInit (1<<8) #define DCL_DualDIMMen (1<<9) #define DCL_DramEnable (1<<10) Index: src/northbridge/amd/amdk8/coherent_ht_car.c =================================================================== --- src/northbridge/amd/amdk8/coherent_ht_car.c (revision 2978) +++ src/northbridge/amd/amdk8/coherent_ht_car.c (working copy) @@ -1703,6 +1703,12 @@ needs_reset = 1; /* Needed? */ } } + /* Errata 169 */ + dev = NODE_HT(node); + cmd = pci_read_config32(dev, 0x68); + cmd &= ~(3 << 21); + cmd |= (1 << 21); + pci_write_config32(dev, 0x68, cmd); #endif } return needs_reset; Index: src/arch/i386/boot/tables.c =================================================================== --- src/arch/i386/boot/tables.c (revision 2978) +++ src/arch/i386/boot/tables.c (working copy) @@ -60,6 +60,7 @@ /* write them in the rom area because DSDT can be large (8K on epia-m) which * pushes linuxbios table out of first 4K if set up in low table area */ + rom_table_end = write_acpi_tables(rom_table_end); rom_table_end = (rom_table_end+1023) & ~1023; Index: src/arch/i386/boot/acpi.c =================================================================== --- src/arch/i386/boot/acpi.c (revision 2978) +++ src/arch/i386/boot/acpi.c (working copy) @@ -293,14 +293,28 @@ header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t)); } +u32 wake_vec; + void acpi_create_facs(acpi_facs_t *facs) { + if (acpi_is_wakeup()) { + wake_vec = facs->firmware_waking_vector; + printk_debug("OS waking vector is %x\n", wake_vec); + } + memset( (void *)facs,0, sizeof(acpi_facs_t)); memcpy(facs->signature,"FACS",4); facs->length = sizeof(acpi_facs_t); facs->hardware_signature = 0; - facs->firmware_waking_vector = 0; + + if (wake_vec) { + facs->firmware_waking_vector = wake_vec; + } else { + facs->firmware_waking_vector = 0; + wake_vec = 0; + } + facs->global_lock = 0; facs->flags = 0; facs->x_firmware_waking_vector_l = 0; Index: targets/asus/a8v-e_se/Config.lb =================================================================== --- targets/asus/a8v-e_se/Config.lb (revision 2978) +++ targets/asus/a8v-e_se/Config.lb (working copy) @@ -20,6 +20,8 @@ target asus_a8v-e_se mainboard asus/a8v-e_se +option CONFIG_COMPRESSED_PAYLOAD_NRV2B = 1 + romimage "normal" option ROM_SIZE = 512 * 1024 option USE_FALLBACK_IMAGE = 0
isaset -y -f 0x2e 0x87 isaset -y -f 0x2e 0x87 isaset -y 0x2e 0x2f 0x7 0xa isaset -y 0x2e 0x2f 0xe6 0x10 isaset -y 0x2e 0x2f 0xe4 0x30 isadump -y -k 0x87,0x87 0x2e 0x2f 0xa
-- linuxbios mailing list linuxbios@linuxbios.org http://www.linuxbios.org/mailman/listinfo/linuxbios