-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi all,
This is yet another WIP patch. This one actually works (suspend/resume works in Linux), but it: 1) corrupts memory around 0x1000 (the real mode trampoline) 2) it corrupts memory randomly in first 64KB copy_secondary_start_to_1m_below It puts Coreboot to last 1MB below 32MB (and reserves the memory there). So all I need is to solve the secondary.S starter and the real mode jumper -> somehow not to corrupt the lowmem or find some hole where it can be hidden. Rudolf -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAknMDVgACgkQ3J9wPJqZRNXa1gCgsqEF5ixml987NqZpq62nBPTZ 2T8AnR0MdwkbqdvzAuvCqAAAoZNBj3WX =pvTU -----END PGP SIGNATURE-----
Index: src/southbridge/via/vt8237r/vt8237r_early_smbus.c
===================================================================
--- src/southbridge/via/vt8237r/vt8237r_early_smbus.c (revision 4030)
+++ src/southbridge/via/vt8237r/vt8237r_early_smbus.c (working copy)
@@ -294,6 +294,61 @@
pci_write_config8(dev, 0x41, 0x7f);
}
+
+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_VT8237S_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_VT8237S_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);
+
+}
+
#if defined(__GNUC__)
void vt8237_early_spi_init(void)
{
Index: src/southbridge/via/vt8237r/vt8237r_lpc.c
===================================================================
--- src/southbridge/via/vt8237r/vt8237r_lpc.c (revision 4030)
+++ src/southbridge/via/vt8237r/vt8237r_lpc.c (working copy)
@@ -149,8 +149,13 @@
* 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);
@@ -171,10 +176,10 @@
/*
* 7 = SMBus clock from RTC 32.768KHz
- * 5 = Internal PLL reset from susp
- * 2 = GPO2 is GPIO
+ * 5 = Internal PLL reset from susp disabled
+ * 2 = GPO2 is SUSA#
*/
- pci_write_config8(dev, 0x94, 0xa4);
+ pci_write_config8(dev, 0x94, 0xa0);
/*
* 7 = stp to sust delay 1msec
@@ -219,7 +224,15 @@
outb(0x0, VT8237R_ACPI_IO_BASE + 0x42);
/* SCI is generated for RTC/pwrBtn/slpBtn. */
- outw(0x001, VT8237R_ACPI_IO_BASE + 0x04);
+ 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);
+ tmp |= 1;
+ outw(tmp, VT8237R_ACPI_IO_BASE + 0x04);
+
+
+
+
}
static void vt8237r_init(struct device *dev)
Index: src/southbridge/via/k8t890/k8t890_early_car.c
===================================================================
--- src/southbridge/via/k8t890/k8t890_early_car.c (revision 4030)
+++ src/southbridge/via/k8t890/k8t890_early_car.c (working copy)
@@ -23,7 +23,15 @@
*/
#include <stdlib.h>
+//include "k8t890.h"
+#warning hack the right header here
+/* The 256 bytes of NVRAM for S3 storage, 256B aligned */
+#define K8T890_NVRAM_IO_BASE 0xf00
+#define K8T890_MULTIPLE_FN_EN 0x4f
+
+
+
/* AMD K8 LDT0, LDT1, LDT2 Link Control Registers */
static ldtreg[3] = {0x86, 0xa6, 0xc6};
@@ -33,10 +41,22 @@
u8 k8t890_early_setup_ht(void)
{
- u8 awidth, afreq, cldtfreq;
+ u8 awidth, afreq, cldtfreq, reg;
u8 cldtwidth_in, cldtwidth_out, vldtwidth_in, vldtwidth_out, ldtnr, width;
u16 vldtcaps;
+ /* hack, enable NVRAM in chipset */
+ pci_write_config8(PCI_DEV(0, 0x0, 0), K8T890_MULTIPLE_FN_EN, 0x01);
+
+ /*
+ * NVRAM I/O base at K8T890_NVRAM_IO_BASE
+ */
+
+ pci_write_config8(PCI_DEV(0, 0x0, 2), 0xa2, (K8T890_NVRAM_IO_BASE >> 8));
+ reg = pci_read_config8(PCI_DEV(0, 0x0, 2), 0xa1);
+ reg |= 0x1;
+ pci_write_config8(PCI_DEV(0, 0x0, 2), 0xa1, reg);
+
/* check if connected non coherent, initcomplete (find the SB on K8 side) */
if (0x7 == pci_read_config8(PCI_DEV(0, 0x18, 0), 0x98)) {
ldtnr = 0;
Index: src/southbridge/via/k8t890/k8t890_host_ctrl.c
===================================================================
--- src/southbridge/via/k8t890/k8t890_host_ctrl.c (revision 4030)
+++ src/southbridge/via/k8t890/k8t890_host_ctrl.c (working copy)
@@ -37,14 +37,14 @@
*/
pci_write_config8(dev, 0xa0, 0x13);
- /* Disable NVRAM and enable non-posted PCI writes. */
- pci_write_config8(dev, 0xa1, 0x8e);
-
/*
- * NVRAM I/O base 0xe00-0xeff, but it is disabled.
+ * NVRAM I/O base at K8T890_NVRAM_IO_BASE
* Some bits are set and reserved.
*/
- pci_write_config8(dev, 0xa2, 0x0e);
+ pci_write_config8(dev, 0xa2, (K8T890_NVRAM_IO_BASE >> 8));
+
+ /* enable NB NVRAM and enable non-posted PCI writes. */
+ pci_write_config8(dev, 0xa1, 0x8f);
/* Arbitration control, some bits are reserved. */
pci_write_config8(dev, 0xa5, 0x3c);
@@ -95,14 +95,15 @@
*/
pci_write_config8(dev, 0xa0, 0x13);
- /* Disable NVRAM and enable non-posted PCI writes. */
- pci_write_config8(dev, 0xa1, 0x8e);
-
/*
- * NVRAM I/O base 0xe00-0xeff, but it is disabled.
+ * NVRAM I/O base at K8T890_NVRAM_IO_BASE
*/
- pci_write_config8(dev, 0xa2, 0x0e);
+ pci_write_config8(dev, 0xa2, (K8T890_NVRAM_IO_BASE >> 8));
+
+ /* Enable NVRAM and enable non-posted PCI writes. */
+ pci_write_config8(dev, 0xa1, 0x8f);
+
/* Arbitration control */
pci_write_config8(dev, 0xa5, 0x3c);
Index: src/southbridge/via/k8t890/k8t890.h
===================================================================
--- src/southbridge/via/k8t890/k8t890.h (revision 4030)
+++ src/southbridge/via/k8t890/k8t890.h (working copy)
@@ -29,6 +29,9 @@
*/
#define K8T890_APIC_BASE 0xfecc0000
+/* The 256 bytes of NVRAM for S3 storage, 256B aligned */
+#define K8T890_NVRAM_IO_BASE 0xf00
+
#define K8T890_MMCONFIG_MBAR 0x61
#define K8T890_MULTIPLE_FN_EN 0x4f
@@ -36,6 +39,7 @@
#define K8M890_FBSIZEMB 64
#include <device/device.h>
+
extern void writeback(struct device *dev, u16 where, u8 what);
extern void dump_south(device_t dev);
Index: src/superio/ite/it8712f/it8712f_early_serial.c
===================================================================
--- src/superio/ite/it8712f/it8712f_early_serial.c (revision 4030)
+++ src/superio/ite/it8712f/it8712f_early_serial.c (working copy)
@@ -32,6 +32,7 @@
#define IT8712F_CONFIG_REG_CONFIGSEL 0x22 /* Configuration Select. */
#define IT8712F_CONFIG_REG_CLOCKSEL 0x23 /* Clock Selection. */
#define IT8712F_CONFIG_REG_SWSUSP 0x24 /* Software Suspend, Flash I/F. */
+#define IT8712F_CONFIG_REG_MFC 0x2a /* Multi-function control */
#define IT8712F_CONFIG_REG_WATCHDOG 0x72 /* Watchdog control. */
#define IT8712F_CONFIGURATION_PORT 0x2e /* Write-only. */
@@ -78,6 +79,21 @@
}
+static void it8712f_enable_3vsbsw(void) {
+
+ /* We need to set enable 3VSBSW#, this was documented only in IT8712F_V0.9.2!
+ LDN 7, reg 0x2a - needed for S3, or memory power will be cut off.
+ Enable 3VSBSW#. (For System Suspend-to-RAM)
+ 0: 3VSBSW# will be always inactive.
+ 1: 3VSBSW# enabled. It will be (NOT SUSB#) NAND SUSC#.
+ */
+
+ it8712f_enter_conf();
+ it8712f_sio_write(0x07, IT8712F_CONFIG_REG_MFC, 0x80);
+ it8712f_exit_conf();
+}
+
+
static void it8712f_kill_watchdog(void)
{
it8712f_enter_conf();
Index: src/cpu/amd/model_fxx/fidvid.c
===================================================================
--- src/cpu/amd/model_fxx/fidvid.c (revision 4030)
+++ src/cpu/amd/model_fxx/fidvid.c (working copy)
@@ -73,7 +73,8 @@
// dword = 0x00070000; /* enable FID/VID change */
pci_write_config32(PCI_DEV(0, 0x18+i, 3), 0x80, dword);
- dword = 0x00132113;
+ //2113_2113h
+ dword = 0x21132113;
pci_write_config32(PCI_DEV(0, 0x18+i, 3), 0x84, dword);
}
Index: src/cpu/amd/car/copy_and_run.c
===================================================================
--- src/cpu/amd/car/copy_and_run.c (revision 4030)
+++ src/cpu/amd/car/copy_and_run.c (working copy)
@@ -21,9 +21,30 @@
static void copy_and_run(void)
{
uint8_t *src, *dst;
+ int i;
+ u32 *p = 4*1024;
unsigned long ilen, olen;
+#if 0
+ print_debug("RAM low poison.\r\n");
+ for (i=(4*1024);i<(640*1024);i+=4) {
+ *p = p;
+ p++;
+ }
+#endif
+
+/*
+ p = 1*1024*1024;
+ print_debug("RAM high poison.\r\n");
+
+ for (i=1;i<(30*1024*1024);i+=4) {
+ *p = p;
+ p++;
+ }
+
+*/
+
#if !CONFIG_COMPRESS
print_debug("Copying coreboot to RAM.\r\n");
__asm__ volatile (
Index: src/cpu/amd/car/clear_init_ram.c
===================================================================
--- src/cpu/amd/car/clear_init_ram.c (revision 4030)
+++ src/cpu/amd/car/clear_init_ram.c (working copy)
@@ -6,8 +6,7 @@
// 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( _RAMBASE, (CONFIG_LB_MEM_TOPK << 10) - _RAMBASE - DCACHE_RAM_SIZE);
}
/* be warned, this file will be used by core other than core 0/node 0 or core0/node0 when cpu_reset*/
Index: src/mainboard/asus/m2v-mx_se/Options.lb
===================================================================
--- src/mainboard/asus/m2v-mx_se/Options.lb (revision 4030)
+++ src/mainboard/asus/m2v-mx_se/Options.lb (working copy)
@@ -159,9 +159,9 @@
default STACK_SIZE = 8 * 1024
default HEAP_SIZE = 256 * 1024
# More 1M for pgtbl.
-default CONFIG_LB_MEM_TOPK = 2048
+default CONFIG_LB_MEM_TOPK = 32768
# to 1MB
-default _RAMBASE = 0x100000
+default _RAMBASE = 0x1F00000
# default USE_OPTION_TABLE = !USE_FALLBACK_IMAGE
default CONFIG_ROM_PAYLOAD = 1
default CC = "$(CROSS_COMPILE)gcc -m32"
Index: src/mainboard/asus/m2v-mx_se/dsdt.asl
===================================================================
--- src/mainboard/asus/m2v-mx_se/dsdt.asl (revision 4030)
+++ src/mainboard/asus/m2v-mx_se/dsdt.asl (working copy)
@@ -30,8 +30,24 @@
* Any others would involve declaring the wake up methods.
*/
Name (\_S0, Package () { 0x00, 0x00, 0x00, 0x00 })
+ Name (\_S3, Package () { 0x01, 0x01, 0x00, 0x00 })
Name (\_S5, Package () { 0x02, 0x02, 0x00, 0x00 })
+
+ /* blink a LED when entering the sleep (any type) */
+ Method (_PTS, 1, NotSerialized)
+ {
+ Store (0x1, \_SB.PCI0.ISA.LEDR)
+ }
+
+ /* cancel a LED blinking when waking from sleep (any type) */
+ Method (_WAK, 1, NotSerialized)
+ {
+ Store (0x0, \_SB.PCI0.ISA.LEDR)
+ /* wake OK */
+ Return(Package(0x02){0x00, 0x00})
+ }
+
/* Root of the bus hierarchy */
Scope (\_SB)
{
@@ -160,7 +176,14 @@
}
Device (ISA) {
Name (_ADR, 0x00110000)
-
+ OperationRegion (PCIC, PCI_Config, 0x0, 0xff)
+ Field (PCIC, ByteAcc, NoLock, Preserve)
+ {
+ Offset (0x94),
+ /* two LSB bits are blink rate */
+ LEDR, 2,
+ }
+
/* PS/2 keyboard (seems to be important for WinXP install) */
Device (KBD)
{
Index: src/mainboard/asus/m2v-mx_se/mainboard.c
===================================================================
--- src/mainboard/asus/m2v-mx_se/mainboard.c (revision 4030)
+++ src/mainboard/asus/m2v-mx_se/mainboard.c (working copy)
@@ -29,11 +29,25 @@
int add_mainboard_resources(struct lb_memory *mem)
{
+ extern char _secondary_start[];
+ extern char _secondary_start_end[];
+ unsigned long code_size;
+
#if HAVE_HIGH_TABLES == 1
printk_debug("Adding high table area\n");
lb_add_memory_range(mem, LB_MEM_TABLE,
high_tables_base, high_tables_size);
#endif
+ lb_add_memory_range(mem, LB_MEM_RESERVED,
+ _RAMBASE, ((CONFIG_LB_MEM_TOPK<<10) - _RAMBASE));
+ lb_add_memory_range(mem, LB_MEM_RESERVED,
+ DCACHE_RAM_BASE, DCACHE_RAM_SIZE);
+
+ code_size = (unsigned long)_secondary_start_end - (unsigned long)_secondary_start;
+
+ lb_add_memory_range(mem, LB_MEM_RESERVED,
+ _secondary_start, code_size);
+
return 0;
}
Index: src/mainboard/asus/m2v-mx_se/cache_as_ram_auto.c
===================================================================
--- src/mainboard/asus/m2v-mx_se/cache_as_ram_auto.c (revision 4030)
+++ src/mainboard/asus/m2v-mx_se/cache_as_ram_auto.c (working copy)
@@ -242,10 +242,12 @@
struct sys_info *sysinfo =
(DCACHE_RAM_BASE + DCACHE_RAM_SIZE - DCACHE_RAM_GLOBAL_VAR_SIZE);
char *p;
+ u8 reg;
sio_init();
it8712f_enable_serial(SERIAL_DEV, TTYS0_BASE);
it8712f_kill_watchdog();
+ it8712f_enable_3vsbsw();
uart_init();
console_init();
enable_rom_decode();
Index: src/boot/hardwaremain.c
===================================================================
--- src/boot/hardwaremain.c (revision 4030)
+++ src/boot/hardwaremain.c (working copy)
@@ -37,6 +37,293 @@
#include <part/init_timer.h>
#include <boot/elf.h>
+//reboot.c from linux
+
+#include <stdint.h>
+#include <string.h>
+#include <arch/io.h>
+#include <console/console.h>
+
+int acpi_is_wakeup_early(void);
+
+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!
+ */
+
+
+static void dump_mem(u32 start, u32 end)
+{
+
+ u32 i;
+ print_debug("dump_mem:");
+ for(i=start;i<end;i++) {
+ if((i & 0xf)==0) {
+ printk_debug("\n%08x:", i);
+ }
+ printk_debug(" %02x", (unsigned char)*((unsigned char *)i));
+ }
+ print_debug("\n");
+ }
+
+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 >> 4) << 16) | (vector & 0xf);
+ 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));
+
+ dump_mem(vector, ((u32) vector) + 4096);
+
+ /* 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;
+}
+
+
/**
* @brief Main function of the DRAM part of coreboot.
*
@@ -46,6 +333,12 @@
* Device Enumeration:
* In the dev_enumerate() phase,
*/
+
+
+ extern u32 wake_vec;
+
+void find_resume_vector(void);
+
void hardwaremain(int boot_complete)
{
struct lb_memory *lb_mem;
@@ -86,8 +379,32 @@
/* Now that we have collected all of our information
* write our configuration tables.
*/
+
+#if 0
+
+{
+ u32 *p = 4*1024;
+ int i;
+
+ printk_debug("RAM check low poison.\r\n");
+
+ for (i=4*1024;i<640*1024;i+=4) {
+ if (p != (*p)) {
+ printk_debug("BAdness at %p data %x\n", p, *p);
+ }
+ p++;
+ }
+
+
+}
+#endif
+
+ find_resume_vector();
+
+ if (wake_vec)
+ acpi_jump_wake(wake_vec);
+
lb_mem = write_tables();
-
#if CONFIG_FS_PAYLOAD == 1
filo(lb_mem);
#else
Index: src/northbridge/amd/amdk8/raminit.c
===================================================================
--- src/northbridge/amd/amdk8/raminit.c (revision 4030)
+++ src/northbridge/amd/amdk8/raminit.c (working copy)
@@ -2262,6 +2262,8 @@
#endif
+#include "exit_from_self.c"
+
#define TIMEOUT_LOOPS 300000
#if RAMINIT_SYSINFO == 1
static void sdram_enable(int controllers, const struct mem_controller *ctrl, struct sys_info *sysinfo)
Index: src/northbridge/amd/amdk8/raminit_f.c
===================================================================
--- src/northbridge/amd/amdk8/raminit_f.c (revision 4030)
+++ src/northbridge/amd/amdk8/raminit_f.c (working copy)
@@ -3008,12 +3008,15 @@
}
#endif
+#include "exit_from_self.c"
static void sdram_enable(int controllers, const struct mem_controller *ctrl,
struct sys_info *sysinfo)
{
int i;
+ int s = acpi_is_wakeup_early();
+
#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1
unsigned cpu_f0_f1[8];
/* FIXME: How about 32 node machine later? */
@@ -3059,6 +3062,14 @@
printk_debug("\n");
#endif
+ /* lets override the rest of the routine */
+ if (s) {
+ printk_debug("Wakeup!\n");
+ exit_from_self(controllers, ctrl, sysinfo);
+ printk_debug("Mem running !\n");
+ return;
+ }
+
for (i = 0; i < controllers; i++) {
uint32_t dcl, dch;
if (!sysinfo->ctrl_present[ i ])
@@ -3192,7 +3203,11 @@
#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1
dqs_timing(controllers, ctrl, tsc0, sysinfo);
#else
+ dump_pci_device_index_wait(ctrl->f2, 0x98);
+
dqs_timing(controllers, ctrl, sysinfo);
+
+ dump_pci_device_index_wait(ctrl->f2, 0x98);
#endif
#else
@@ -3205,7 +3220,6 @@
/* Skip everything if I don't have any memory on this controller */
if (sysinfo->mem_trained[i]!=0x80)
continue;
-
dqs_timing(i, &ctrl[i], sysinfo, 1);
#if MEM_TRAIN_SEQ == 1
@@ -3225,7 +3239,6 @@
}
-
static void fill_mem_ctrl(int controllers, struct mem_controller *ctrl_a,
const uint16_t *spd_addr)
{
Index: src/northbridge/amd/amdk8/raminit_f_dqs.c
===================================================================
--- src/northbridge/amd/amdk8/raminit_f_dqs.c (revision 4030)
+++ src/northbridge/amd/amdk8/raminit_f_dqs.c (working copy)
@@ -1824,7 +1824,131 @@
#if MEM_TRAIN_SEQ == 0
+#define NVRAM_BASE 0xf00
+
+int save_nvram(u32 dword, int size, int nvram_pos) {
+printk_debug("Writing %x of size %d to nvram pos: %d\n", dword, size, nvram_pos);
+switch (size) {
+ case 1:
+ outb((dword & 0xff), NVRAM_BASE+nvram_pos);
+ nvram_pos +=1;
+ break;
+ case 2:
+ outw((dword & 0xffff), NVRAM_BASE+nvram_pos);
+ nvram_pos +=2;
+ break;
+ default:
+ outl(dword, NVRAM_BASE+nvram_pos);
+ nvram_pos +=4;
+ break;
+}
+return nvram_pos;
+}
+
+int load_nvram(int size, u32 *old_dword, int nvram_pos) {
+
+switch (size) {
+ case 1:
+ *old_dword &= ~0xff;
+ *old_dword |= inb(NVRAM_BASE+nvram_pos);
+ nvram_pos +=1;
+ break;
+ case 2:
+ *old_dword &= ~0xffff;
+ *old_dword |= inw(NVRAM_BASE+nvram_pos);
+ nvram_pos +=2;
+ break;
+ default:
+ *old_dword = inl(NVRAM_BASE+nvram_pos);
+ nvram_pos +=4;
+ break;
+}
+printk_debug("Loading %x of size %d to nvram pos:%d\n", * old_dword, size, nvram_pos-size);
+
+return nvram_pos;
+}
+
+int save_index_to_pos(unsigned int dev, int size, int index, int nvram_pos) {
+ u32 dword = pci_read_config32_index_wait(dev, 0x98, index);
+
+ return save_nvram(dword, size, nvram_pos);
+}
+
+int load_index_to_pos(unsigned int dev, int size, int index, int nvram_pos) {
+
+ u32 old_dword = pci_read_config32_index_wait(dev, 0x98, index);
+ nvram_pos = load_nvram(size, &old_dword, nvram_pos);
+ pci_write_config32_index_wait(dev, 0x98, index, old_dword);
+ return nvram_pos;
+}
+
+int dqs_load_MC_NVRAM_ch(unsigned int dev, int ch, int pos) {
+ /* 30 bytes per channel */
+ ch *= 0x20;
+ pos = load_index_to_pos(dev, 4, 0x00 + ch, pos);
+ pos = load_index_to_pos(dev, 4, 0x01 + ch, pos);
+ pos = load_index_to_pos(dev, 4, 0x02 + ch, pos);
+ pos = load_index_to_pos(dev, 1, 0x03 + ch, pos);
+ pos = load_index_to_pos(dev, 4, 0x04 + ch, pos);
+ pos = load_index_to_pos(dev, 4, 0x05 + ch, pos);
+ pos = load_index_to_pos(dev, 4, 0x06 + ch, pos);
+ pos = load_index_to_pos(dev, 1, 0x07 + ch, pos);
+ pos = load_index_to_pos(dev, 1, 0x10 + ch, pos);
+ pos = load_index_to_pos(dev, 1, 0x13 + ch, pos);
+ pos = load_index_to_pos(dev, 1, 0x16 + ch, pos);
+ pos = load_index_to_pos(dev, 1, 0x19 + ch, pos);
+ return pos;
+}
+
+
+
+int dqs_save_MC_NVRAM_ch(unsigned int dev, int ch, int pos) {
+ /* 30 bytes per channel */
+ ch *= 0x20;
+ pos = save_index_to_pos(dev, 4, 0x00 + ch, pos);
+ pos = save_index_to_pos(dev, 4, 0x01 + ch, pos);
+ pos = save_index_to_pos(dev, 4, 0x02 + ch, pos);
+ pos = save_index_to_pos(dev, 1, 0x03 + ch, pos);
+ pos = save_index_to_pos(dev, 4, 0x04 + ch, pos);
+ pos = save_index_to_pos(dev, 4, 0x05 + ch, pos);
+ pos = save_index_to_pos(dev, 4, 0x06 + ch, pos);
+ pos = save_index_to_pos(dev, 1, 0x07 + ch, pos);
+ pos = save_index_to_pos(dev, 1, 0x10 + ch, pos);
+ pos = save_index_to_pos(dev, 1, 0x13 + ch, pos);
+ pos = save_index_to_pos(dev, 1, 0x16 + ch, pos);
+ pos = save_index_to_pos(dev, 1, 0x19 + ch, pos);
+ return pos;
+}
+
+void dqs_save_MC_NVRAM(unsigned int dev) {
+int pos = 0;
+u32 reg;
+printk_debug("DQS SAVE NVRAM: %x\n", dev);
+pos = dqs_save_MC_NVRAM_ch(dev, 0, pos);
+pos = dqs_save_MC_NVRAM_ch(dev, 1, pos);
+/* save the maxasync lat here */
+ reg = pci_read_config32(dev, DRAM_CONFIG_HIGH);
+ pos = save_nvram(reg, 4, pos);
+// reg &= ~(DCH_MaxAsyncLat_MASK <<DCH_MaxAsyncLat_SHIFT);
+// reg |= ((dly - DCH_MaxAsyncLat_BASE) << DCH_MaxAsyncLat_SHIFT);
+// pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, reg);
+}
+
+void dqs_restore_MC_NVRAM(unsigned int dev) {
+ int pos = 0;
+ u32 reg;
+
+printk_debug("DQS RESTORE FROM NVRAM: %x\n", dev);
+ pos = dqs_load_MC_NVRAM_ch(dev, 0, pos);
+ pos = dqs_load_MC_NVRAM_ch(dev, 1, pos);
+ /* save the maxasync lat here */
+ pos = load_nvram(4, ®, pos);
+ reg &= (DCH_MaxAsyncLat_MASK <<DCH_MaxAsyncLat_SHIFT);
+ reg |= pci_read_config32(dev, DRAM_CONFIG_HIGH);
+ pci_write_config32(dev, DRAM_CONFIG_HIGH, reg);
+}
+
#if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1
static void dqs_timing(int controllers, const struct mem_controller *ctrl, tsc_t *tsc0, struct sys_info *sysinfo)
#else
@@ -1832,7 +1956,6 @@
#endif
{
int i;
-
tsc_t tsc[5];
//need to enable mtrr, so dqs training could access the test address
@@ -1891,13 +2014,13 @@
if(train_DqsRcvrEn(ctrl+i, 2, sysinfo)) goto out;
printk_debug(" done\r\n");
sysinfo->mem_trained[i]=1;
+ dqs_save_MC_NVRAM((ctrl+i)->f2);
}
out:
tsc[4] = rdtsc();
clear_mtrr_dqs(sysinfo->tom2_k);
-
for(i=0;i<5;i++) {
print_debug_dqs_tsc_x("DQS Training:tsc", i, tsc[i].hi, tsc[i].lo);
}
Index: src/arch/i386/boot/acpi.c
===================================================================
--- src/arch/i386/boot/acpi.c (revision 4030)
+++ src/arch/i386/boot/acpi.c (working copy)
@@ -324,14 +324,43 @@
header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
}
+
+
+u32 wake_vec;
+
+
+extern u8 acpi_sleep_type;
+
+int acpi_is_wakeup(void) {
+ return (acpi_sleep_type == 3);
+}
+
+/* FIXME */
+#warning HACK!
+acpi_facs_t *facs = 0x1BFF0080;
+void find_resume_vector()
+{
+ if (acpi_is_wakeup()) {
+ wake_vec = facs->firmware_waking_vector;
+ printk_debug("OS waking vector is %x\n", wake_vec);
+ } else {
+ wake_vec = 0;
+ }
+}
+
+
void acpi_create_facs(acpi_facs_t *facs)
{
+
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;
+ wake_vec = 0;
+
facs->global_lock = 0;
facs->flags = 0;
facs->x_firmware_waking_vector_l = 0;
Index: targets/asus/m2v-mx_se/Config.lb
===================================================================
--- targets/asus/m2v-mx_se/Config.lb (revision 4030)
+++ targets/asus/m2v-mx_se/Config.lb (working copy)
@@ -21,7 +21,7 @@
mainboard asus/m2v-mx_se
romimage "normal"
- option ROM_SIZE = 512 * 1024
+ option ROM_SIZE = (512 * 1024) - 39424
option USE_FALLBACK_IMAGE = 0
option ROM_IMAGE_SIZE = 128 * 1024
option COREBOOT_EXTRA_VERSION=".0Normal"
s3_stuff.patch.sig
Description: Binary data
-- coreboot mailing list: [email protected] http://www.coreboot.org/mailman/listinfo/coreboot

