1 /* 2 * Copyright (C) 2015 Google, Inc 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 * 6 * Based on code from coreboot 7 */ 8 9 #include <common.h> 10 #include <cpu.h> 11 #include <dm.h> 12 #include <asm/cpu.h> 13 #include <asm/lapic.h> 14 #include <asm/mp.h> 15 #include <asm/msr.h> 16 #include <asm/turbo.h> 17 18 #ifdef CONFIG_SMP 19 static int enable_smis(struct udevice *cpu, void *unused) 20 { 21 return 0; 22 } 23 24 static struct mp_flight_record mp_steps[] = { 25 MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), 26 /* Wait for APs to finish initialization before proceeding. */ 27 MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL), 28 }; 29 30 static int detect_num_cpus(void) 31 { 32 int ecx = 0; 33 34 /* 35 * Use the algorithm described in Intel 64 and IA-32 Architectures 36 * Software Developer's Manual Volume 3 (3A, 3B & 3C): System 37 * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping 38 * of CPUID Extended Topology Leaf. 39 */ 40 while (1) { 41 struct cpuid_result leaf_b; 42 43 leaf_b = cpuid_ext(0xb, ecx); 44 45 /* 46 * Bay Trail doesn't have hyperthreading so just determine the 47 * number of cores by from level type (ecx[15:8] == * 2) 48 */ 49 if ((leaf_b.ecx & 0xff00) == 0x0200) 50 return leaf_b.ebx & 0xffff; 51 ecx++; 52 } 53 } 54 55 static int baytrail_init_cpus(void) 56 { 57 struct mp_params mp_params; 58 59 lapic_setup(); 60 61 mp_params.num_cpus = detect_num_cpus(); 62 mp_params.parallel_microcode_load = 0, 63 mp_params.flight_plan = &mp_steps[0]; 64 mp_params.num_records = ARRAY_SIZE(mp_steps); 65 mp_params.microcode_pointer = 0; 66 67 if (mp_init(&mp_params)) { 68 printf("Warning: MP init failure\n"); 69 return -EIO; 70 } 71 72 return 0; 73 } 74 #endif 75 76 int x86_init_cpus(void) 77 { 78 #ifdef CONFIG_SMP 79 debug("Init additional CPUs\n"); 80 baytrail_init_cpus(); 81 #endif 82 83 return 0; 84 } 85 86 static void set_max_freq(void) 87 { 88 msr_t perf_ctl; 89 msr_t msr; 90 91 /* Enable speed step */ 92 msr = msr_read(MSR_IA32_MISC_ENABLES); 93 msr.lo |= (1 << 16); 94 msr_write(MSR_IA32_MISC_ENABLES, msr); 95 96 /* 97 * Set guaranteed ratio [21:16] from IACORE_RATIOS to bits [15:8] of 98 * the PERF_CTL 99 */ 100 msr = msr_read(MSR_IACORE_RATIOS); 101 perf_ctl.lo = (msr.lo & 0x3f0000) >> 8; 102 103 /* 104 * Set guaranteed vid [21:16] from IACORE_VIDS to bits [7:0] of 105 * the PERF_CTL 106 */ 107 msr = msr_read(MSR_IACORE_VIDS); 108 perf_ctl.lo |= (msr.lo & 0x7f0000) >> 16; 109 perf_ctl.hi = 0; 110 111 msr_write(MSR_IA32_PERF_CTL, perf_ctl); 112 } 113 114 static int cpu_x86_baytrail_probe(struct udevice *dev) 115 { 116 debug("Init BayTrail core\n"); 117 118 /* 119 * On BayTrail the turbo disable bit is actually scoped at the 120 * building-block level, not package. For non-BSP cores that are 121 * within a building block, enable turbo. The cores within the BSP's 122 * building block will just see it already enabled and move on. 123 */ 124 if (lapicid()) 125 turbo_enable(); 126 127 /* Dynamic L2 shrink enable and threshold */ 128 msr_clrsetbits_64(MSR_PMG_CST_CONFIG_CONTROL, 0x3f000f, 0xe0008), 129 130 /* Disable C1E */ 131 msr_clrsetbits_64(MSR_POWER_CTL, 2, 0); 132 msr_setbits_64(MSR_POWER_MISC, 0x44); 133 134 /* Set this core to max frequency ratio */ 135 set_max_freq(); 136 137 return 0; 138 } 139 140 static unsigned bus_freq(void) 141 { 142 msr_t clk_info = msr_read(MSR_BSEL_CR_OVERCLOCK_CONTROL); 143 switch (clk_info.lo & 0x3) { 144 case 0: 145 return 83333333; 146 case 1: 147 return 100000000; 148 case 2: 149 return 133333333; 150 case 3: 151 return 116666666; 152 default: 153 return 0; 154 } 155 } 156 157 static unsigned long tsc_freq(void) 158 { 159 msr_t platform_info; 160 ulong bclk = bus_freq(); 161 162 if (!bclk) 163 return 0; 164 165 platform_info = msr_read(MSR_PLATFORM_INFO); 166 167 return bclk * ((platform_info.lo >> 8) & 0xff); 168 } 169 170 static int baytrail_get_info(struct udevice *dev, struct cpu_info *info) 171 { 172 info->cpu_freq = tsc_freq(); 173 info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU; 174 175 return 0; 176 } 177 178 static int cpu_x86_baytrail_bind(struct udevice *dev) 179 { 180 struct cpu_platdata *plat = dev_get_parent_platdata(dev); 181 182 plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, 183 "intel,apic-id", -1); 184 185 return 0; 186 } 187 188 static const struct cpu_ops cpu_x86_baytrail_ops = { 189 .get_desc = x86_cpu_get_desc, 190 .get_info = baytrail_get_info, 191 }; 192 193 static const struct udevice_id cpu_x86_baytrail_ids[] = { 194 { .compatible = "intel,baytrail-cpu" }, 195 { } 196 }; 197 198 U_BOOT_DRIVER(cpu_x86_baytrail_drv) = { 199 .name = "cpu_x86_baytrail", 200 .id = UCLASS_CPU, 201 .of_match = cpu_x86_baytrail_ids, 202 .bind = cpu_x86_baytrail_bind, 203 .probe = cpu_x86_baytrail_probe, 204 .ops = &cpu_x86_baytrail_ops, 205 }; 206