Vladimir Serbinenko | 2a19fb1 | 2014-10-02 20:09:19 +0200 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 4 | * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. |
Vladimir Serbinenko | 2a19fb1 | 2014-10-02 20:09:19 +0200 | [diff] [blame] | 5 | * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz> |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 6 | * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering |
Vladimir Serbinenko | 2a19fb1 | 2014-10-02 20:09:19 +0200 | [diff] [blame] | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by |
| 10 | * the Free Software Foundation; version 2 of the License. |
| 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | * GNU General Public License for more details. |
Vladimir Serbinenko | 2a19fb1 | 2014-10-02 20:09:19 +0200 | [diff] [blame] | 16 | */ |
| 17 | |
| 18 | #include <console/console.h> |
| 19 | #include <stdint.h> |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 20 | #include <option.h> |
Vladimir Serbinenko | 2a19fb1 | 2014-10-02 20:09:19 +0200 | [diff] [blame] | 21 | #include <cpu/x86/msr.h> |
| 22 | #include <arch/acpigen.h> |
| 23 | #include <cpu/amd/powernow.h> |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 24 | #include <device/pci.h> |
| 25 | #include <device/pci_ids.h> |
| 26 | #include <cpu/x86/msr.h> |
| 27 | #include <cpu/amd/mtrr.h> |
| 28 | #include <cpu/amd/amdfam10_sysconf.h> |
| 29 | #include <arch/cpu.h> |
| 30 | #include <northbridge/amd/amdht/AsPsDefs.h> |
Timothy Pearson | ead8751 | 2015-02-20 12:47:52 -0600 | [diff] [blame] | 31 | #include <northbridge/amd/amdmct/mct/mct.h> |
| 32 | #include <northbridge/amd/amdmct/amddefs.h> |
Vladimir Serbinenko | 2a19fb1 | 2014-10-02 20:09:19 +0200 | [diff] [blame] | 33 | |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 34 | static inline uint8_t is_fam15h(void) |
| 35 | { |
| 36 | uint8_t fam15h = 0; |
| 37 | uint32_t family; |
| 38 | |
| 39 | family = cpuid_eax(0x80000001); |
| 40 | family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8); |
| 41 | |
| 42 | if (family >= 0x6f) |
| 43 | /* Family 15h or later */ |
| 44 | fam15h = 1; |
| 45 | |
| 46 | return fam15h; |
| 47 | } |
| 48 | |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 49 | static void write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u32 *pstate_power, |
| 50 | u32 *pstate_latency, u32 *pstate_control, |
| 51 | u32 *pstate_status, int coreID, |
Timothy Pearson | ef33db0 | 2015-05-08 00:32:47 -0500 | [diff] [blame] | 52 | uint8_t single_link) |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 53 | { |
| 54 | int i; |
Timothy Pearson | ef33db0 | 2015-05-08 00:32:47 -0500 | [diff] [blame] | 55 | struct cpuid_result cpuid1; |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 56 | |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 57 | acpigen_write_empty_PCT(); |
| 58 | acpigen_write_name("_PSS"); |
| 59 | |
| 60 | /* add later to total sum */ |
| 61 | acpigen_write_package(pstate_num); |
| 62 | |
| 63 | for (i = 0;i < pstate_num; i++) |
| 64 | acpigen_write_PSS_package(pstate_feq[i], |
| 65 | pstate_power[i], |
| 66 | pstate_latency[i], |
| 67 | pstate_latency[i], |
| 68 | pstate_control[i], |
| 69 | pstate_status[i]); |
| 70 | |
| 71 | /* update the package size */ |
| 72 | acpigen_pop_len(); |
| 73 | |
Timothy Pearson | ef33db0 | 2015-05-08 00:32:47 -0500 | [diff] [blame] | 74 | /* Write PPC object */ |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 75 | acpigen_write_PPC(pstate_num); |
Timothy Pearson | ef33db0 | 2015-05-08 00:32:47 -0500 | [diff] [blame] | 76 | |
| 77 | /* Write PSD indicating coordination type */ |
| 78 | if ((single_link) && (mctGetLogicalCPUID(0) & AMD_DR_GT_Bx)) { |
| 79 | /* Revision C or greater single-link processor */ |
| 80 | cpuid1 = cpuid(0x80000008); |
| 81 | acpigen_write_PSD_package(0, (cpuid1.ecx & 0xff) + 1, SW_ALL); |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 82 | } else { |
Timothy Pearson | ef33db0 | 2015-05-08 00:32:47 -0500 | [diff] [blame] | 83 | /* Find the local APIC ID for the specified core ID */ |
| 84 | struct device* cpu; |
| 85 | int cpu_index = 0; |
| 86 | for (cpu = all_devices; cpu; cpu = cpu->next) { |
| 87 | if ((cpu->path.type != DEVICE_PATH_APIC) || |
| 88 | (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) |
| 89 | continue; |
| 90 | if (!cpu->enabled) |
| 91 | continue; |
| 92 | if (cpu_index == coreID) |
| 93 | break; |
| 94 | cpu_index++; |
| 95 | } |
| 96 | |
| 97 | if (cpu) |
| 98 | acpigen_write_PSD_package(cpu->path.apic.apic_id, 1, SW_ANY); |
| 99 | } |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 100 | } |
Timothy Pearson | ef33db0 | 2015-05-08 00:32:47 -0500 | [diff] [blame] | 101 | |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 102 | static void write_cstates_for_core(int coreID) |
| 103 | { |
| 104 | /* Generate C state entries */ |
| 105 | uint8_t cstate_count = 1; |
| 106 | acpi_cstate_t cstate; |
| 107 | |
| 108 | if (is_fam15h()) { |
| 109 | cstate.ctype = 2; |
| 110 | cstate.latency = 100; |
| 111 | cstate.power = 0; |
| 112 | cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO; |
| 113 | cstate.resource.bit_width = 8; |
| 114 | cstate.resource.bit_offset = 0; |
| 115 | cstate.resource.addrl = rdmsr(0xc0010073).lo + 1; |
| 116 | cstate.resource.addrh = 0; |
| 117 | cstate.resource.resv = 1; |
| 118 | } else { |
| 119 | cstate.ctype = 2; |
| 120 | cstate.latency = 75; |
| 121 | cstate.power = 0; |
| 122 | cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO; |
| 123 | cstate.resource.bit_width = 8; |
| 124 | cstate.resource.bit_offset = 0; |
| 125 | cstate.resource.addrl = rdmsr(0xc0010073).lo; |
| 126 | cstate.resource.addrh = 0; |
| 127 | cstate.resource.resv = 1; |
| 128 | } |
| 129 | |
| 130 | acpigen_write_CST_package(&cstate, cstate_count); |
| 131 | |
| 132 | /* Find the local APIC ID for the specified core ID */ |
| 133 | if (is_fam15h()) { |
| 134 | struct device* cpu; |
| 135 | int cpu_index = 0; |
| 136 | for (cpu = all_devices; cpu; cpu = cpu->next) { |
| 137 | if ((cpu->path.type != DEVICE_PATH_APIC) || |
| 138 | (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) |
| 139 | continue; |
| 140 | if (!cpu->enabled) |
| 141 | continue; |
| 142 | if (cpu_index == coreID) |
| 143 | break; |
| 144 | cpu_index++; |
| 145 | } |
| 146 | |
| 147 | if (cpu) { |
| 148 | /* TODO |
| 149 | * Detect dual core status and skip CSD generation if dual core is disabled |
| 150 | */ |
| 151 | |
| 152 | /* Generate C state dependency entries */ |
| 153 | acpigen_write_CSD_package((cpu->path.apic.apic_id >> 1) & 0x7f, 2, CSD_HW_ALL, 0); |
| 154 | } |
| 155 | } |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 156 | } |
| 157 | |
| 158 | /* |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 159 | * For details of this algorithm, please refer to: |
| 160 | * Family 10h BDKG 3.62 page 69 |
| 161 | * Family 15h BDKG 3.14 page 74 |
Timothy Pearson | 6fdb4d5 | 2015-02-10 21:15:39 -0600 | [diff] [blame] | 162 | * |
| 163 | * WARNING: The core count algorithm below assumes that all processors |
| 164 | * are identical, with the same number of active cores. While the BKDG |
| 165 | * states the BIOS must enforce this coreboot does not currently do so. |
| 166 | * As a result it is possible that this code may break if an illegal |
| 167 | * processor combination is installed. If it does break please fix the |
| 168 | * code in the proper locations! |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 169 | */ |
Patrick Georgi | a425b96 | 2015-03-05 20:18:21 +0100 | [diff] [blame] | 170 | void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 171 | { |
| 172 | u8 processor_brand[49]; |
| 173 | u32 *v; |
| 174 | struct cpuid_result cpuid1; |
| 175 | |
| 176 | u16 Pstate_feq[10]; |
| 177 | u32 Pstate_power[10]; |
| 178 | u32 Pstate_latency[10]; |
| 179 | u32 Pstate_control[10]; |
| 180 | u32 Pstate_status[10]; |
| 181 | u8 Pstate_num; |
| 182 | u8 cmp_cap; |
| 183 | u8 index; |
| 184 | msr_t msr; |
| 185 | |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 186 | uint8_t nvram; |
| 187 | uint8_t enable_c_states; |
| 188 | |
| 189 | enable_c_states = 0; |
| 190 | #if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) |
| 191 | if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS) |
| 192 | enable_c_states = !!nvram; |
| 193 | #endif |
| 194 | |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 195 | /* Get the Processor Brand String using cpuid(0x8000000x) command x=2,3,4 */ |
| 196 | cpuid1 = cpuid(0x80000002); |
| 197 | v = (u32 *) processor_brand; |
| 198 | v[0] = cpuid1.eax; |
| 199 | v[1] = cpuid1.ebx; |
| 200 | v[2] = cpuid1.ecx; |
| 201 | v[3] = cpuid1.edx; |
| 202 | cpuid1 = cpuid(0x80000003); |
| 203 | v[4] = cpuid1.eax; |
| 204 | v[5] = cpuid1.ebx; |
| 205 | v[6] = cpuid1.ecx; |
| 206 | v[7] = cpuid1.edx; |
| 207 | cpuid1 = cpuid(0x80000004); |
| 208 | v[8] = cpuid1.eax; |
| 209 | v[9] = cpuid1.ebx; |
| 210 | v[10] = cpuid1.ecx; |
| 211 | v[11] = cpuid1.edx; |
| 212 | processor_brand[48] = 0; |
| 213 | printk(BIOS_INFO, "processor_brand=%s\n", processor_brand); |
| 214 | |
Timothy Pearson | 6fdb4d5 | 2015-02-10 21:15:39 -0600 | [diff] [blame] | 215 | uint32_t dtemp; |
Timothy Pearson | 066980c | 2015-05-08 17:17:44 -0500 | [diff] [blame] | 216 | uint8_t node_index; |
Timothy Pearson | 6fdb4d5 | 2015-02-10 21:15:39 -0600 | [diff] [blame] | 217 | uint8_t node_count; |
Timothy Pearson | 066980c | 2015-05-08 17:17:44 -0500 | [diff] [blame] | 218 | uint8_t cores_per_node; |
| 219 | uint8_t total_core_count; |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 220 | uint8_t fam15h; |
| 221 | uint8_t fam10h_rev_e = 0; |
| 222 | |
| 223 | /* Detect Revision E processors via method used in fidvid.c */ |
| 224 | if ((cpuid_edx(0x80000007) & CPB_MASK) |
| 225 | && ((cpuid_ecx(0x80000008) & NC_MASK) == 5)) |
| 226 | fam10h_rev_e = 1; |
Timothy Pearson | 6fdb4d5 | 2015-02-10 21:15:39 -0600 | [diff] [blame] | 227 | |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 228 | /* |
| 229 | * Based on the CPU socket type,cmp_cap and pwr_lmt , get the power limit. |
| 230 | * socket_type : 0x10 SocketF; 0x11 AM2/ASB1 ; 0x12 S1G1 |
Timothy Pearson | 6fdb4d5 | 2015-02-10 21:15:39 -0600 | [diff] [blame] | 231 | * cmp_cap : 0x0 SingleCore ; 0x1 DualCore ; 0x2 TripleCore ; 0x3 QuadCore ; 0x4 QuintupleCore ; 0x5 HexCore |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 232 | */ |
Timothy Pearson | 6fdb4d5 | 2015-02-10 21:15:39 -0600 | [diff] [blame] | 233 | printk(BIOS_INFO, "Pstates algorithm ...\n"); |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 234 | fam15h = !!(mctGetLogicalCPUID(0) & AMD_FAM15_ALL); |
Timothy Pearson | 6fdb4d5 | 2015-02-10 21:15:39 -0600 | [diff] [blame] | 235 | /* Get number of cores */ |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 236 | if (fam15h) { |
| 237 | cmp_cap = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 5)), 0x84) & 0xff; |
| 238 | } else { |
| 239 | dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xe8); |
| 240 | cmp_cap = (dtemp & 0x3000) >> 12; |
| 241 | if (mctGetLogicalCPUID(0) & (AMD_FAM10_REV_D | AMD_FAM15_ALL)) /* revision D or higher */ |
| 242 | cmp_cap |= (dtemp & 0x8000) >> 13; |
| 243 | } |
| 244 | |
Timothy Pearson | 6fdb4d5 | 2015-02-10 21:15:39 -0600 | [diff] [blame] | 245 | /* Get number of nodes */ |
| 246 | dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 0)), 0x60); |
| 247 | node_count = ((dtemp & 0x70) >> 4) + 1; |
Timothy Pearson | 066980c | 2015-05-08 17:17:44 -0500 | [diff] [blame] | 248 | cores_per_node = cmp_cap + 1; |
| 249 | |
Timothy Pearson | 6fdb4d5 | 2015-02-10 21:15:39 -0600 | [diff] [blame] | 250 | /* Compute total number of cores installed in system */ |
Timothy Pearson | 066980c | 2015-05-08 17:17:44 -0500 | [diff] [blame] | 251 | total_core_count = cores_per_node * node_count; |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 252 | |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 253 | /* Get number of boost states */ |
| 254 | uint8_t boost_count = 0; |
| 255 | dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 4)), 0x15c); |
| 256 | if (fam10h_rev_e) |
| 257 | boost_count = (dtemp >> 2) & 0x1; |
| 258 | else if (mctGetLogicalCPUID(0) & AMD_FAM15_ALL) |
| 259 | boost_count = (dtemp >> 2) & 0x7; |
| 260 | |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 261 | Pstate_num = 0; |
| 262 | |
| 263 | /* See if the CPUID(0x80000007) returned EDX[7]==1b */ |
| 264 | cpuid1 = cpuid(0x80000007); |
| 265 | if ((cpuid1.edx & 0x80) != 0x80) { |
| 266 | printk(BIOS_INFO, "No valid set of P-states\n"); |
Patrick Georgi | 477b4c5 | 2015-02-22 16:21:01 +0100 | [diff] [blame] | 267 | return; |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 268 | } |
| 269 | |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 270 | if (fam15h) |
| 271 | /* Set P_LVL2 P_BLK entry */ |
| 272 | *(((uint8_t *)pcontrol_blk) + 0x04) = (rdmsr(0xc0010073).lo + 1) & 0xff; |
| 273 | |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 274 | uint8_t pviModeFlag; |
| 275 | uint8_t Pstate_max; |
| 276 | uint8_t cpufid; |
| 277 | uint8_t cpudid; |
| 278 | uint8_t cpuvid; |
| 279 | uint8_t cpuidd; |
| 280 | uint8_t cpuidv; |
| 281 | uint8_t power_step_up; |
| 282 | uint8_t power_step_down; |
| 283 | uint8_t pll_lock_time; |
| 284 | uint32_t expanded_cpuidv; |
| 285 | uint32_t core_frequency; |
| 286 | uint32_t core_power; |
| 287 | uint32_t core_latency; |
| 288 | uint32_t core_voltage; /* multiplied by 10000 */ |
Timothy Pearson | ef33db0 | 2015-05-08 00:32:47 -0500 | [diff] [blame] | 289 | uint8_t single_link; |
| 290 | |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 291 | /* Determine if this is a PVI or SVI system */ |
| 292 | dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xA0); |
| 293 | |
| 294 | if (dtemp & PVI_MODE) |
| 295 | pviModeFlag = 1; |
| 296 | else |
| 297 | pviModeFlag = 0; |
| 298 | |
| 299 | /* Get PSmax's index */ |
| 300 | msr = rdmsr(0xC0010061); |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 301 | Pstate_max = (uint8_t) ((msr.lo >> PS_MAX_VAL_SHFT) & ((fam15h)?BIT_MASK_7:BIT_MASK_3)); |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 302 | |
| 303 | /* Determine if all enabled Pstates have the same fidvid */ |
| 304 | uint8_t i; |
| 305 | uint8_t cpufid_prev = (rdmsr(0xC0010064).lo & 0x3f); |
| 306 | uint8_t all_enabled_cores_have_same_cpufid = 1; |
| 307 | for (i = 1; i < Pstate_max; i++) { |
| 308 | cpufid = rdmsr(0xC0010064 + i).lo & 0x3f; |
| 309 | if (cpufid != cpufid_prev) { |
| 310 | all_enabled_cores_have_same_cpufid = 0; |
| 311 | break; |
| 312 | } |
| 313 | } |
| 314 | |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 315 | /* Family 15h uses slightly different PSmax numbering */ |
| 316 | if (fam15h) |
| 317 | Pstate_max++; |
| 318 | |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 319 | /* Populate tables with all Pstate information */ |
| 320 | for (Pstate_num = 0; Pstate_num < Pstate_max; Pstate_num++) { |
| 321 | /* Get power state information */ |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 322 | msr = rdmsr(0xC0010064 + Pstate_num + boost_count); |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 323 | cpufid = (msr.lo & 0x3f); |
| 324 | cpudid = (msr.lo & 0x1c0) >> 6; |
| 325 | cpuvid = (msr.lo & 0xfe00) >> 9; |
| 326 | cpuidd = (msr.hi & 0xff); |
| 327 | cpuidv = (msr.hi & 0x300) >> 8; |
| 328 | core_frequency = (100 * (cpufid + 0x10)) / (0x01 << cpudid); |
| 329 | if (pviModeFlag) { |
| 330 | if (cpuvid >= 0x20) { |
| 331 | core_voltage = 7625 - (((cpuvid - 0x20) * 10000) / 80); |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 332 | } else { |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 333 | core_voltage = 15500 - ((cpuvid * 10000) / 40); |
| 334 | } |
Timothy Pearson | 730a043 | 2015-10-16 13:51:51 -0500 | [diff] [blame] | 335 | } else { |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 336 | cpuvid = cpuvid & 0x7f; |
| 337 | if (cpuvid >= 0x7c) |
| 338 | core_voltage = 0; |
| 339 | else |
| 340 | core_voltage = 15500 - ((cpuvid * 10000) / 80); |
| 341 | } |
| 342 | switch (cpuidv) { |
| 343 | case 0x0: |
| 344 | expanded_cpuidv = 1; |
| 345 | break; |
| 346 | case 0x1: |
| 347 | expanded_cpuidv = 10; |
| 348 | break; |
| 349 | case 0x2: |
| 350 | expanded_cpuidv = 100; |
| 351 | break; |
| 352 | case 0x3: |
| 353 | expanded_cpuidv = 1000; |
| 354 | break; |
Patrick Georgi | aab66b1 | 2015-02-22 16:27:56 +0100 | [diff] [blame] | 355 | default: |
| 356 | printk(BIOS_ERR, "%s:%s:%d: Invalid cpuidv, " |
| 357 | "not generating pstate tables.\n", |
| 358 | __FILE__, __func__, __LINE__); |
| 359 | return; |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 360 | } |
| 361 | core_power = (core_voltage * cpuidd) / (expanded_cpuidv * 10); |
| 362 | |
| 363 | /* Calculate transition latency */ |
| 364 | dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xD4); |
| 365 | power_step_up = (dtemp & 0xf000000) >> 24; |
| 366 | power_step_down = (dtemp & 0xf00000) >> 20; |
| 367 | dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xA0); |
Timothy Pearson | c1f47c1 | 2015-02-06 16:07:53 -0600 | [diff] [blame] | 368 | pll_lock_time = (dtemp & 0x3800) >> 11; |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 369 | if (all_enabled_cores_have_same_cpufid) |
| 370 | core_latency = ((12 * power_step_down) + power_step_up) / 1000; |
| 371 | else |
| 372 | core_latency = (12 * (power_step_down + power_step_up) / 1000) |
| 373 | + pll_lock_time; |
| 374 | |
| 375 | Pstate_feq[Pstate_num] = core_frequency; |
| 376 | Pstate_power[Pstate_num] = core_power; |
| 377 | Pstate_latency[Pstate_num] = core_latency; |
| 378 | Pstate_control[Pstate_num] = Pstate_num; |
| 379 | Pstate_status[Pstate_num] = Pstate_num; |
| 380 | } |
| 381 | |
| 382 | /* Print Pstate frequency, power, and latency */ |
| 383 | for (index = 0; index < Pstate_num; index++) { |
| 384 | printk(BIOS_INFO, "Pstate_freq[%d] = %dMHz\t", index, |
| 385 | Pstate_feq[index]); |
| 386 | printk(BIOS_INFO, "Pstate_power[%d] = %dmw\n", index, |
| 387 | Pstate_power[index]); |
| 388 | printk(BIOS_INFO, "Pstate_latency[%d] = %dus\n", index, |
| 389 | Pstate_latency[index]); |
| 390 | } |
| 391 | |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 392 | /* Enter processor block scope */ |
Patrick Georgi | a425b96 | 2015-03-05 20:18:21 +0100 | [diff] [blame] | 393 | char pscope[] = "\\_PR"; |
Patrick Georgi | a425b96 | 2015-03-05 20:18:21 +0100 | [diff] [blame] | 394 | acpigen_write_scope(pscope); |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 395 | |
Timothy Pearson | 066980c | 2015-05-08 17:17:44 -0500 | [diff] [blame] | 396 | for (index = 0; index < total_core_count; index++) { |
| 397 | /* Determine if this is a single-link processor */ |
| 398 | node_index = 0x18 + (index / cores_per_node); |
| 399 | dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(node_index, 0)), 0x80); |
| 400 | single_link = !!(((dtemp & 0xff00) >> 8) == 0); |
| 401 | |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 402 | /* Enter processor core scope */ |
| 403 | uint8_t plen_cur = plen; |
| 404 | uint32_t pcontrol_blk_cur = pcontrol_blk; |
| 405 | if ((onlyBSP) && (index != 0)) { |
| 406 | plen_cur = 0; |
| 407 | pcontrol_blk_cur = 0; |
| 408 | } |
| 409 | acpigen_write_processor(index, pcontrol_blk_cur, plen_cur); |
| 410 | |
| 411 | /* Write P-state status and dependency objects */ |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 412 | write_pstates_for_core(Pstate_num, Pstate_feq, Pstate_power, |
| 413 | Pstate_latency, Pstate_control, Pstate_status, |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 414 | index, single_link); |
| 415 | |
| 416 | /* Write C-state status and dependency objects */ |
| 417 | if (fam15h && enable_c_states) |
| 418 | write_cstates_for_core(index); |
| 419 | |
| 420 | /* Exit processor core scope */ |
| 421 | acpigen_pop_len(); |
Timothy Pearson | 066980c | 2015-05-08 17:17:44 -0500 | [diff] [blame] | 422 | } |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 423 | |
| 424 | /* Exit processor block scope */ |
Timothy Pearson | 6300b03 | 2015-01-26 17:53:22 -0600 | [diff] [blame] | 425 | acpigen_pop_len(); |
Vladimir Serbinenko | 2a19fb1 | 2014-10-02 20:09:19 +0200 | [diff] [blame] | 426 | } |
Timothy Pearson | 83abd81 | 2015-06-08 19:35:06 -0500 | [diff] [blame] | 427 | |
| 428 | void amd_powernow_update_fadt(acpi_fadt_t * fadt) |
| 429 | { |
| 430 | if (is_fam15h()) { |
| 431 | fadt->p_lvl2_lat = 101; /* NOTE: While the BKDG states this should |
| 432 | * be set to 100, there is no way to meet |
| 433 | * the other FADT requirements. I suspect |
| 434 | * there is an error in the BKDG for ACPI |
| 435 | * 1.x support; disable all FADT-based C |
| 436 | * states > 2... */ |
| 437 | fadt->p_lvl3_lat = 1001; |
| 438 | fadt->flags |= 0x1 << 2; /* FLAGS.PROC_C1 = 1 */ |
| 439 | fadt->flags |= 0x1 << 3; /* FLAGS.P_LVL2_UP = 1 */ |
| 440 | } else { |
| 441 | fadt->cst_cnt = 0; |
| 442 | } |
| 443 | fadt->pstate_cnt = 0; |
| 444 | } |