Patchwork preview - suspend/resume S3 on K8 and 785G/710

login
register
about
Submitter Rudolf Marek
Date 2010-12-01 21:20:35
Message ID <4CF6BC23.4090705@assembler.cz>
Download mbox | patch
Permalink /patch/2379/
State Superseded
Headers show

Comments

Rudolf Marek - 2010-12-01 21:20:35
Hi all

attached patch adds the suspend/resume support for socket 939 and AMD 785G/710 
(on asrock board)

The patch is still WIP but works right now. The purpose is just to show how it 
is done.

Signed-off-by: Rudolf Marek <r.marek@assembler.cz>

Proper patches will hopefully follow.

Thanks
Rudolf

Patch

Index: coreboot/src/mainboard/asrock/939a785gmh/Kconfig
===================================================================
--- coreboot.orig/src/mainboard/asrock/939a785gmh/Kconfig	2010-11-30 22:42:28.000000000 +0100
+++ coreboot/src/mainboard/asrock/939a785gmh/Kconfig	2010-11-30 22:42:49.000000000 +0100
@@ -11,6 +11,7 @@ 
 	select SOUTHBRIDGE_AMD_SB700
 	select SUPERIO_WINBOND_W83627DHG
 	select BOARD_HAS_FADT
+	select HAVE_ACPI_RESUME
 	select HAVE_ACPI_TABLES
 	select HAVE_MP_TABLE
 	select HAVE_PIRQ_TABLE
Index: coreboot/src/northbridge/amd/amdk8/raminit.c
===================================================================
--- coreboot.orig/src/northbridge/amd/amdk8/raminit.c	2010-11-30 22:48:02.000000000 +0100
+++ coreboot/src/northbridge/amd/amdk8/raminit.c	2010-11-30 23:15:41.000000000 +0100
@@ -2226,6 +2226,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) {
@@ -2264,6 +2266,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);
@@ -2277,13 +2282,34 @@ 
 			}
 			pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc);
 		}
-		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) {
+			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;
+
+		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);
 	}
 
@@ -2305,19 +2331,22 @@ 
 			if ((loops & 1023) == 0) {
 				printk(BIOS_DEBUG, ".");
 			}
-		} while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS));
+		} while(((dcl & whatWAIT) != 0) && (loops < TIMEOUT_LOOPS));
 		if (loops >= TIMEOUT_LOOPS) {
 			printk(BIOS_DEBUG, " failed\n");
 			continue;
 		}
 
+
 		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) );
+				printk(BIOS_DEBUG, "DCL %x\r\n", dcl);
+			} while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) || 
+					((dcl & DCL_SRS)));
 		}
 
 		printk(BIOS_DEBUG, " done\n");
Index: coreboot/src/southbridge/amd/sb700/sb700.h
===================================================================
--- coreboot.orig/src/southbridge/amd/sb700/sb700.h	2010-11-30 22:33:30.000000000 +0100
+++ coreboot/src/southbridge/amd/sb700/sb700.h	2010-11-30 22:34:34.000000000 +0100
@@ -24,10 +24,21 @@ 
 #include "chip.h"
 
 /* Power management index/data registers */
+#define BIOSRAM_INDEX	0xcd4
+#define BIOSRAM_DATA	0xcd5
 #define PM_INDEX	0xcd6
 #define PM_DATA		0xcd7
 #define PM2_INDEX	0xcd0
 #define PM2_DATA	0xcd1
+ 
+#define SB600_PM_BASE 		0x800
+
+#define ACPI_PM_EVT_BLK		(SB600_PM_BASE + 0x00) /* 4 bytes */
+#define ACPI_PM1_CNT_BLK	(SB600_PM_BASE + 0x04) /* 2 bytes */
+#define ACPI_PMA_CNT_BLK	(SB600_PM_BASE + 0x0F) /* 1 byte */
+#define ACPI_PM_TMR_BLK		(SB600_PM_BASE + 0x18) /* 4 bytes */
+#define ACPI_GPE0_BLK		(SB600_PM_BASE + 0x10) /* 8 bytes */
+#define ACPI_CPU_CONTORL	(SB600_PM_BASE + 0x08) /* 6 bytes */
 
 extern void pm_iowrite(u8 reg, u8 value);
 extern u8 pm_ioread(u8 reg);
Index: coreboot/src/southbridge/amd/sb700/sb700_early_setup.c
===================================================================
--- coreboot.orig/src/southbridge/amd/sb700/sb700_early_setup.c	2010-11-30 22:35:01.000000000 +0100
+++ coreboot/src/southbridge/amd/sb700/sb700_early_setup.c	2010-12-01 21:51:48.000000000 +0100
@@ -40,6 +40,34 @@ 
 	return inb(PM_INDEX + 1);
 }
 
