upstream u-boot with additional patches for our devices/boards:
https://lists.denx.de/pipermail/u-boot/2017-March/282789.html (AXP crashes) ;
Gbit ethernet patch for some LIME2 revisions ;
with SPI flash support
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
4.2 KiB
206 lines
4.2 KiB
10 years ago
|
/*
|
||
|
* Copyright (C) 2015 Google, Inc
|
||
|
*
|
||
|
* SPDX-License-Identifier: GPL-2.0+
|
||
|
*
|
||
|
* Based on code from coreboot
|
||
|
*/
|
||
|
|
||
|
#include <common.h>
|
||
|
#include <cpu.h>
|
||
|
#include <dm.h>
|
||
|
#include <asm/cpu.h>
|
||
|
#include <asm/lapic.h>
|
||
|
#include <asm/mp.h>
|
||
|
#include <asm/msr.h>
|
||
|
#include <asm/turbo.h>
|
||
|
|
||
|
#ifdef CONFIG_SMP
|
||
|
static int enable_smis(struct udevice *cpu, void *unused)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct mp_flight_record mp_steps[] = {
|
||
|
MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL),
|
||
|
/* Wait for APs to finish initialization before proceeding. */
|
||
|
MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL),
|
||
|
};
|
||
|
|
||
|
static int detect_num_cpus(void)
|
||
|
{
|
||
|
int ecx = 0;
|
||
|
|
||
|
/*
|
||
|
* Use the algorithm described in Intel 64 and IA-32 Architectures
|
||
|
* Software Developer's Manual Volume 3 (3A, 3B & 3C): System
|
||
|
* Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping
|
||
|
* of CPUID Extended Topology Leaf.
|
||
|
*/
|
||
|
while (1) {
|
||
|
struct cpuid_result leaf_b;
|
||
|
|
||
|
leaf_b = cpuid_ext(0xb, ecx);
|
||
|
|
||
|
/*
|
||
|
* Bay Trail doesn't have hyperthreading so just determine the
|
||
|
* number of cores by from level type (ecx[15:8] == * 2)
|
||
|
*/
|
||
|
if ((leaf_b.ecx & 0xff00) == 0x0200)
|
||
|
return leaf_b.ebx & 0xffff;
|
||
|
ecx++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int baytrail_init_cpus(void)
|
||
|
{
|
||
|
struct mp_params mp_params;
|
||
|
|
||
|
lapic_setup();
|
||
|
|
||
|
mp_params.num_cpus = detect_num_cpus();
|
||
|
mp_params.parallel_microcode_load = 0,
|
||
|
mp_params.flight_plan = &mp_steps[0];
|
||
|
mp_params.num_records = ARRAY_SIZE(mp_steps);
|
||
|
mp_params.microcode_pointer = 0;
|
||
|
|
||
|
if (mp_init(&mp_params)) {
|
||
|
printf("Warning: MP init failure\n");
|
||
|
return -EIO;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
int x86_init_cpus(void)
|
||
|
{
|
||
|
#ifdef CONFIG_SMP
|
||
|
debug("Init additional CPUs\n");
|
||
|
baytrail_init_cpus();
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void set_max_freq(void)
|
||
|
{
|
||
|
msr_t perf_ctl;
|
||
|
msr_t msr;
|
||
|
|
||
|
/* Enable speed step */
|
||
|
msr = msr_read(MSR_IA32_MISC_ENABLES);
|
||
|
msr.lo |= (1 << 16);
|
||
|
msr_write(MSR_IA32_MISC_ENABLES, msr);
|
||
|
|
||
|
/*
|
||
|
* Set guaranteed ratio [21:16] from IACORE_RATIOS to bits [15:8] of
|
||
|
* the PERF_CTL
|
||
|
*/
|
||
|
msr = msr_read(MSR_IACORE_RATIOS);
|
||
|
perf_ctl.lo = (msr.lo & 0x3f0000) >> 8;
|
||
|
|
||
|
/*
|
||
|
* Set guaranteed vid [21:16] from IACORE_VIDS to bits [7:0] of
|
||
|
* the PERF_CTL
|
||
|
*/
|
||
|
msr = msr_read(MSR_IACORE_VIDS);
|
||
|
perf_ctl.lo |= (msr.lo & 0x7f0000) >> 16;
|
||
|
perf_ctl.hi = 0;
|
||
|
|
||
|
msr_write(MSR_IA32_PERF_CTL, perf_ctl);
|
||
|
}
|
||
|
|
||
|
static int cpu_x86_baytrail_probe(struct udevice *dev)
|
||
|
{
|
||
|
debug("Init BayTrail core\n");
|
||
|
|
||
|
/*
|
||
|
* On BayTrail the turbo disable bit is actually scoped at the
|
||
|
* building-block level, not package. For non-BSP cores that are
|
||
|
* within a building block, enable turbo. The cores within the BSP's
|
||
|
* building block will just see it already enabled and move on.
|
||
|
*/
|
||
|
if (lapicid())
|
||
|
turbo_enable();
|
||
|
|
||
|
/* Dynamic L2 shrink enable and threshold */
|
||
|
msr_clrsetbits_64(MSR_PMG_CST_CONFIG_CONTROL, 0x3f000f, 0xe0008),
|
||
|
|
||
|
/* Disable C1E */
|
||
|
msr_clrsetbits_64(MSR_POWER_CTL, 2, 0);
|
||
|
msr_setbits_64(MSR_POWER_MISC, 0x44);
|
||
|
|
||
|
/* Set this core to max frequency ratio */
|
||
|
set_max_freq();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static unsigned bus_freq(void)
|
||
|
{
|
||
|
msr_t clk_info = msr_read(MSR_BSEL_CR_OVERCLOCK_CONTROL);
|
||
|
switch (clk_info.lo & 0x3) {
|
||
|
case 0:
|
||
|
return 83333333;
|
||
|
case 1:
|
||
|
return 100000000;
|
||
|
case 2:
|
||
|
return 133333333;
|
||
|
case 3:
|
||
|
return 116666666;
|
||
|
default:
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static unsigned long tsc_freq(void)
|
||
|
{
|
||
|
msr_t platform_info;
|
||
|
ulong bclk = bus_freq();
|
||
|
|
||
|
if (!bclk)
|
||
|
return 0;
|
||
|
|
||
|
platform_info = msr_read(MSR_PLATFORM_INFO);
|
||
|
|
||
|
return bclk * ((platform_info.lo >> 8) & 0xff);
|
||
|
}
|
||
|
|
||
|
static int baytrail_get_info(struct udevice *dev, struct cpu_info *info)
|
||
|
{
|
||
|
info->cpu_freq = tsc_freq();
|
||
|
info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int cpu_x86_baytrail_bind(struct udevice *dev)
|
||
|
{
|
||
|
struct cpu_platdata *plat = dev_get_parent_platdata(dev);
|
||
|
|
||
|
plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
|
||
|
"intel,apic-id", -1);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct cpu_ops cpu_x86_baytrail_ops = {
|
||
|
.get_desc = x86_cpu_get_desc,
|
||
|
.get_info = baytrail_get_info,
|
||
|
};
|
||
|
|
||
|
static const struct udevice_id cpu_x86_baytrail_ids[] = {
|
||
|
{ .compatible = "intel,baytrail-cpu" },
|
||
|
{ }
|
||
|
};
|
||
|
|
||
|
U_BOOT_DRIVER(cpu_x86_baytrail_drv) = {
|
||
|
.name = "cpu_x86_baytrail",
|
||
|
.id = UCLASS_CPU,
|
||
|
.of_match = cpu_x86_baytrail_ids,
|
||
|
.bind = cpu_x86_baytrail_bind,
|
||
|
.probe = cpu_x86_baytrail_probe,
|
||
|
.ops = &cpu_x86_baytrail_ops,
|
||
|
};
|