summaryrefslogtreecommitdiffstats
path: root/src/cpu/amd/car/post_cache_as_ram.c
blob: 81175dade368b95a602896f8fcd9529fe0d873cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* 2005.6 by yhlu
 * 2006.3 yhlu add copy data from CAR to ram
 */
#include <string.h>
#include <arch/stages.h>
#include <cpu/x86/mtrr.h>
#include <cpu/amd/mtrr.h>
#include "cbmem.h"
#include "cpu/amd/car/disable_cache_as_ram.c"

static inline void print_debug_pcar(const char *strval, uint32_t val)
{
	printk(BIOS_DEBUG, "%s%08x\n", strval, val);
}

/* from linux kernel 2.6.32 asm/string_32.h */

static void inline __attribute__((always_inline))  memcopy(void *dest, const void *src, unsigned long bytes)
{
	int d0, d1, d2;
	asm volatile("cld ; rep ; movsl\n\t"
			"movl %4,%%ecx\n\t"
			"andl $3,%%ecx\n\t"
			"jz 1f\n\t"
			"rep ; movsb\n\t"
			"1:"
			: "=&c" (d0), "=&D" (d1), "=&S" (d2)
			: "0" (bytes / 4), "g" (bytes), "1" ((long)dest), "2" ((long)src)
			: "memory", "cc");
}

#if CONFIG_HAVE_ACPI_RESUME

static inline void *backup_resume(void) {
	void *resume_backup_memory;
	int suspend = acpi_is_wakeup_early();

	if (!suspend)
		return NULL;

	if (!cbmem_reinit())
		return NULL;

	resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);

	/* copy 1MB - 64K to high tables ram_base to prevent memory corruption
	 * through stage 2. We could keep stuff like stack and heap in high tables
	 * memory completely, but that's a wonderful clean up task for another
	 * day.
	 */

	if (resume_backup_memory) {
		print_debug_pcar("Will copy coreboot region to: ", (uint32_t) resume_backup_memory);
		/* copy only backup only memory used for CAR */
		memcopy(resume_backup_memory+HIGH_MEMORY_SAVE-CONFIG_DCACHE_RAM_SIZE,
			(void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE),
			 CONFIG_DCACHE_RAM_SIZE); //inline
	}

	return resume_backup_memory;
}
#endif

/* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */

static void vErrata343(void)
{
#ifdef BU_CFG2_MSR
    msr_t msr;
    unsigned int uiMask = 0xFFFFFFF7;

    msr = rdmsr(BU_CFG2_MSR);
    msr.hi &= uiMask; // set bit 35 to 0
    wrmsr(BU_CFG2_MSR, msr);
#endif
}

void cache_as_ram_switch_stack(void *resume_backup_memory);

void post_cache_as_ram(void)
{
	void *resume_backup_memory = NULL;
#if 1
	{
	/* Check value of esp to verify if we have enough room for stack in Cache as RAM */
	unsigned v_esp;
	__asm__ volatile (
		"movl   %%esp, %0\n\t"
		: "=a" (v_esp)
	);
	print_debug_pcar("v_esp=", v_esp);
	}
#endif

	/* copy data from cache as ram to
		ram need to set CONFIG_RAMTOP to 2M and use var mtrr instead.
	 */
#if CONFIG_RAMTOP <= 0x100000
	#error "You need to set CONFIG_RAMTOP greater than 1M"
#endif

#if CONFIG_HAVE_ACPI_RESUME
 	resume_backup_memory = backup_resume();
#endif

	print_debug("Copying data from cache to RAM -- switching to use RAM as stack... ");

	/* from here don't store more data in CAR */
	vErrata343();

	memcopy((void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE), (void *)CONFIG_DCACHE_RAM_BASE, CONFIG_DCACHE_RAM_SIZE); //inline
	cache_as_ram_switch_stack(resume_backup_memory);
}

void
cache_as_ram_new_stack (void *resume_backup_memory);

void
cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused)))
{
	/* We can put data to stack again */

	/* only global variable sysinfo in cache need to be offset */
	print_debug("Done\n");

	print_debug("Disabling cache as ram now \n");

	disable_cache_as_ram_bsp();

	disable_cache();
	set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
	enable_cache();

#if CONFIG_HAVE_ACPI_RESUME
	/* now copy the rest of the area, using the WB method because we already
	   run normal RAM */
	if (resume_backup_memory) {
		memcopy(resume_backup_memory,
				(void *)(CONFIG_RAMBASE),
				(CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE);
	}
#endif

	print_debug("Clearing initial memory region: ");

#if CONFIG_HAVE_ACPI_RESUME
	/* clear only coreboot used region of memory. Note: this may break ECC enabled boards */
	memset((void*) CONFIG_RAMBASE, 0, (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE);
#else
	memset((void*)0, 0, ((CONFIG_RAMTOP) - CONFIG_DCACHE_RAM_SIZE));
#endif
	print_debug("Done\n");

	set_sysinfo_in_ram(1); // So other core0 could start to train mem

	/*copy and execute coreboot_ram */
	copy_and_run();
	/* We will not return */

	print_debug("should not be here -\n");
}