+static void sb700_acpi_init(void) {
+	pmio_write(0x20, ACPI_PM_EVT_BLK & 0xFF);
+	pmio_write(0x21, ACPI_PM_EVT_BLK >> 8);
+	pmio_write(0x22, ACPI_PM1_CNT_BLK & 0xFF);
+	pmio_write(0x23, ACPI_PM1_CNT_BLK >> 8);
+	pmio_write(0x24, ACPI_PM_TMR_BLK & 0xFF);
+	pmio_write(0x25, ACPI_PM_TMR_BLK >> 8);
+	pmio_write(0x28, ACPI_GPE0_BLK & 0xFF);
+	pmio_write(0x29, ACPI_GPE0_BLK >> 8);
+
+	/* CpuControl is in \_PR.CPU0, 6 bytes */
+	pmio_write(0x26, ACPI_CPU_CONTORL & 0xFF);
+	pmio_write(0x27, ACPI_CPU_CONTORL >> 8);
+
+	pmio_write(0x2A, 0);	/* AcpiSmiCmdLo */
+	pmio_write(0x2B, 0);	/* AcpiSmiCmdHi */
+
+	pmio_write(0x2C, ACPI_PMA_CNT_BLK & 0xFF);
+	pmio_write(0x2D, ACPI_PMA_CNT_BLK >> 8);
+
+	pmio_write(0x0E, 1<<3 | 0<<2); /* AcpiDecodeEnable, When set, SB uses
+					* the contents of the PM registers at
+					* index 20-2B to decode ACPI I/O address.
+					* AcpiSmiEn & SmiCmdEn*/
+	pmio_write(0x10, 1<<1 | 1<<3| 1<<5); /* RTC_En_En, TMR_En_En, GBL_EN_EN */
+}
+
+
 /* RPR 2.28: Get SB ASIC Revision. */
 static u8 set_sb700_revision(void)
 {
@@ -610,10 +638,59 @@ 
 {
 	printk(BIOS_INFO, "sb700_early_setup()\n");
 	sb700_por_init();
+	sb700_acpi_init();
 }
 
 static int smbus_read_byte(u32 device, u32 address)
 {
 	return do_smbus_read_byte(SMBUS_IO_BASE, device, address);
 }
+#if 0
+int s3_save_nvram_early(u32 dword, int size, int  nvram_pos) {
+	int i;
+	printk_debug("Writing %x of size %d to nvram pos: %d\n", dword, size, nvram_pos);
+
+	for (i = 0; i<size; i++) {
+		outb(nvram_pos, BIOSRAM_INDEX);
+		outb((dword >>(8 * i)) & 0xff , BIOSRAM_DATA);
+		nvram_pos++;
+	}
+
+	return nvram_pos;
+}
+
+int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos) {
+	u32 data = *old_dword;
+	int i;
+	for (i = 0; i<size; i++) {
+		outb(nvram_pos, BIOSRAM_INDEX);
+		data &= ~(0xff << (i * 8));
+		data |= inb(BIOSRAM_DATA) << (i *8);
+		nvram_pos++;
+	}
+	*old_dword = data;
+	printk_debug("Loading %x of size %d to nvram pos:%d\n", * old_dword, size, nvram_pos-size);
+	return nvram_pos;
+}
+#endif
+static int acpi_is_wakeup_early(void) {
+	u16 tmp;
+	tmp = inw(ACPI_PM1_CNT_BLK);
+	printk(BIOS_DEBUG, "IN TEST WAKEUP %x\n", tmp);
+	return ((tmp & (7 << 10)) >> 10);
+}
+
+#define get_cbmem_toc() ( { struct cbmem_entry *p ;  \
+	int xi; \
+	uint32_t xdata = 0; \
+	int xnvram_pos = 0xfc; \
+	for (xi = 0; xi<4; xi++) { \
+		outb(xnvram_pos, BIOSRAM_INDEX); \
+		xdata &= ~(0xff << (xi * 8));      \
+		xdata |= inb(BIOSRAM_DATA) << (xi *8); \
+		xnvram_pos++;                          \
+	}                                              \
+p = (struct cbmem_entry *) xdata; \
+p; } )
+
 #endif
