blob: c270426d820818f9576c32fea0db0e9ced27faab [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Google, Inc
*
* Based on code from coreboot
*/
#include <common.h>
#include <cpu.h>
#include <dm.h>
#include <event.h>
#include <init.h>
#include <log.h>
#include <pci.h>
#include <asm/cpu.h>
#include <asm/cpu_x86.h>
#include <asm/io.h>
#include <asm/lapic.h>
#include <asm/msr.h>
#include <asm/turbo.h>
#define BYT_PRV_CLK 0x800
#define BYT_PRV_CLK_EN (1 << 0)
#define BYT_PRV_CLK_M_VAL_SHIFT 1
#define BYT_PRV_CLK_N_VAL_SHIFT 16
#define BYT_PRV_CLK_UPDATE (1 << 31)
static void hsuart_clock_set(void *base)
{
u32 m, n, reg;
/*
* Configure the BayTrail UART clock for the internal HS UARTs
* (PCI devices) to 58982400 Hz
*/
m = 0x2400;
n = 0x3d09;
reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT);
writel(reg, base + BYT_PRV_CLK);
reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
writel(reg, base + BYT_PRV_CLK);
}
/*
* Configure the internal clock of both SIO HS-UARTs, if they are enabled
* via FSP
*/
static int baytrail_uart_init(void)
{
struct udevice *dev;
void *base;
int ret;
int i;
/* Loop over the 2 HS-UARTs */
for (i = 0; i < 2; i++) {
ret = dm_pci_bus_find_bdf(PCI_BDF(0, 0x1e, 3 + i), &dev);
if (!ret) {
base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
hsuart_clock_set(base);
}
}
return 0;
}
EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, baytrail_uart_init);
static void set_max_freq(void)
{
msr_t perf_ctl;
msr_t msr;
/* Enable speed step */
msr = msr_read(MSR_IA32_MISC_ENABLE);
msr.lo |= MISC_ENABLE_ENHANCED_SPEEDSTEP;
msr_write(MSR_IA32_MISC_ENABLE, 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 [22: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)
{
if (!ll_boot_init())
return 0;
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(const 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 baytrail_get_count(const struct udevice *dev)
{
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++;
}
return 0;
}
static const struct cpu_ops cpu_x86_baytrail_ops = {
.get_desc = cpu_x86_get_desc,
.get_info = baytrail_get_info,
.get_count = baytrail_get_count,
.get_vendor = cpu_x86_get_vendor,
};
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_bind,
.probe = cpu_x86_baytrail_probe,
.ops = &cpu_x86_baytrail_ops,
.flags = DM_FLAG_PRE_RELOC,
};