Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 1 | #include <console/console.h> |
| 2 | #include <device/device.h> |
Tobias Diedrich | c292467 | 2010-11-09 22:31:11 +0000 | [diff] [blame] | 3 | #include <arch/cpu.h> |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 4 | #include <cpu/x86/mtrr.h> |
| 5 | #include <cpu/amd/mtrr.h> |
| 6 | #include <cpu/x86/cache.h> |
| 7 | #include <cpu/x86/msr.h> |
| 8 | |
Scott Duplichan | f3cce2f | 2010-11-13 19:07:59 +0000 | [diff] [blame] | 9 | #if CONFIG_GFXUMA == 1 |
| 10 | extern uint64_t uma_memory_size; |
| 11 | #endif |
| 12 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 13 | static unsigned long resk(uint64_t value) |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 14 | { |
| 15 | unsigned long resultk; |
| 16 | if (value < (1ULL << 42)) { |
| 17 | resultk = value >> 10; |
| 18 | } |
| 19 | else { |
| 20 | resultk = 0xffffffff; |
| 21 | } |
| 22 | return resultk; |
| 23 | } |
| 24 | |
Eric Biederman | a1653cf | 2004-10-22 04:41:53 +0000 | [diff] [blame] | 25 | static unsigned fixed_mtrr_index(unsigned long addrk) |
| 26 | { |
| 27 | unsigned index; |
| 28 | index = (addrk - 0) >> 6; |
| 29 | if (index >= 8) { |
| 30 | index = ((addrk - 8*64) >> 4) + 8; |
| 31 | } |
| 32 | if (index >= 24) { |
| 33 | index = ((addrk - (8*64 + 16*16)) >> 2) + 24; |
| 34 | } |
| 35 | if (index > NUM_FIXED_RANGES) { |
| 36 | index = NUM_FIXED_RANGES; |
| 37 | } |
| 38 | return index; |
| 39 | } |
| 40 | |
Eric Biederman | a1653cf | 2004-10-22 04:41:53 +0000 | [diff] [blame] | 41 | static unsigned int mtrr_msr[] = { |
| 42 | MTRRfix64K_00000_MSR, MTRRfix16K_80000_MSR, MTRRfix16K_A0000_MSR, |
| 43 | MTRRfix4K_C0000_MSR, MTRRfix4K_C8000_MSR, MTRRfix4K_D0000_MSR, MTRRfix4K_D8000_MSR, |
| 44 | MTRRfix4K_E0000_MSR, MTRRfix4K_E8000_MSR, MTRRfix4K_F0000_MSR, MTRRfix4K_F8000_MSR, |
| 45 | }; |
| 46 | |
| 47 | static void set_fixed_mtrrs(unsigned int first, unsigned int last, unsigned char type) |
| 48 | { |
| 49 | unsigned int i; |
| 50 | unsigned int fixed_msr = NUM_FIXED_RANGES >> 3; |
| 51 | msr_t msr; |
| 52 | msr.lo = msr.hi = 0; /* Shut up gcc */ |
| 53 | for (i = first; i < last; i++) { |
| 54 | /* When I switch to a new msr read it in */ |
| 55 | if (fixed_msr != i >> 3) { |
| 56 | /* But first write out the old msr */ |
| 57 | if (fixed_msr < (NUM_FIXED_RANGES >> 3)) { |
| 58 | disable_cache(); |
| 59 | wrmsr(mtrr_msr[fixed_msr], msr); |
| 60 | enable_cache(); |
| 61 | } |
| 62 | fixed_msr = i>>3; |
| 63 | msr = rdmsr(mtrr_msr[fixed_msr]); |
| 64 | } |
| 65 | if ((i & 7) < 4) { |
| 66 | msr.lo &= ~(0xff << ((i&3)*8)); |
| 67 | msr.lo |= type << ((i&3)*8); |
| 68 | } else { |
| 69 | msr.hi &= ~(0xff << ((i&3)*8)); |
| 70 | msr.hi |= type << ((i&3)*8); |
| 71 | } |
| 72 | } |
| 73 | /* Write out the final msr */ |
| 74 | if (fixed_msr < (NUM_FIXED_RANGES >> 3)) { |
| 75 | disable_cache(); |
| 76 | wrmsr(mtrr_msr[fixed_msr], msr); |
| 77 | enable_cache(); |
| 78 | } |
| 79 | } |
| 80 | |
Eric Biederman | f8a2ddd | 2004-10-30 08:05:41 +0000 | [diff] [blame] | 81 | struct mem_state { |
| 82 | unsigned long mmio_basek, tomk; |
| 83 | }; |
| 84 | static void set_fixed_mtrr_resource(void *gp, struct device *dev, struct resource *res) |
| 85 | { |
| 86 | struct mem_state *state = gp; |
| 87 | unsigned long topk; |
| 88 | unsigned int start_mtrr; |
| 89 | unsigned int last_mtrr; |
| 90 | |
| 91 | topk = resk(res->base + res->size); |
| 92 | if (state->tomk < topk) { |
| 93 | state->tomk = topk; |
| 94 | } |
| 95 | if ((topk < 4*1024*1024) && (state->mmio_basek < topk)) { |
| 96 | state->mmio_basek = topk; |
| 97 | } |
| 98 | start_mtrr = fixed_mtrr_index(resk(res->base)); |
| 99 | last_mtrr = fixed_mtrr_index(resk((res->base + res->size))); |
| 100 | if (start_mtrr >= NUM_FIXED_RANGES) { |
| 101 | return; |
| 102 | } |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 103 | printk(BIOS_DEBUG, "Setting fixed MTRRs(%d-%d) Type: WB, RdMEM, WrMEM\n", |
Yinghai Lu | 13f1c2a | 2005-07-08 02:49:49 +0000 | [diff] [blame] | 104 | start_mtrr, last_mtrr); |
Eric Biederman | f8a2ddd | 2004-10-30 08:05:41 +0000 | [diff] [blame] | 105 | set_fixed_mtrrs(start_mtrr, last_mtrr, MTRR_TYPE_WRBACK | MTRR_READ_MEM | MTRR_WRITE_MEM); |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 106 | |
Eric Biederman | f8a2ddd | 2004-10-30 08:05:41 +0000 | [diff] [blame] | 107 | } |
| 108 | |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 109 | void amd_setup_mtrrs(void) |
| 110 | { |
Yinghai Lu | 13f1c2a | 2005-07-08 02:49:49 +0000 | [diff] [blame] | 111 | unsigned long address_bits; |
Eric Biederman | f8a2ddd | 2004-10-30 08:05:41 +0000 | [diff] [blame] | 112 | struct mem_state state; |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 113 | unsigned long i; |
Scott Duplichan | f3cce2f | 2010-11-13 19:07:59 +0000 | [diff] [blame] | 114 | msr_t msr, sys_cfg; |
Oskar Enoksson | 07bf911 | 2011-10-06 18:21:19 +0200 | [diff] [blame] | 115 | // Test if this CPU is a Fam 0Fh rev. F or later |
| 116 | const int cpu_id = cpuid_eax(0x80000001); |
Marc Jones | d8d8c63 | 2012-01-30 19:30:45 -0700 | [diff] [blame^] | 117 | printk(BIOS_SPEW, "CPU ID 0x80000001: %x\n", cpu_id); |
Oskar Enoksson | 07bf911 | 2011-10-06 18:21:19 +0200 | [diff] [blame] | 118 | const int has_tom2wb = |
Marc Jones | d8d8c63 | 2012-01-30 19:30:45 -0700 | [diff] [blame^] | 119 | (((cpu_id>>20 )&0xf) > 0) || // ExtendedFamily > 0 |
Oskar Enoksson | 07bf911 | 2011-10-06 18:21:19 +0200 | [diff] [blame] | 120 | ((((cpu_id>>8 )&0xf) == 0xf) && // Family == 0F |
| 121 | (((cpu_id>>16)&0xf) >= 0x4)); // Rev>=F deduced from rev tables |
| 122 | if(has_tom2wb) |
Marc Jones | d8d8c63 | 2012-01-30 19:30:45 -0700 | [diff] [blame^] | 123 | printk(BIOS_DEBUG, "CPU is Fam 0Fh rev.F or later. We can use TOM2WB for any memory above 4GB\n"); |
Yinghai Lu | 13f1c2a | 2005-07-08 02:49:49 +0000 | [diff] [blame] | 124 | |
Eric Biederman | a1653cf | 2004-10-22 04:41:53 +0000 | [diff] [blame] | 125 | /* Enable the access to AMD RdDram and WrDram extension bits */ |
Yinghai Lu | 13f1c2a | 2005-07-08 02:49:49 +0000 | [diff] [blame] | 126 | disable_cache(); |
Scott Duplichan | f3cce2f | 2010-11-13 19:07:59 +0000 | [diff] [blame] | 127 | sys_cfg = rdmsr(SYSCFG_MSR); |
| 128 | sys_cfg.lo |= SYSCFG_MSR_MtrrFixDramModEn; |
| 129 | wrmsr(SYSCFG_MSR, sys_cfg); |
Yinghai Lu | 13f1c2a | 2005-07-08 02:49:49 +0000 | [diff] [blame] | 130 | enable_cache(); |
Eric Biederman | f3aa470 | 2004-10-21 02:53:25 +0000 | [diff] [blame] | 131 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 132 | printk(BIOS_DEBUG, "\n"); |
Eric Biederman | a1653cf | 2004-10-22 04:41:53 +0000 | [diff] [blame] | 133 | /* Initialized the fixed_mtrrs to uncached */ |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 134 | printk(BIOS_DEBUG, "Setting fixed MTRRs(%d-%d) type: UC\n", |
Yinghai Lu | 13f1c2a | 2005-07-08 02:49:49 +0000 | [diff] [blame] | 135 | 0, NUM_FIXED_RANGES); |
Eric Biederman | a1653cf | 2004-10-22 04:41:53 +0000 | [diff] [blame] | 136 | set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHEABLE); |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 137 | |
| 138 | /* Except for the PCI MMIO hole just before 4GB there are no |
| 139 | * significant holes in the address space, so just account |
| 140 | * for those two and move on. |
| 141 | */ |
Eric Biederman | f8a2ddd | 2004-10-30 08:05:41 +0000 | [diff] [blame] | 142 | state.mmio_basek = state.tomk = 0; |
| 143 | search_global_resources( |
| 144 | IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE, |
| 145 | set_fixed_mtrr_resource, &state); |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 146 | printk(BIOS_DEBUG, "DONE fixed MTRRs\n"); |
Yinghai Lu | 13f1c2a | 2005-07-08 02:49:49 +0000 | [diff] [blame] | 147 | |
Eric Biederman | f8a2ddd | 2004-10-30 08:05:41 +0000 | [diff] [blame] | 148 | if (state.mmio_basek > state.tomk) { |
| 149 | state.mmio_basek = state.tomk; |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 150 | } |
Eric Biederman | f8a2ddd | 2004-10-30 08:05:41 +0000 | [diff] [blame] | 151 | /* Round state.mmio_basek down to the nearst size that will fit in TOP_MEM */ |
| 152 | state.mmio_basek = state.mmio_basek & ~TOP_MEM_MASK_KB; |
| 153 | /* Round state.tomk up to the next greater size that will fit in TOP_MEM */ |
| 154 | state.tomk = (state.tomk + TOP_MEM_MASK_KB) & ~TOP_MEM_MASK_KB; |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 155 | |
| 156 | disable_cache(); |
| 157 | |
| 158 | /* Setup TOP_MEM */ |
Eric Biederman | f8a2ddd | 2004-10-30 08:05:41 +0000 | [diff] [blame] | 159 | msr.hi = state.mmio_basek >> 22; |
| 160 | msr.lo = state.mmio_basek << 10; |
Scott Duplichan | f3cce2f | 2010-11-13 19:07:59 +0000 | [diff] [blame] | 161 | |
| 162 | /* If UMA graphics is enabled, the frame buffer memory |
| 163 | * has been deducted from the size of memory below 4GB. |
| 164 | * When setting TOM, include UMA DRAM |
| 165 | */ |
| 166 | #if CONFIG_GFXUMA == 1 |
| 167 | msr.lo += uma_memory_size; |
| 168 | #endif |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 169 | wrmsr(TOP_MEM, msr); |
| 170 | |
Scott Duplichan | f3cce2f | 2010-11-13 19:07:59 +0000 | [diff] [blame] | 171 | sys_cfg.lo &= ~(SYSCFG_MSR_TOM2En | SYSCFG_MSR_TOM2WB); |
Yinghai Lu | d4b278c | 2006-10-04 20:46:15 +0000 | [diff] [blame] | 172 | if(state.tomk > (4*1024*1024)) { |
Scott Duplichan | f3cce2f | 2010-11-13 19:07:59 +0000 | [diff] [blame] | 173 | /* DRAM above 4GB: set TOM2, SYSCFG_MSR_TOM2En |
| 174 | * and SYSCFG_MSR_TOM2WB |
| 175 | */ |
Yinghai Lu | 3057660 | 2005-12-14 20:16:49 +0000 | [diff] [blame] | 176 | msr.hi = state.tomk >> 22; |
| 177 | msr.lo = state.tomk << 10; |
| 178 | wrmsr(TOP_MEM2, msr); |
Oskar Enoksson | 07bf911 | 2011-10-06 18:21:19 +0200 | [diff] [blame] | 179 | sys_cfg.lo |= SYSCFG_MSR_TOM2En; |
| 180 | if(has_tom2wb) |
| 181 | sys_cfg.lo |= SYSCFG_MSR_TOM2WB; |
Yinghai Lu | 3057660 | 2005-12-14 20:16:49 +0000 | [diff] [blame] | 182 | } |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 183 | |
| 184 | /* zero the IORR's before we enable to prevent |
| 185 | * undefined side effects. |
| 186 | */ |
| 187 | msr.lo = msr.hi = 0; |
| 188 | for(i = IORR_FIRST; i <= IORR_LAST; i++) { |
| 189 | wrmsr(i, msr); |
| 190 | } |
| 191 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 192 | /* Enable Variable Mtrrs |
Eric Biederman | a1653cf | 2004-10-22 04:41:53 +0000 | [diff] [blame] | 193 | * Enable the RdMem and WrMem bits in the fixed mtrrs. |
| 194 | * Disable access to the RdMem and WrMem in the fixed mtrr. |
| 195 | */ |
Scott Duplichan | f3cce2f | 2010-11-13 19:07:59 +0000 | [diff] [blame] | 196 | sys_cfg.lo |= SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn; |
| 197 | sys_cfg.lo &= ~SYSCFG_MSR_MtrrFixDramModEn; |
| 198 | wrmsr(SYSCFG_MSR, sys_cfg); |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 199 | |
Yinghai Lu | 13f1c2a | 2005-07-08 02:49:49 +0000 | [diff] [blame] | 200 | enable_fixed_mtrr(); |
| 201 | |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 202 | enable_cache(); |
Eric Biederman | a1653cf | 2004-10-22 04:41:53 +0000 | [diff] [blame] | 203 | |
Stefan Reinauer | 0867062 | 2009-06-30 15:17:49 +0000 | [diff] [blame] | 204 | address_bits = CONFIG_CPU_ADDR_BITS; //K8 could be 40, and GH could be 48 |
Yinghai Lu | 13f1c2a | 2005-07-08 02:49:49 +0000 | [diff] [blame] | 205 | |
Tobias Diedrich | c292467 | 2010-11-09 22:31:11 +0000 | [diff] [blame] | 206 | /* AMD specific cpuid function to query number of address bits */ |
| 207 | if (cpuid_eax(0x80000000) >= 0x80000008) { |
| 208 | address_bits = cpuid_eax(0x80000008) & 0xff; |
| 209 | } |
| 210 | |
Eric Biederman | a1653cf | 2004-10-22 04:41:53 +0000 | [diff] [blame] | 211 | /* Now that I have mapped what is memory and what is not |
| 212 | * Setup the mtrrs so we can cache the memory. |
| 213 | */ |
Oskar Enoksson | 07bf911 | 2011-10-06 18:21:19 +0200 | [diff] [blame] | 214 | |
| 215 | // Rev. F K8 supports has SYSCFG_MSR_TOM2WB and dont need |
| 216 | // variable MTRR to span memory above 4GB |
| 217 | // Lower revisions K8 need variable MTRR over 4GB |
| 218 | x86_setup_var_mtrrs(address_bits, has_tom2wb ? 0 : 1); |
Eric Biederman | fcd5ace | 2004-10-14 19:29:29 +0000 | [diff] [blame] | 219 | } |