Index: coreboot/src/southbridge/amd/sb700/sb700_lpc.c
===================================================================
--- coreboot.orig/src/southbridge/amd/sb700/sb700_lpc.c	2010-11-30 22:40:54.000000000 +0100
+++ coreboot/src/southbridge/amd/sb700/sb700_lpc.c	2010-12-01 21:47:45.000000000 +0100
@@ -63,8 +63,37 @@ 
 	byte = pci_read_config8(dev, 0x78);
 	byte &= ~(1 << 1);
 	pci_write_config8(dev, 0x78, byte);
+
+	/* hack, but the whole sb700 startup lacks any device which 
+	   is doing the acpi init */
+#if CONFIG_HAVE_ACPI_RESUME == 1
+extern u8 acpi_slp_type;
+
+	{
+	u16 tmp = inw(ACPI_PM1_CNT_BLK);
+	acpi_slp_type = ((tmp & (7 << 10)) >> 10);
+	printk(BIOS_DEBUG, "SLP_TYP type was %x %x\n", tmp, acpi_slp_type);
+	}
+#endif
+
 }
 
+#include <cbmem.h>
+void set_cbmem_toc(struct cbmem_entry *toc) {
+int i;
+u32 dword = (u32) toc;
+int nvram_pos = 0xfc;
+	for (i = 0; i<4; i++) {
+		outb(nvram_pos, BIOSRAM_INDEX);
+		outb((dword >>(8 * i)) & 0xff , BIOSRAM_DATA);
+		nvram_pos++;
+	}
+
+
+//		outl((u32) toc, K8T890_NVRAM_IO_BASE+K8T890_NVRAM_CBMEM_TOC);
+}
+
+
 static void sb700_lpc_read_resources(device_t dev)
 {
 	struct resource *res;
Index: coreboot/src/mainboard/asrock/939a785gmh/fadt.c
===================================================================
--- coreboot.orig/src/mainboard/asrock/939a785gmh/fadt.c	2010-12-01 00:15:22.000000000 +0100
+++ coreboot/src/mainboard/asrock/939a785gmh/fadt.c	2010-12-01 00:15:36.000000000 +0100
@@ -34,12 +34,13 @@ 
  * registers into 32 bytes limit.
  * */
 
-#define ACPI_PM_EVT_BLK		(pm_base + 0x00) /* 4 bytes */
-#define ACPI_PM1_CNT_BLK	(pm_base + 0x04) /* 2 bytes */
-#define ACPI_PMA_CNT_BLK	(pm_base + 0x0F) /* 1 byte */
-#define ACPI_PM_TMR_BLK		(pm_base + 0x18) /* 4 bytes */
-#define ACPI_GPE0_BLK		(pm_base + 0x10) /* 8 bytes */
-#define ACPI_CPU_CONTORL	(pm_base + 0x08) /* 6 bytes */
+
+//#define ACPI_PM_EVT_BLK		(pm_base + 0x00) /* 4 bytes */
+//#define ACPI_PM1_CNT_BLK	(pm_base + 0x04) /* 2 bytes */
+//#define ACPI_PMA_CNT_BLK	(pm_base + 0x0F) /* 1 byte */
+//#define ACPI_PM_TMR_BLK		(pm_base + 0x18) /* 4 bytes */
+//#define ACPI_GPE0_BLK		(pm_base + 0x10) /* 8 bytes */
+//#define ACPI_CPU_CONTORL	(pm_base + 0x08) /* 6 bytes */
 
 void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
 {
Index: coreboot/src/mainboard/asrock/939a785gmh/romstage.c
===================================================================
--- coreboot.orig/src/mainboard/asrock/939a785gmh/romstage.c	2010-11-30 23:21:01.000000000 +0100
+++ coreboot/src/mainboard/asrock/939a785gmh/romstage.c	2010-11-30 23:30:04.000000000 +0100
@@ -67,11 +67,22 @@ 
 #include "lib/generic_sdram.c"
 #include "resourcemap.c"
 #include "cpu/amd/dualcore/dualcore.c"
+
+
+// Now, this needs to be included because it relies on the symbol
+// __PRE_RAM__ being set during CAR stage (in order to compile the
+// BSS free versions of the functions). Either rewrite the code
+// to be always BSS free, or invent a flag that's better suited than
+// __PRE_RAM__ to determine whether we're in ram init stage (stage 1)
+//
+#include "lib/cbmem.c"
+
 #include "cpu/amd/car/post_cache_as_ram.c"
 #include "cpu/amd/model_fxx/init_cpus.c"
 #include "cpu/amd/model_fxx/fidvid.c"
 #include "northbridge/amd/amdk8/early_ht.c"
 
+
 static void sio_init(void)
 {
 	u8 reg;