| /* 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 "cbmem.h" |
| #include "cpu/amd/car/disable_cache_as_ram.c" |
| #include "cpu/x86/mtrr/earlymtrr.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) { |
| unsigned long high_ram_base; |
| void *resume_backup_memory; |
| int suspend = acpi_is_wakeup_early(); |
| |
| if (!suspend) |
| return NULL; |
| |
| /* Start address of high memory tables */ |
| high_ram_base = (u32) get_cbmem_toc(); |
| |
| print_debug_pcar("CBMEM TOC is at: ", (uint32_t)high_ram_base); |
| print_debug_pcar("CBMEM TOC 0-size: ",(uint32_t)(high_ram_base + HIGH_MEMORY_SIZE + 4096)); |
| |
| cbmem_reinit((u64)high_ram_base); |
| |
| 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 |
| } |
| |
| static void post_cache_as_ram(void) |
| { |
| #if CONFIG_HAVE_ACPI_RESUME |
| void *resume_backup_memory; |
| #endif |
| #if 1 |
| { |
| /* Check value of esp to verify if we have enough rom 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 |
| |
| unsigned testx = 0x5a5a5a5a; |
| print_debug_pcar("testx = ", testx); |
| |
| /* 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 |
| |
| __asm__ volatile ( |
| /* set new esp */ /* before CONFIG_RAMBASE */ |
| "subl %0, %%esp\n\t" |
| ::"a"( (CONFIG_DCACHE_RAM_BASE + CONFIG_DCACHE_RAM_SIZE)- (CONFIG_RAMTOP) ) |
| /* discard all registers (eax is used for %0), so gcc redo everything |
| after the stack is moved */ |
| : "cc", "memory", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp" |
| ); |
| |
| /* We can put data to stack again */ |
| |
| /* only global variable sysinfo in cache need to be offset */ |
| print_debug("Done\n"); |
| print_debug_pcar("testx = ", testx); |
| |
| 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"); |
| } |