Merge git://git.denx.de/u-boot-x86

- Allow x86 boards to use TPL, SPL and U-Boot proper
- Update sysreset x86 driver to utilize ACPI registers to do power off
- Add a new chromebook_samus_tpl board for TPL support
- Several minor changes in binman tool
This commit is contained in:
Tom Rini 2019-05-08 09:20:19 -04:00
commit 8c66fb88e3
64 changed files with 2076 additions and 995 deletions

View File

@ -1380,6 +1380,7 @@ cmd_ldr = $(LD) $(LDFLAGS_$(@F)) \
u-boot.rom: u-boot-x86-16bit.bin u-boot.bin \
$(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \
$(if $(CONFIG_TPL_X86_16BIT_INIT),tpl/u-boot-tpl.bin) \
$(if $(CONFIG_HAVE_REFCODE),refcode.bin) FORCE
$(call if_changed,binman)

View File

@ -126,6 +126,8 @@ config SH
config X86
bool "x86 architecture"
select SUPPORT_SPL
select SUPPORT_TPL
select CREATE_ARCH_SYMLINK
select DM
select DM_PCI
@ -163,6 +165,36 @@ config X86
imply USB_ETHER_SMSC95XX
imply USB_HOST_ETHER
imply PCH
imply RTC_MC146818
# Thing to enable for when SPL/TPL are enabled: SPL
imply SPL_DM
imply SPL_OF_LIBFDT
imply SPL_DRIVERS_MISC_SUPPORT
imply SPL_GPIO_SUPPORT
imply SPL_LIBCOMMON_SUPPORT
imply SPL_LIBGENERIC_SUPPORT
imply SPL_SERIAL_SUPPORT
imply SPL_SPI_FLASH_SUPPORT
imply SPL_SPI_SUPPORT
imply SPL_OF_CONTROL
imply SPL_TIMER
imply SPL_REGMAP
imply SPL_SYSCON
# TPL
imply TPL_DM
imply TPL_OF_LIBFDT
imply TPL_DRIVERS_MISC_SUPPORT
imply TPL_GPIO_SUPPORT
imply TPL_LIBCOMMON_SUPPORT
imply TPL_LIBGENERIC_SUPPORT
imply TPL_SERIAL_SUPPORT
imply TPL_SPI_FLASH_SUPPORT
imply TPL_SPI_SUPPORT
imply TPL_OF_CONTROL
imply TPL_TIMER
imply TPL_REGMAP
imply TPL_SYSCON
config XTENSA
bool "Xtensa architecture"

View File

@ -32,7 +32,6 @@ config X86_RUN_32BIT
config X86_RUN_64BIT
bool "64-bit"
select X86_64
select SUPPORT_SPL
select SPL
select SPL_SEPARATE_BSS
help
@ -177,10 +176,17 @@ config X86_16BIT_INIT
config SPL_X86_16BIT_INIT
bool
depends on X86_RESET_VECTOR
default y if X86_RESET_VECTOR && SPL
default y if X86_RESET_VECTOR && SPL && !TPL
help
This is enabled when 16-bit init is in SPL
config TPL_X86_16BIT_INIT
bool
depends on X86_RESET_VECTOR
default y if X86_RESET_VECTOR && TPL
help
This is enabled when 16-bit init is in TPL
config X86_32BIT_INIT
bool
depends on X86_RESET_VECTOR

View File

@ -4,12 +4,24 @@ ifeq ($(CONFIG_EFI_APP),)
ifdef CONFIG_$(SPL_)X86_64
head-y := arch/x86/cpu/start64.o
else
ifeq ($(CONFIG_$(SPL_TPL_)X86_16BIT_INIT),y)
head-y := arch/x86/cpu/start.o
else
ifndef CONFIG_SPL
head-y := arch/x86/cpu/start.o
else
ifdef CONFIG_SPL_BUILD
head-y = arch/x86/cpu/start_from_tpl.o
else
head-y = arch/x86/cpu/start_from_spl.o
endif
endif
endif
endif
endif # EFI
head-$(CONFIG_$(SPL_)X86_16BIT_INIT) += arch/x86/cpu/start16.o
head-$(CONFIG_$(SPL_)X86_16BIT_INIT) += arch/x86/cpu/resetvec.o
head-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += arch/x86/cpu/start16.o
head-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += arch/x86/cpu/resetvec.o
libs-y += arch/x86/cpu/
libs-y += arch/x86/lib/

View File

@ -9,9 +9,22 @@
ifeq ($(CONFIG_$(SPL_)X86_64),y)
extra-y = start64.o
else
ifeq ($(CONFIG_$(SPL_TPL_)X86_16BIT_INIT),y)
extra-y = start.o
else
ifndef CONFIG_SPL
extra-y = start.o
else
ifdef CONFIG_SPL_BUILD
extra-y = start_from_tpl.o
else
extra-y = start_from_spl.o
endif
extra-$(CONFIG_$(SPL_)X86_16BIT_INIT) += resetvec.o start16.o
endif
endif
endif
extra-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += resetvec.o start16.o
obj-y += cpu.o cpu_x86.o

View File

@ -3,7 +3,24 @@
# Copyright (c) 2016 Google, Inc
obj-y += adsp.o
obj-y += cpu.o
obj-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += cpu.o
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += cpu_full.o
ifdef CONFIG_SPL
ifndef CONFIG_SPL_BUILD
obj-y += cpu_from_spl.o
obj-y += cpu_full.o
obj-y += refcode.o
endif
ifndef CONFIG_SPL_BUILD
# obj-y += cpu_from_spl.o
endif
endif
ifeq ($(CONFIG_$(SPL_TPL_)X86_32BIT_INIT),)
#obj-y += cpu_from_spl.o
endif
obj-y += iobp.o
obj-y += lpc.o
obj-y += me.o
@ -11,6 +28,6 @@ obj-y += northbridge.o
obj-y += pch.o
obj-y += pinctrl_broadwell.o
obj-y += power_state.o
obj-y += refcode.o
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += refcode.o
obj-y += sata.o
obj-y += sdram.o
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += sdram.o

View File

@ -12,75 +12,15 @@
#include <asm/cpu_x86.h>
#include <asm/cpu_common.h>
#include <asm/intel_regs.h>
#include <asm/lpc_common.h>
#include <asm/msr.h>
#include <asm/pci.h>
#include <asm/post.h>
#include <asm/turbo.h>
#include <asm/arch/cpu.h>
#include <asm/arch/pch.h>
#include <asm/arch/rcb.h>
struct cpu_broadwell_priv {
bool ht_disabled;
};
/* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */
static const u8 power_limit_time_sec_to_msr[] = {
[0] = 0x00,
[1] = 0x0a,
[2] = 0x0b,
[3] = 0x4b,
[4] = 0x0c,
[5] = 0x2c,
[6] = 0x4c,
[7] = 0x6c,
[8] = 0x0d,
[10] = 0x2d,
[12] = 0x4d,
[14] = 0x6d,
[16] = 0x0e,
[20] = 0x2e,
[24] = 0x4e,
[28] = 0x6e,
[32] = 0x0f,
[40] = 0x2f,
[48] = 0x4f,
[56] = 0x6f,
[64] = 0x10,
[80] = 0x30,
[96] = 0x50,
[112] = 0x70,
[128] = 0x11,
};
/* Convert POWER_LIMIT_1_TIME MSR value to seconds */
static const u8 power_limit_time_msr_to_sec[] = {
[0x00] = 0,
[0x0a] = 1,
[0x0b] = 2,
[0x4b] = 3,
[0x0c] = 4,
[0x2c] = 5,
[0x4c] = 6,
[0x6c] = 7,
[0x0d] = 8,
[0x2d] = 10,
[0x4d] = 12,
[0x6d] = 14,
[0x0e] = 16,
[0x2e] = 20,
[0x4e] = 24,
[0x6e] = 28,
[0x0f] = 32,
[0x2f] = 40,
[0x4f] = 48,
[0x6f] = 56,
[0x10] = 64,
[0x30] = 80,
[0x50] = 96,
[0x70] = 112,
[0x11] = 128,
};
int arch_cpu_init_dm(void)
{
struct udevice *dev;
@ -156,613 +96,13 @@ int print_cpuinfo(void)
return 0;
}
/*
* The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate
* the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly
* when a core is woken up
*/
static int pcode_ready(void)
void board_debug_uart_init(void)
{
int wait_count;
const int delay_step = 10;
struct udevice *bus = NULL;
wait_count = 0;
do {
if (!(readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) &
MAILBOX_RUN_BUSY))
return 0;
wait_count += delay_step;
udelay(delay_step);
} while (wait_count < 1000);
/* com1 / com2 decode range */
pci_x86_write_config(bus, PCH_DEV_LPC, LPC_IO_DEC, 1 << 4, PCI_SIZE_16);
return -ETIMEDOUT;
pci_x86_write_config(bus, PCH_DEV_LPC, LPC_EN, COMA_LPC_EN,
PCI_SIZE_16);
}
static u32 pcode_mailbox_read(u32 command)
{
int ret;
ret = pcode_ready();
if (ret) {
debug("PCODE: mailbox timeout on wait ready\n");
return ret;
}
/* Send command and start transaction */
writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE));
ret = pcode_ready();
if (ret) {
debug("PCODE: mailbox timeout on completion\n");
return ret;
}
/* Read mailbox */
return readl(MCHBAR_REG(BIOS_MAILBOX_DATA));
}
static int pcode_mailbox_write(u32 command, u32 data)
{
int ret;
ret = pcode_ready();
if (ret) {
debug("PCODE: mailbox timeout on wait ready\n");
return ret;
}
writel(data, MCHBAR_REG(BIOS_MAILBOX_DATA));
/* Send command and start transaction */
writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE));
ret = pcode_ready();
if (ret) {
debug("PCODE: mailbox timeout on completion\n");
return ret;
}
return 0;
}
/* @dev is the CPU device */
static void initialize_vr_config(struct udevice *dev)
{
int ramp, min_vid;
msr_t msr;
debug("Initializing VR config\n");
/* Configure VR_CURRENT_CONFIG */
msr = msr_read(MSR_VR_CURRENT_CONFIG);
/*
* Preserve bits 63 and 62. Bit 62 is PSI4 enable, but it is only valid
* on ULT systems
*/
msr.hi &= 0xc0000000;
msr.hi |= (0x01 << (52 - 32)); /* PSI3 threshold - 1A */
msr.hi |= (0x05 << (42 - 32)); /* PSI2 threshold - 5A */
msr.hi |= (0x14 << (32 - 32)); /* PSI1 threshold - 20A */
msr.hi |= (1 << (62 - 32)); /* Enable PSI4 */
/* Leave the max instantaneous current limit (12:0) to default */
msr_write(MSR_VR_CURRENT_CONFIG, msr);
/* Configure VR_MISC_CONFIG MSR */
msr = msr_read(MSR_VR_MISC_CONFIG);
/* Set the IOUT_SLOPE scalar applied to dIout in U10.1.9 format */
msr.hi &= ~(0x3ff << (40 - 32));
msr.hi |= (0x200 << (40 - 32)); /* 1.0 */
/* Set IOUT_OFFSET to 0 */
msr.hi &= ~0xff;
/* Set entry ramp rate to slow */
msr.hi &= ~(1 << (51 - 32));
/* Enable decay mode on C-state entry */
msr.hi |= (1 << (52 - 32));
/* Set the slow ramp rate */
msr.hi &= ~(0x3 << (53 - 32));
/* Configure the C-state exit ramp rate */
ramp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"intel,slow-ramp", -1);
if (ramp != -1) {
/* Configured slow ramp rate */
msr.hi |= ((ramp & 0x3) << (53 - 32));
/* Set exit ramp rate to slow */
msr.hi &= ~(1 << (50 - 32));
} else {
/* Fast ramp rate / 4 */
msr.hi |= (0x01 << (53 - 32));
/* Set exit ramp rate to fast */
msr.hi |= (1 << (50 - 32));
}
/* Set MIN_VID (31:24) to allow CPU to have full control */
msr.lo &= ~0xff000000;
min_vid = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"intel,min-vid", 0);
msr.lo |= (min_vid & 0xff) << 24;
msr_write(MSR_VR_MISC_CONFIG, msr);
/* Configure VR_MISC_CONFIG2 MSR */
msr = msr_read(MSR_VR_MISC_CONFIG2);
msr.lo &= ~0xffff;
/*
* Allow CPU to control minimum voltage completely (15:8) and
* set the fast ramp voltage in 10mV steps
*/
if (cpu_get_family_model() == BROADWELL_FAMILY_ULT)
msr.lo |= 0x006a; /* 1.56V */
else
msr.lo |= 0x006f; /* 1.60V */
msr_write(MSR_VR_MISC_CONFIG2, msr);
/* Set C9/C10 VCC Min */
pcode_mailbox_write(MAILBOX_BIOS_CMD_WRITE_C9C10_VOLTAGE, 0x1f1f);
}
static int calibrate_24mhz_bclk(void)
{
int err_code;
int ret;
ret = pcode_ready();
if (ret)
return ret;
/* A non-zero value initiates the PCODE calibration */
writel(~0, MCHBAR_REG(BIOS_MAILBOX_DATA));
writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_FSM_MEASURE_INTVL,
MCHBAR_REG(BIOS_MAILBOX_INTERFACE));
ret = pcode_ready();
if (ret)
return ret;
err_code = readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & 0xff;
debug("PCODE: 24MHz BLCK calibration response: %d\n", err_code);
/* Read the calibrated value */
writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_READ_CALIBRATION,
MCHBAR_REG(BIOS_MAILBOX_INTERFACE));
ret = pcode_ready();
if (ret)
return ret;
debug("PCODE: 24MHz BLCK calibration value: 0x%08x\n",
readl(MCHBAR_REG(BIOS_MAILBOX_DATA)));
return 0;
}
static void configure_pch_power_sharing(void)
{
u32 pch_power, pch_power_ext, pmsync, pmsync2;
int i;
/* Read PCH Power levels from PCODE */
pch_power = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER);
pch_power_ext = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER_EXT);
debug("PCH Power: PCODE Levels 0x%08x 0x%08x\n", pch_power,
pch_power_ext);
pmsync = readl(RCB_REG(PMSYNC_CONFIG));
pmsync2 = readl(RCB_REG(PMSYNC_CONFIG2));
/*
* Program PMSYNC_TPR_CONFIG PCH power limit values
* pmsync[0:4] = mailbox[0:5]
* pmsync[8:12] = mailbox[6:11]
* pmsync[16:20] = mailbox[12:17]
*/
for (i = 0; i < 3; i++) {
u32 level = pch_power & 0x3f;
pch_power >>= 6;
pmsync &= ~(0x1f << (i * 8));
pmsync |= (level & 0x1f) << (i * 8);
}
writel(pmsync, RCB_REG(PMSYNC_CONFIG));
/*
* Program PMSYNC_TPR_CONFIG2 Extended PCH power limit values
* pmsync2[0:4] = mailbox[23:18]
* pmsync2[8:12] = mailbox_ext[6:11]
* pmsync2[16:20] = mailbox_ext[12:17]
* pmsync2[24:28] = mailbox_ext[18:22]
*/
pmsync2 &= ~0x1f;
pmsync2 |= pch_power & 0x1f;
for (i = 1; i < 4; i++) {
u32 level = pch_power_ext & 0x3f;
pch_power_ext >>= 6;
pmsync2 &= ~(0x1f << (i * 8));
pmsync2 |= (level & 0x1f) << (i * 8);
}
writel(pmsync2, RCB_REG(PMSYNC_CONFIG2));
}
static int bsp_init_before_ap_bringup(struct udevice *dev)
{
int ret;
initialize_vr_config(dev);
ret = calibrate_24mhz_bclk();
if (ret)
return ret;
configure_pch_power_sharing();
return 0;
}
int cpu_config_tdp_levels(void)
{
msr_t platform_info;
/* Bits 34:33 indicate how many levels supported */
platform_info = msr_read(MSR_PLATFORM_INFO);
return (platform_info.hi >> 1) & 3;
}
static void set_max_ratio(void)
{
msr_t msr, perf_ctl;
perf_ctl.hi = 0;
/* Check for configurable TDP option */
if (turbo_get_state() == TURBO_ENABLED) {
msr = msr_read(MSR_NHM_TURBO_RATIO_LIMIT);
perf_ctl.lo = (msr.lo & 0xff) << 8;
} else if (cpu_config_tdp_levels()) {
/* Set to nominal TDP ratio */
msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
perf_ctl.lo = (msr.lo & 0xff) << 8;
} else {
/* Platform Info bits 15:8 give max ratio */
msr = msr_read(MSR_PLATFORM_INFO);
perf_ctl.lo = msr.lo & 0xff00;
}
msr_write(IA32_PERF_CTL, perf_ctl);
debug("cpu: frequency set to %d\n",
((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK);
}
int broadwell_init(struct udevice *dev)
{
struct cpu_broadwell_priv *priv = dev_get_priv(dev);
int num_threads;
int num_cores;
msr_t msr;
int ret;
msr = msr_read(CORE_THREAD_COUNT_MSR);
num_threads = (msr.lo >> 0) & 0xffff;
num_cores = (msr.lo >> 16) & 0xffff;
debug("CPU has %u cores, %u threads enabled\n", num_cores,
num_threads);
priv->ht_disabled = num_threads == num_cores;
ret = bsp_init_before_ap_bringup(dev);
if (ret)
return ret;
set_max_ratio();
return ret;
}
static void configure_mca(void)
{
msr_t msr;
const unsigned int mcg_cap_msr = 0x179;
int i;
int num_banks;
msr = msr_read(mcg_cap_msr);
num_banks = msr.lo & 0xff;
msr.lo = 0;
msr.hi = 0;
/*
* TODO(adurbin): This should only be done on a cold boot. Also, some
* of these banks are core vs package scope. For now every CPU clears
* every bank
*/
for (i = 0; i < num_banks; i++)
msr_write(MSR_IA32_MC0_STATUS + (i * 4), msr);
}
static void enable_lapic_tpr(void)
{
msr_t msr;
msr = msr_read(MSR_PIC_MSG_CONTROL);
msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
msr_write(MSR_PIC_MSG_CONTROL, msr);
}
static void configure_c_states(void)
{
msr_t msr;
msr = msr_read(MSR_PMG_CST_CONFIG_CONTROL);
msr.lo |= (1 << 31); /* Timed MWAIT Enable */
msr.lo |= (1 << 30); /* Package c-state Undemotion Enable */
msr.lo |= (1 << 29); /* Package c-state Demotion Enable */
msr.lo |= (1 << 28); /* C1 Auto Undemotion Enable */
msr.lo |= (1 << 27); /* C3 Auto Undemotion Enable */
msr.lo |= (1 << 26); /* C1 Auto Demotion Enable */
msr.lo |= (1 << 25); /* C3 Auto Demotion Enable */
msr.lo &= ~(1 << 10); /* Disable IO MWAIT redirection */
/* The deepest package c-state defaults to factory-configured value */
msr_write(MSR_PMG_CST_CONFIG_CONTROL, msr);
msr = msr_read(MSR_MISC_PWR_MGMT);
msr.lo &= ~(1 << 0); /* Enable P-state HW_ALL coordination */
msr_write(MSR_MISC_PWR_MGMT, msr);
msr = msr_read(MSR_POWER_CTL);
msr.lo |= (1 << 18); /* Enable Energy Perf Bias MSR 0x1b0 */
msr.lo |= (1 << 1); /* C1E Enable */
msr.lo |= (1 << 0); /* Bi-directional PROCHOT# */
msr_write(MSR_POWER_CTL, msr);
/* C-state Interrupt Response Latency Control 0 - package C3 latency */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_0_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_0, msr);
/* C-state Interrupt Response Latency Control 1 */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_1_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_1, msr);
/* C-state Interrupt Response Latency Control 2 - package C6/C7 short */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_2_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_2, msr);
/* C-state Interrupt Response Latency Control 3 - package C8 */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_3_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_3, msr);
/* C-state Interrupt Response Latency Control 4 - package C9 */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_4_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_4, msr);
/* C-state Interrupt Response Latency Control 5 - package C10 */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_5_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_5, msr);
}
static void configure_misc(void)
{
msr_t msr;
msr = msr_read(MSR_IA32_MISC_ENABLE);
msr.lo |= (1 << 0); /* Fast String enable */
msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
msr_write(MSR_IA32_MISC_ENABLE, msr);
/* Disable thermal interrupts */
msr.lo = 0;
msr.hi = 0;
msr_write(MSR_IA32_THERM_INTERRUPT, msr);
/* Enable package critical interrupt only */
msr.lo = 1 << 4;
msr.hi = 0;
msr_write(MSR_IA32_PACKAGE_THERM_INTERRUPT, msr);
}
static void configure_thermal_target(struct udevice *dev)
{
int tcc_offset;
msr_t msr;
tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"intel,tcc-offset", 0);
/* Set TCC activaiton offset if supported */
msr = msr_read(MSR_PLATFORM_INFO);
if ((msr.lo & (1 << 30)) && tcc_offset) {
msr = msr_read(MSR_TEMPERATURE_TARGET);
msr.lo &= ~(0xf << 24); /* Bits 27:24 */
msr.lo |= (tcc_offset & 0xf) << 24;
msr_write(MSR_TEMPERATURE_TARGET, msr);
}
}
static void configure_dca_cap(void)
{
struct cpuid_result cpuid_regs;
msr_t msr;
/* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */
cpuid_regs = cpuid(1);
if (cpuid_regs.ecx & (1 << 18)) {
msr = msr_read(MSR_IA32_PLATFORM_DCA_CAP);
msr.lo |= 1;
msr_write(MSR_IA32_PLATFORM_DCA_CAP, msr);
}
}
static void set_energy_perf_bias(u8 policy)
{
msr_t msr;
int ecx;
/* Determine if energy efficient policy is supported */
ecx = cpuid_ecx(0x6);
if (!(ecx & (1 << 3)))
return;
/* Energy Policy is bits 3:0 */
msr = msr_read(MSR_IA32_ENERGY_PERFORMANCE_BIAS);
msr.lo &= ~0xf;
msr.lo |= policy & 0xf;
msr_write(MSR_IA32_ENERGY_PERFORMANCE_BIAS, msr);
debug("cpu: energy policy set to %u\n", policy);
}
/* All CPUs including BSP will run the following function */
static void cpu_core_init(struct udevice *dev)
{
/* Clear out pending MCEs */
configure_mca();
/* Enable the local cpu apics */
enable_lapic_tpr();
/* Configure C States */
configure_c_states();
/* Configure Enhanced SpeedStep and Thermal Sensors */
configure_misc();
/* Thermal throttle activation offset */
configure_thermal_target(dev);
/* Enable Direct Cache Access */
configure_dca_cap();
/* Set energy policy */
set_energy_perf_bias(ENERGY_POLICY_NORMAL);
/* Enable Turbo */
turbo_enable();
}
/*
* Configure processor power limits if possible
* This must be done AFTER set of BIOS_RESET_CPL
*/
void cpu_set_power_limits(int power_limit_1_time)
{
msr_t msr;
msr_t limit;
unsigned power_unit;
unsigned tdp, min_power, max_power, max_time;
u8 power_limit_1_val;
msr = msr_read(MSR_PLATFORM_INFO);
if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr))
power_limit_1_time = 28;
if (!(msr.lo & PLATFORM_INFO_SET_TDP))
return;
/* Get units */
msr = msr_read(MSR_PKG_POWER_SKU_UNIT);
power_unit = 2 << ((msr.lo & 0xf) - 1);
/* Get power defaults for this SKU */
msr = msr_read(MSR_PKG_POWER_SKU);
tdp = msr.lo & 0x7fff;
min_power = (msr.lo >> 16) & 0x7fff;
max_power = msr.hi & 0x7fff;
max_time = (msr.hi >> 16) & 0x7f;
debug("CPU TDP: %u Watts\n", tdp / power_unit);
if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time)
power_limit_1_time = power_limit_time_msr_to_sec[max_time];
if (min_power > 0 && tdp < min_power)
tdp = min_power;
if (max_power > 0 && tdp > max_power)
tdp = max_power;
power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time];
/* Set long term power limit to TDP */
limit.lo = 0;
limit.lo |= tdp & PKG_POWER_LIMIT_MASK;
limit.lo |= PKG_POWER_LIMIT_EN;
limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) <<
PKG_POWER_LIMIT_TIME_SHIFT;
/* Set short term power limit to 1.25 * TDP */
limit.hi = 0;
limit.hi |= ((tdp * 125) / 100) & PKG_POWER_LIMIT_MASK;
limit.hi |= PKG_POWER_LIMIT_EN;
/* Power limit 2 time is only programmable on server SKU */
msr_write(MSR_PKG_POWER_LIMIT, limit);
/* Set power limit values in MCHBAR as well */
writel(limit.lo, MCHBAR_REG(MCH_PKG_POWER_LIMIT_LO));
writel(limit.hi, MCHBAR_REG(MCH_PKG_POWER_LIMIT_HI));
/* Set DDR RAPL power limit by copying from MMIO to MSR */
msr.lo = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_LO));
msr.hi = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_HI));
msr_write(MSR_DDR_RAPL_LIMIT, msr);
/* Use nominal TDP values for CPUs with configurable TDP */
if (cpu_config_tdp_levels()) {
msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
limit.hi = 0;
limit.lo = msr.lo & 0xff;
msr_write(MSR_TURBO_ACTIVATION_RATIO, limit);
}
}
static int broadwell_get_info(struct udevice *dev, struct cpu_info *info)
{
msr_t msr;
msr = msr_read(IA32_PERF_CTL);
info->cpu_freq = ((msr.lo >> 8) & 0xff) * BROADWELL_BCLK * 1000000;
info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU |
1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID;
return 0;
}
static int broadwell_get_count(struct udevice *dev)
{
return 4;
}
static int cpu_x86_broadwell_probe(struct udevice *dev)
{
if (dev->seq == 0) {
cpu_core_init(dev);
return broadwell_init(dev);
}
return 0;
}
static const struct cpu_ops cpu_x86_broadwell_ops = {
.get_desc = cpu_x86_get_desc,
.get_info = broadwell_get_info,
.get_count = broadwell_get_count,
.get_vendor = cpu_x86_get_vendor,
};
static const struct udevice_id cpu_x86_broadwell_ids[] = {
{ .compatible = "intel,core-i3-gen5" },
{ }
};
U_BOOT_DRIVER(cpu_x86_broadwell_drv) = {
.name = "cpu_x86_broadwell",
.id = UCLASS_CPU,
.of_match = cpu_x86_broadwell_ids,
.bind = cpu_x86_bind,
.probe = cpu_x86_broadwell_probe,
.ops = &cpu_x86_broadwell_ops,
.priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv),
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2016 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <bloblist.h>
#include <debug_uart.h>
#include <handoff.h>
#include <asm/mtrr.h>
int misc_init_r(void)
{
return 0;
}
int dram_init(void)
{
struct spl_handoff *ho;
ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(*ho));
if (!ho)
return log_msg_ret("Missing SPL hand-off info", -ENOENT);
handoff_load_dram_size(ho);
#ifdef CONFIG_TPL
/* TODO(sjg@chromium.org): MTRR cannot be adjusted without a hang */
mtrr_add_request(MTRR_TYPE_WRBACK, 0, 2ULL << 30);
#else
mtrr_add_request(MTRR_TYPE_WRBACK, 0, gd->ram_size);
mtrr_commit(true);
#endif
return 0;
}
int checkcpu(void)
{
return 0;
}
int print_cpuinfo(void)
{
return 0;
}
void board_debug_uart_init(void)
{
}
int dram_init_banksize(void)
{
#ifdef CONFIG_NR_DRAM_BANKS
struct spl_handoff *ho;
ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(*ho));
if (!ho)
return log_msg_ret("Missing SPL hand-off info", -ENOENT);
handoff_load_dram_banks(ho);
#endif
return 0;
}

View File

@ -0,0 +1,694 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 Google, Inc
*
* Based on code from coreboot src/soc/intel/broadwell/cpu.c
*/
#include <common.h>
#include <dm.h>
#include <cpu.h>
#include <asm/cpu.h>
#include <asm/cpu_x86.h>
#include <asm/cpu_common.h>
#include <asm/intel_regs.h>
#include <asm/msr.h>
#include <asm/post.h>
#include <asm/turbo.h>
#include <asm/arch/cpu.h>
#include <asm/arch/pch.h>
#include <asm/arch/rcb.h>
struct cpu_broadwell_priv {
bool ht_disabled;
};
/* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */
static const u8 power_limit_time_sec_to_msr[] = {
[0] = 0x00,
[1] = 0x0a,
[2] = 0x0b,
[3] = 0x4b,
[4] = 0x0c,
[5] = 0x2c,
[6] = 0x4c,
[7] = 0x6c,
[8] = 0x0d,
[10] = 0x2d,
[12] = 0x4d,
[14] = 0x6d,
[16] = 0x0e,
[20] = 0x2e,
[24] = 0x4e,
[28] = 0x6e,
[32] = 0x0f,
[40] = 0x2f,
[48] = 0x4f,
[56] = 0x6f,
[64] = 0x10,
[80] = 0x30,
[96] = 0x50,
[112] = 0x70,
[128] = 0x11,
};
/* Convert POWER_LIMIT_1_TIME MSR value to seconds */
static const u8 power_limit_time_msr_to_sec[] = {
[0x00] = 0,
[0x0a] = 1,
[0x0b] = 2,
[0x4b] = 3,
[0x0c] = 4,
[0x2c] = 5,
[0x4c] = 6,
[0x6c] = 7,
[0x0d] = 8,
[0x2d] = 10,
[0x4d] = 12,
[0x6d] = 14,
[0x0e] = 16,
[0x2e] = 20,
[0x4e] = 24,
[0x6e] = 28,
[0x0f] = 32,
[0x2f] = 40,
[0x4f] = 48,
[0x6f] = 56,
[0x10] = 64,
[0x30] = 80,
[0x50] = 96,
[0x70] = 112,
[0x11] = 128,
};
/*
* The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate
* the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly
* when a core is woken up
*/
static int pcode_ready(void)
{
int wait_count;
const int delay_step = 10;
wait_count = 0;
do {
if (!(readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) &
MAILBOX_RUN_BUSY))
return 0;
wait_count += delay_step;
udelay(delay_step);
} while (wait_count < 1000);
return -ETIMEDOUT;
}
static u32 pcode_mailbox_read(u32 command)
{
int ret;
ret = pcode_ready();
if (ret) {
debug("PCODE: mailbox timeout on wait ready\n");
return ret;
}
/* Send command and start transaction */
writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE));
ret = pcode_ready();
if (ret) {
debug("PCODE: mailbox timeout on completion\n");
return ret;
}
/* Read mailbox */
return readl(MCHBAR_REG(BIOS_MAILBOX_DATA));
}
static int pcode_mailbox_write(u32 command, u32 data)
{
int ret;
ret = pcode_ready();
if (ret) {
debug("PCODE: mailbox timeout on wait ready\n");
return ret;
}
writel(data, MCHBAR_REG(BIOS_MAILBOX_DATA));
/* Send command and start transaction */
writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE));
ret = pcode_ready();
if (ret) {
debug("PCODE: mailbox timeout on completion\n");
return ret;
}
return 0;
}
/* @dev is the CPU device */
static void initialize_vr_config(struct udevice *dev)
{
int ramp, min_vid;
msr_t msr;
debug("Initializing VR config\n");
/* Configure VR_CURRENT_CONFIG */
msr = msr_read(MSR_VR_CURRENT_CONFIG);
/*
* Preserve bits 63 and 62. Bit 62 is PSI4 enable, but it is only valid
* on ULT systems
*/
msr.hi &= 0xc0000000;
msr.hi |= (0x01 << (52 - 32)); /* PSI3 threshold - 1A */
msr.hi |= (0x05 << (42 - 32)); /* PSI2 threshold - 5A */
msr.hi |= (0x14 << (32 - 32)); /* PSI1 threshold - 20A */
msr.hi |= (1 << (62 - 32)); /* Enable PSI4 */
/* Leave the max instantaneous current limit (12:0) to default */
msr_write(MSR_VR_CURRENT_CONFIG, msr);
/* Configure VR_MISC_CONFIG MSR */
msr = msr_read(MSR_VR_MISC_CONFIG);
/* Set the IOUT_SLOPE scalar applied to dIout in U10.1.9 format */
msr.hi &= ~(0x3ff << (40 - 32));
msr.hi |= (0x200 << (40 - 32)); /* 1.0 */
/* Set IOUT_OFFSET to 0 */
msr.hi &= ~0xff;
/* Set entry ramp rate to slow */
msr.hi &= ~(1 << (51 - 32));
/* Enable decay mode on C-state entry */
msr.hi |= (1 << (52 - 32));
/* Set the slow ramp rate */
msr.hi &= ~(0x3 << (53 - 32));
/* Configure the C-state exit ramp rate */
ramp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"intel,slow-ramp", -1);
if (ramp != -1) {
/* Configured slow ramp rate */
msr.hi |= ((ramp & 0x3) << (53 - 32));
/* Set exit ramp rate to slow */
msr.hi &= ~(1 << (50 - 32));
} else {
/* Fast ramp rate / 4 */
msr.hi |= (0x01 << (53 - 32));
/* Set exit ramp rate to fast */
msr.hi |= (1 << (50 - 32));
}
/* Set MIN_VID (31:24) to allow CPU to have full control */
msr.lo &= ~0xff000000;
min_vid = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"intel,min-vid", 0);
msr.lo |= (min_vid & 0xff) << 24;
msr_write(MSR_VR_MISC_CONFIG, msr);
/* Configure VR_MISC_CONFIG2 MSR */
msr = msr_read(MSR_VR_MISC_CONFIG2);
msr.lo &= ~0xffff;
/*
* Allow CPU to control minimum voltage completely (15:8) and
* set the fast ramp voltage in 10mV steps
*/
if (cpu_get_family_model() == BROADWELL_FAMILY_ULT)
msr.lo |= 0x006a; /* 1.56V */
else
msr.lo |= 0x006f; /* 1.60V */
msr_write(MSR_VR_MISC_CONFIG2, msr);
/* Set C9/C10 VCC Min */
pcode_mailbox_write(MAILBOX_BIOS_CMD_WRITE_C9C10_VOLTAGE, 0x1f1f);
}
static int calibrate_24mhz_bclk(void)
{
int err_code;
int ret;
ret = pcode_ready();
if (ret)
return ret;
/* A non-zero value initiates the PCODE calibration */
writel(~0, MCHBAR_REG(BIOS_MAILBOX_DATA));
writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_FSM_MEASURE_INTVL,
MCHBAR_REG(BIOS_MAILBOX_INTERFACE));
ret = pcode_ready();
if (ret)
return ret;
err_code = readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & 0xff;
debug("PCODE: 24MHz BLCK calibration response: %d\n", err_code);
/* Read the calibrated value */
writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_READ_CALIBRATION,
MCHBAR_REG(BIOS_MAILBOX_INTERFACE));
ret = pcode_ready();
if (ret)
return ret;
debug("PCODE: 24MHz BLCK calibration value: 0x%08x\n",
readl(MCHBAR_REG(BIOS_MAILBOX_DATA)));
return 0;
}
static void configure_pch_power_sharing(void)
{
u32 pch_power, pch_power_ext, pmsync, pmsync2;
int i;
/* Read PCH Power levels from PCODE */
pch_power = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER);
pch_power_ext = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER_EXT);
debug("PCH Power: PCODE Levels 0x%08x 0x%08x\n", pch_power,
pch_power_ext);
pmsync = readl(RCB_REG(PMSYNC_CONFIG));
pmsync2 = readl(RCB_REG(PMSYNC_CONFIG2));
/*
* Program PMSYNC_TPR_CONFIG PCH power limit values
* pmsync[0:4] = mailbox[0:5]
* pmsync[8:12] = mailbox[6:11]
* pmsync[16:20] = mailbox[12:17]
*/
for (i = 0; i < 3; i++) {
u32 level = pch_power & 0x3f;
pch_power >>= 6;
pmsync &= ~(0x1f << (i * 8));
pmsync |= (level & 0x1f) << (i * 8);
}
writel(pmsync, RCB_REG(PMSYNC_CONFIG));
/*
* Program PMSYNC_TPR_CONFIG2 Extended PCH power limit values
* pmsync2[0:4] = mailbox[23:18]
* pmsync2[8:12] = mailbox_ext[6:11]
* pmsync2[16:20] = mailbox_ext[12:17]
* pmsync2[24:28] = mailbox_ext[18:22]
*/
pmsync2 &= ~0x1f;
pmsync2 |= pch_power & 0x1f;
for (i = 1; i < 4; i++) {
u32 level = pch_power_ext & 0x3f;
pch_power_ext >>= 6;
pmsync2 &= ~(0x1f << (i * 8));
pmsync2 |= (level & 0x1f) << (i * 8);
}
writel(pmsync2, RCB_REG(PMSYNC_CONFIG2));
}
static int bsp_init_before_ap_bringup(struct udevice *dev)
{
int ret;
initialize_vr_config(dev);
ret = calibrate_24mhz_bclk();
if (ret)
return ret;
configure_pch_power_sharing();
return 0;
}
static int cpu_config_tdp_levels(void)
{
msr_t platform_info;
/* Bits 34:33 indicate how many levels supported */
platform_info = msr_read(MSR_PLATFORM_INFO);
return (platform_info.hi >> 1) & 3;
}
static void set_max_ratio(void)
{
msr_t msr, perf_ctl;
perf_ctl.hi = 0;
/* Check for configurable TDP option */
if (turbo_get_state() == TURBO_ENABLED) {
msr = msr_read(MSR_NHM_TURBO_RATIO_LIMIT);
perf_ctl.lo = (msr.lo & 0xff) << 8;
} else if (cpu_config_tdp_levels()) {
/* Set to nominal TDP ratio */
msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
perf_ctl.lo = (msr.lo & 0xff) << 8;
} else {
/* Platform Info bits 15:8 give max ratio */
msr = msr_read(MSR_PLATFORM_INFO);
perf_ctl.lo = msr.lo & 0xff00;
}
msr_write(IA32_PERF_CTL, perf_ctl);
debug("cpu: frequency set to %d\n",
((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK);
}
int broadwell_init(struct udevice *dev)
{
struct cpu_broadwell_priv *priv = dev_get_priv(dev);
int num_threads;
int num_cores;
msr_t msr;
int ret;
msr = msr_read(CORE_THREAD_COUNT_MSR);
num_threads = (msr.lo >> 0) & 0xffff;
num_cores = (msr.lo >> 16) & 0xffff;
debug("CPU has %u cores, %u threads enabled\n", num_cores,
num_threads);
priv->ht_disabled = num_threads == num_cores;
ret = bsp_init_before_ap_bringup(dev);
if (ret)
return ret;
set_max_ratio();
return ret;
}
static void configure_mca(void)
{
msr_t msr;
const unsigned int mcg_cap_msr = 0x179;
int i;
int num_banks;
msr = msr_read(mcg_cap_msr);
num_banks = msr.lo & 0xff;
msr.lo = 0;
msr.hi = 0;
/*
* TODO(adurbin): This should only be done on a cold boot. Also, some
* of these banks are core vs package scope. For now every CPU clears
* every bank
*/
for (i = 0; i < num_banks; i++)
msr_write(MSR_IA32_MC0_STATUS + (i * 4), msr);
}
static void enable_lapic_tpr(void)
{
msr_t msr;
msr = msr_read(MSR_PIC_MSG_CONTROL);
msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
msr_write(MSR_PIC_MSG_CONTROL, msr);
}
static void configure_c_states(void)
{
msr_t msr;
msr = msr_read(MSR_PMG_CST_CONFIG_CONTROL);
msr.lo |= (1 << 31); /* Timed MWAIT Enable */
msr.lo |= (1 << 30); /* Package c-state Undemotion Enable */
msr.lo |= (1 << 29); /* Package c-state Demotion Enable */
msr.lo |= (1 << 28); /* C1 Auto Undemotion Enable */
msr.lo |= (1 << 27); /* C3 Auto Undemotion Enable */
msr.lo |= (1 << 26); /* C1 Auto Demotion Enable */
msr.lo |= (1 << 25); /* C3 Auto Demotion Enable */
msr.lo &= ~(1 << 10); /* Disable IO MWAIT redirection */
/* The deepest package c-state defaults to factory-configured value */
msr_write(MSR_PMG_CST_CONFIG_CONTROL, msr);
msr = msr_read(MSR_MISC_PWR_MGMT);
msr.lo &= ~(1 << 0); /* Enable P-state HW_ALL coordination */
msr_write(MSR_MISC_PWR_MGMT, msr);
msr = msr_read(MSR_POWER_CTL);
msr.lo |= (1 << 18); /* Enable Energy Perf Bias MSR 0x1b0 */
msr.lo |= (1 << 1); /* C1E Enable */
msr.lo |= (1 << 0); /* Bi-directional PROCHOT# */
msr_write(MSR_POWER_CTL, msr);
/* C-state Interrupt Response Latency Control 0 - package C3 latency */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_0_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_0, msr);
/* C-state Interrupt Response Latency Control 1 */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_1_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_1, msr);
/* C-state Interrupt Response Latency Control 2 - package C6/C7 short */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_2_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_2, msr);
/* C-state Interrupt Response Latency Control 3 - package C8 */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_3_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_3, msr);
/* C-state Interrupt Response Latency Control 4 - package C9 */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_4_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_4, msr);
/* C-state Interrupt Response Latency Control 5 - package C10 */
msr.hi = 0;
msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_5_LIMIT;
msr_write(MSR_C_STATE_LATENCY_CONTROL_5, msr);
}
static void configure_misc(void)
{
msr_t msr;
msr = msr_read(MSR_IA32_MISC_ENABLE);
msr.lo |= (1 << 0); /* Fast String enable */
msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
msr_write(MSR_IA32_MISC_ENABLE, msr);
/* Disable thermal interrupts */
msr.lo = 0;
msr.hi = 0;
msr_write(MSR_IA32_THERM_INTERRUPT, msr);
/* Enable package critical interrupt only */
msr.lo = 1 << 4;
msr.hi = 0;
msr_write(MSR_IA32_PACKAGE_THERM_INTERRUPT, msr);
}
static void configure_thermal_target(struct udevice *dev)
{
int tcc_offset;
msr_t msr;
tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"intel,tcc-offset", 0);
/* Set TCC activaiton offset if supported */
msr = msr_read(MSR_PLATFORM_INFO);
if ((msr.lo & (1 << 30)) && tcc_offset) {
msr = msr_read(MSR_TEMPERATURE_TARGET);
msr.lo &= ~(0xf << 24); /* Bits 27:24 */
msr.lo |= (tcc_offset & 0xf) << 24;
msr_write(MSR_TEMPERATURE_TARGET, msr);
}
}
static void configure_dca_cap(void)
{
struct cpuid_result cpuid_regs;
msr_t msr;
/* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */
cpuid_regs = cpuid(1);
if (cpuid_regs.ecx & (1 << 18)) {
msr = msr_read(MSR_IA32_PLATFORM_DCA_CAP);
msr.lo |= 1;
msr_write(MSR_IA32_PLATFORM_DCA_CAP, msr);
}
}
static void set_energy_perf_bias(u8 policy)
{
msr_t msr;
int ecx;
/* Determine if energy efficient policy is supported */
ecx = cpuid_ecx(0x6);
if (!(ecx & (1 << 3)))
return;
/* Energy Policy is bits 3:0 */
msr = msr_read(MSR_IA32_ENERGY_PERFORMANCE_BIAS);
msr.lo &= ~0xf;
msr.lo |= policy & 0xf;
msr_write(MSR_IA32_ENERGY_PERFORMANCE_BIAS, msr);
debug("cpu: energy policy set to %u\n", policy);
}
/* All CPUs including BSP will run the following function */
static void cpu_core_init(struct udevice *dev)
{
/* Clear out pending MCEs */
configure_mca();
/* Enable the local cpu apics */
enable_lapic_tpr();
/* Configure C States */
configure_c_states();
/* Configure Enhanced SpeedStep and Thermal Sensors */
configure_misc();
/* Thermal throttle activation offset */
configure_thermal_target(dev);
/* Enable Direct Cache Access */
configure_dca_cap();
/* Set energy policy */
set_energy_perf_bias(ENERGY_POLICY_NORMAL);
/* Enable Turbo */
turbo_enable();
}
/*
* Configure processor power limits if possible
* This must be done AFTER set of BIOS_RESET_CPL
*/
void cpu_set_power_limits(int power_limit_1_time)
{
msr_t msr;
msr_t limit;
uint power_unit;
uint tdp, min_power, max_power, max_time;
u8 power_limit_1_val;
msr = msr_read(MSR_PLATFORM_INFO);
if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr))
power_limit_1_time = 28;
if (!(msr.lo & PLATFORM_INFO_SET_TDP))
return;
/* Get units */
msr = msr_read(MSR_PKG_POWER_SKU_UNIT);
power_unit = 2 << ((msr.lo & 0xf) - 1);
/* Get power defaults for this SKU */
msr = msr_read(MSR_PKG_POWER_SKU);
tdp = msr.lo & 0x7fff;
min_power = (msr.lo >> 16) & 0x7fff;
max_power = msr.hi & 0x7fff;
max_time = (msr.hi >> 16) & 0x7f;
debug("CPU TDP: %u Watts\n", tdp / power_unit);
if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time)
power_limit_1_time = power_limit_time_msr_to_sec[max_time];
if (min_power > 0 && tdp < min_power)
tdp = min_power;
if (max_power > 0 && tdp > max_power)
tdp = max_power;
power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time];
/* Set long term power limit to TDP */
limit.lo = 0;
limit.lo |= tdp & PKG_POWER_LIMIT_MASK;
limit.lo |= PKG_POWER_LIMIT_EN;
limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) <<
PKG_POWER_LIMIT_TIME_SHIFT;
/* Set short term power limit to 1.25 * TDP */
limit.hi = 0;
limit.hi |= ((tdp * 125) / 100) & PKG_POWER_LIMIT_MASK;
limit.hi |= PKG_POWER_LIMIT_EN;
/* Power limit 2 time is only programmable on server SKU */
msr_write(MSR_PKG_POWER_LIMIT, limit);
/* Set power limit values in MCHBAR as well */
writel(limit.lo, MCHBAR_REG(MCH_PKG_POWER_LIMIT_LO));
writel(limit.hi, MCHBAR_REG(MCH_PKG_POWER_LIMIT_HI));
/* Set DDR RAPL power limit by copying from MMIO to MSR */
msr.lo = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_LO));
msr.hi = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_HI));
msr_write(MSR_DDR_RAPL_LIMIT, msr);
/* Use nominal TDP values for CPUs with configurable TDP */
if (cpu_config_tdp_levels()) {
msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
limit.hi = 0;
limit.lo = msr.lo & 0xff;
msr_write(MSR_TURBO_ACTIVATION_RATIO, limit);
}
}
static int broadwell_get_info(struct udevice *dev, struct cpu_info *info)
{
msr_t msr;
msr = msr_read(IA32_PERF_CTL);
info->cpu_freq = ((msr.lo >> 8) & 0xff) * BROADWELL_BCLK * 1000000;
info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU |
1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID;
return 0;
}
static int broadwell_get_count(struct udevice *dev)
{
return 4;
}
static int cpu_x86_broadwell_probe(struct udevice *dev)
{
if (dev->seq == 0) {
cpu_core_init(dev);
return broadwell_init(dev);
}
return 0;
}
static const struct cpu_ops cpu_x86_broadwell_ops = {
.get_desc = cpu_x86_get_desc,
.get_info = broadwell_get_info,
.get_count = broadwell_get_count,
.get_vendor = cpu_x86_get_vendor,
};
static const struct udevice_id cpu_x86_broadwell_ids[] = {
{ .compatible = "intel,core-i3-gen5" },
{ }
};
U_BOOT_DRIVER(cpu_x86_broadwell_drv) = {
.name = "cpu_x86_broadwell",
.id = UCLASS_CPU,
.of_match = cpu_x86_broadwell_ids,
.bind = cpu_x86_bind,
.probe = cpu_x86_broadwell_probe,
.ops = &cpu_x86_broadwell_ops,
.priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv),
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -6,8 +6,108 @@
#include <common.h>
#include <dm.h>
#include <asm/io.h>
#include <asm/mrc_common.h>
#include <asm/arch/iomap.h>
#include <asm/arch/pch.h>
#include <asm/arch/pei_data.h>
__weak asmlinkage void sdram_console_tx_byte(unsigned char byte)
{
#ifdef DEBUG
putc(byte);
#endif
}
void broadwell_fill_pei_data(struct pei_data *pei_data)
{
pei_data->pei_version = PEI_VERSION;
pei_data->board_type = BOARD_TYPE_ULT;
pei_data->pciexbar = MCFG_BASE_ADDRESS;
pei_data->smbusbar = SMBUS_BASE_ADDRESS;
pei_data->ehcibar = EARLY_EHCI_BAR;
pei_data->xhcibar = EARLY_XHCI_BAR;
pei_data->gttbar = EARLY_GTT_BAR;
pei_data->pmbase = ACPI_BASE_ADDRESS;
pei_data->gpiobase = GPIO_BASE_ADDRESS;
pei_data->tseg_size = CONFIG_SMM_TSEG_SIZE;
pei_data->temp_mmio_base = EARLY_TEMP_MMIO;
pei_data->tx_byte = sdram_console_tx_byte;
pei_data->ddr_refresh_2x = 1;
}
static void pei_data_usb2_port(struct pei_data *pei_data, int port, uint length,
uint enable, uint oc_pin, uint location)
{
pei_data->usb2_ports[port].length = length;
pei_data->usb2_ports[port].enable = enable;
pei_data->usb2_ports[port].oc_pin = oc_pin;
pei_data->usb2_ports[port].location = location;
}
static void pei_data_usb3_port(struct pei_data *pei_data, int port, uint enable,
uint oc_pin, uint fixed_eq)
{
pei_data->usb3_ports[port].enable = enable;
pei_data->usb3_ports[port].oc_pin = oc_pin;
pei_data->usb3_ports[port].fixed_eq = fixed_eq;
}
void mainboard_fill_pei_data(struct pei_data *pei_data)
{
/* DQ byte map for Samus board */
const u8 dq_map[2][6][2] = {
{ { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 },
{ 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } },
{ { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 },
{ 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } } };
/* DQS CPU<>DRAM map for Samus board */
const u8 dqs_map[2][8] = {
{ 2, 0, 1, 3, 6, 4, 7, 5 },
{ 2, 1, 0, 3, 6, 5, 4, 7 } };
pei_data->ec_present = 1;
/* One installed DIMM per channel */
pei_data->dimm_channel0_disabled = 2;
pei_data->dimm_channel1_disabled = 2;
memcpy(pei_data->dq_map, dq_map, sizeof(dq_map));
memcpy(pei_data->dqs_map, dqs_map, sizeof(dqs_map));
/* P0: HOST PORT */
pei_data_usb2_port(pei_data, 0, 0x0080, 1, 0,
USB_PORT_BACK_PANEL);
/* P1: HOST PORT */
pei_data_usb2_port(pei_data, 1, 0x0080, 1, 1,
USB_PORT_BACK_PANEL);
/* P2: RAIDEN */
pei_data_usb2_port(pei_data, 2, 0x0080, 1, USB_OC_PIN_SKIP,
USB_PORT_BACK_PANEL);
/* P3: SD CARD */
pei_data_usb2_port(pei_data, 3, 0x0040, 1, USB_OC_PIN_SKIP,
USB_PORT_INTERNAL);
/* P4: RAIDEN */
pei_data_usb2_port(pei_data, 4, 0x0080, 1, USB_OC_PIN_SKIP,
USB_PORT_BACK_PANEL);
/* P5: WWAN (Disabled) */
pei_data_usb2_port(pei_data, 5, 0x0000, 0, USB_OC_PIN_SKIP,
USB_PORT_SKIP);
/* P6: CAMERA */
pei_data_usb2_port(pei_data, 6, 0x0040, 1, USB_OC_PIN_SKIP,
USB_PORT_INTERNAL);
/* P7: BT */
pei_data_usb2_port(pei_data, 7, 0x0040, 1, USB_OC_PIN_SKIP,
USB_PORT_INTERNAL);
/* P1: HOST PORT */
pei_data_usb3_port(pei_data, 0, 1, 0, 0);
/* P2: HOST PORT */
pei_data_usb3_port(pei_data, 1, 1, 1, 0);
/* P3: RAIDEN */
pei_data_usb3_port(pei_data, 2, 1, USB_OC_PIN_SKIP, 0);
/* P4: RAIDEN */
pei_data_usb3_port(pei_data, 3, 1, USB_OC_PIN_SKIP, 0);
}
static int broadwell_northbridge_early_init(struct udevice *dev)
{

View File

@ -599,10 +599,16 @@ static int broadwell_pch_init(struct udevice *dev)
static int broadwell_pch_probe(struct udevice *dev)
{
if (!(gd->flags & GD_FLG_RELOC))
return broadwell_pch_early_init(dev);
else
if (CONFIG_IS_ENABLED(X86_32BIT_INIT)) {
if (!(gd->flags & GD_FLG_RELOC))
return broadwell_pch_early_init(dev);
else
return broadwell_pch_init(dev);
} else if (IS_ENABLED(CONFIG_SPL) && !IS_ENABLED(CONFIG_SPL_BUILD)) {
return broadwell_pch_init(dev);
} else {
return 0;
}
}
static int broadwell_pch_get_spi_base(struct udevice *dev, ulong *sbasep)
@ -630,10 +636,35 @@ static int broadwell_get_gpio_base(struct udevice *dev, u32 *gbasep)
return 0;
}
static int broadwell_ioctl(struct udevice *dev, enum pch_req_t req, void *data,
int size)
{
switch (req) {
case PCH_REQ_PMBASE_INFO: {
struct pch_pmbase_info *pm = data;
int ret;
/* Find the base address of the powermanagement registers */
ret = dm_pci_read_config16(dev, 0x40, &pm->base);
if (ret)
return ret;
pm->base &= 0xfffe;
pm->gpio0_en_ofs = GPE0_EN(0);
pm->pm1_sts_ofs = PM1_STS;
pm->pm1_cnt_ofs = PM1_CNT;
return 0;
}
default:
return -ENOSYS;
}
}
static const struct pch_ops broadwell_pch_ops = {
.get_spi_base = broadwell_pch_get_spi_base,
.set_spi_protect = broadwell_set_spi_protect,
.get_gpio_base = broadwell_get_gpio_base,
.ioctl = broadwell_ioctl,
};
static const struct udevice_id broadwell_pch_ids[] = {

View File

@ -34,99 +34,6 @@ int dram_init_banksize(void)
return 0;
}
void broadwell_fill_pei_data(struct pei_data *pei_data)
{
pei_data->pei_version = PEI_VERSION;
pei_data->board_type = BOARD_TYPE_ULT;
pei_data->pciexbar = MCFG_BASE_ADDRESS;
pei_data->smbusbar = SMBUS_BASE_ADDRESS;
pei_data->ehcibar = EARLY_EHCI_BAR;
pei_data->xhcibar = EARLY_XHCI_BAR;
pei_data->gttbar = EARLY_GTT_BAR;
pei_data->pmbase = ACPI_BASE_ADDRESS;
pei_data->gpiobase = GPIO_BASE_ADDRESS;
pei_data->tseg_size = CONFIG_SMM_TSEG_SIZE;
pei_data->temp_mmio_base = EARLY_TEMP_MMIO;
pei_data->tx_byte = sdram_console_tx_byte;
pei_data->ddr_refresh_2x = 1;
}
static inline void pei_data_usb2_port(struct pei_data *pei_data, int port,
uint16_t length, uint8_t enable,
uint8_t oc_pin, uint8_t location)
{
pei_data->usb2_ports[port].length = length;
pei_data->usb2_ports[port].enable = enable;
pei_data->usb2_ports[port].oc_pin = oc_pin;
pei_data->usb2_ports[port].location = location;
}
static inline void pei_data_usb3_port(struct pei_data *pei_data, int port,
uint8_t enable, uint8_t oc_pin,
uint8_t fixed_eq)
{
pei_data->usb3_ports[port].enable = enable;
pei_data->usb3_ports[port].oc_pin = oc_pin;
pei_data->usb3_ports[port].fixed_eq = fixed_eq;
}
void mainboard_fill_pei_data(struct pei_data *pei_data)
{
/* DQ byte map for Samus board */
const u8 dq_map[2][6][2] = {
{ { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 },
{ 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } },
{ { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 },
{ 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } } };
/* DQS CPU<>DRAM map for Samus board */
const u8 dqs_map[2][8] = {
{ 2, 0, 1, 3, 6, 4, 7, 5 },
{ 2, 1, 0, 3, 6, 5, 4, 7 } };
pei_data->ec_present = 1;
/* One installed DIMM per channel */
pei_data->dimm_channel0_disabled = 2;
pei_data->dimm_channel1_disabled = 2;
memcpy(pei_data->dq_map, dq_map, sizeof(dq_map));
memcpy(pei_data->dqs_map, dqs_map, sizeof(dqs_map));
/* P0: HOST PORT */
pei_data_usb2_port(pei_data, 0, 0x0080, 1, 0,
USB_PORT_BACK_PANEL);
/* P1: HOST PORT */
pei_data_usb2_port(pei_data, 1, 0x0080, 1, 1,
USB_PORT_BACK_PANEL);
/* P2: RAIDEN */
pei_data_usb2_port(pei_data, 2, 0x0080, 1, USB_OC_PIN_SKIP,
USB_PORT_BACK_PANEL);
/* P3: SD CARD */
pei_data_usb2_port(pei_data, 3, 0x0040, 1, USB_OC_PIN_SKIP,
USB_PORT_INTERNAL);
/* P4: RAIDEN */
pei_data_usb2_port(pei_data, 4, 0x0080, 1, USB_OC_PIN_SKIP,
USB_PORT_BACK_PANEL);
/* P5: WWAN (Disabled) */
pei_data_usb2_port(pei_data, 5, 0x0000, 0, USB_OC_PIN_SKIP,
USB_PORT_SKIP);
/* P6: CAMERA */
pei_data_usb2_port(pei_data, 6, 0x0040, 1, USB_OC_PIN_SKIP,
USB_PORT_INTERNAL);
/* P7: BT */
pei_data_usb2_port(pei_data, 7, 0x0040, 1, USB_OC_PIN_SKIP,
USB_PORT_INTERNAL);
/* P1: HOST PORT */
pei_data_usb3_port(pei_data, 0, 1, 0, 0);
/* P2: HOST PORT */
pei_data_usb3_port(pei_data, 1, 1, 1, 0);
/* P3: RAIDEN */
pei_data_usb3_port(pei_data, 2, 1, USB_OC_PIN_SKIP, 0);
/* P4: RAIDEN */
pei_data_usb3_port(pei_data, 3, 1, USB_OC_PIN_SKIP, 0);
}
static unsigned long get_top_of_ram(struct udevice *dev)
{
/*
@ -204,16 +111,18 @@ int dram_init(void)
/* Print ME state before MRC */
ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev);
if (ret)
if (ret) {
debug("Cannot get ME (err=%d)\n", ret);
return ret;
}
intel_me_status(me_dev);
/* Save ME HSIO version */
ret = uclass_first_device(UCLASS_PCH, &pch_dev);
if (ret)
ret = uclass_first_device_err(UCLASS_PCH, &pch_dev);
if (ret) {
debug("Cannot get PCH (err=%d)\n", ret);
return ret;
if (!pch_dev)
return -ENODEV;
}
power_state_get(pch_dev, &ps);
intel_me_hsio_version(me_dev, &ps.hsio_version, &ps.hsio_checksum);
@ -221,15 +130,17 @@ int dram_init(void)
broadwell_fill_pei_data(pei_data);
mainboard_fill_pei_data(pei_data);
ret = uclass_first_device(UCLASS_NORTHBRIDGE, &dev);
if (ret)
ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev);
if (ret) {
debug("Cannot get Northbridge (err=%d)\n", ret);
return ret;
if (!dev)
return -ENODEV;
}
size = 256;
ret = mrc_locate_spd(dev, size, &spd_data);
if (ret)
if (ret) {
debug("Cannot locate SPD (err=%d)\n", ret);
return ret;
}
memcpy(pei_data->spd_data[0][0], spd_data, size);
memcpy(pei_data->spd_data[1][0], spd_data, size);
@ -239,13 +150,17 @@ int dram_init(void)
debug("PEI version %#x\n", pei_data->pei_version);
ret = mrc_common_init(dev, pei_data, true);
if (ret)
if (ret) {
debug("mrc_common_init() failed(err=%d)\n", ret);
return ret;
}
debug("Memory init done\n");
ret = sdram_find(dev);
if (ret)
if (ret) {
debug("sdram_find() failed (err=%d)\n", ret);
return ret;
}
gd->ram_size = gd->arch.meminfo.total_32bit_memory;
debug("RAM size %llx\n", (unsigned long long)gd->ram_size);
@ -279,17 +194,6 @@ int misc_init_r(void)
return 0;
}
void board_debug_uart_init(void)
{
struct udevice *bus = NULL;
/* com1 / com2 decode range */
pci_x86_write_config(bus, PCH_DEV_LPC, LPC_IO_DEC, 1 << 4, PCI_SIZE_16);
pci_x86_write_config(bus, PCH_DEV_LPC, LPC_EN, COMA_LPC_EN,
PCI_SIZE_16);
}
static const struct udevice_id broadwell_syscon_ids[] = {
{ .compatible = "intel,me", .data = X86_SYSCON_ME },
{ }

View File

@ -309,21 +309,22 @@ u32 cpu_get_stepping(void)
return gd->arch.x86_mask;
}
int x86_cpu_init_f(void)
/* initialise FPU, reset EM, set MP and NE */
static void setup_cpu_features(void)
{
const u32 em_rst = ~X86_CR0_EM;
const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE;
if (ll_boot_init()) {
/* initialize FPU, reset EM, set MP and NE */
asm ("fninit\n" \
"movl %%cr0, %%eax\n" \
"andl %0, %%eax\n" \
"orl %1, %%eax\n" \
"movl %%eax, %%cr0\n" \
: : "i" (em_rst), "i" (mp_ne_set) : "eax");
}
asm ("fninit\n" \
"movl %%cr0, %%eax\n" \
"andl %0, %%eax\n" \
"orl %1, %%eax\n" \
"movl %%eax, %%cr0\n" \
: : "i" (em_rst), "i" (mp_ne_set) : "eax");
}
static void setup_identity(void)
{
/* identify CPU via cpuid and store the decoded info into gd->arch */
if (has_cpuid()) {
struct cpu_device_id cpu;
@ -339,46 +340,70 @@ int x86_cpu_init_f(void)
gd->arch.has_mtrr = has_mtrr();
}
/* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */
}
/* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */
static void setup_pci_ram_top(void)
{
gd->pci_ram_top = 0x80000000U;
}
static void setup_mtrr(void)
{
u64 mtrr_cap;
/* Configure fixed range MTRRs for some legacy regions */
if (gd->arch.has_mtrr) {
u64 mtrr_cap;
if (!gd->arch.has_mtrr)
return;
mtrr_cap = native_read_msr(MTRR_CAP_MSR);
if (mtrr_cap & MTRR_CAP_FIX) {
/* Mark the VGA RAM area as uncacheable */
native_write_msr(MTRR_FIX_16K_A0000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE),
MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE));
mtrr_cap = native_read_msr(MTRR_CAP_MSR);
if (mtrr_cap & MTRR_CAP_FIX) {
/* Mark the VGA RAM area as uncacheable */
native_write_msr(MTRR_FIX_16K_A0000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE),
MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE));
/*
* Mark the PCI ROM area as cacheable to improve ROM
* execution performance.
*/
native_write_msr(MTRR_FIX_4K_C0000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
native_write_msr(MTRR_FIX_4K_C8000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
native_write_msr(MTRR_FIX_4K_D0000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
native_write_msr(MTRR_FIX_4K_D8000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
/*
* Mark the PCI ROM area as cacheable to improve ROM
* execution performance.
*/
native_write_msr(MTRR_FIX_4K_C0000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
native_write_msr(MTRR_FIX_4K_C8000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
native_write_msr(MTRR_FIX_4K_D0000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
native_write_msr(MTRR_FIX_4K_D8000_MSR,
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
/* Enable the fixed range MTRRs */
msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN);
}
/* Enable the fixed range MTRRs */
msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN);
}
}
int x86_cpu_init_f(void)
{
if (ll_boot_init())
setup_cpu_features();
setup_identity();
setup_mtrr();
setup_pci_ram_top();
#ifdef CONFIG_I8254_TIMER
/* Set up the i8254 timer if required */
i8254_init();
#endif
if (IS_ENABLED(CONFIG_I8254_TIMER))
i8254_init();
return 0;
}
int x86_cpu_reinit_f(void)
{
setup_identity();
setup_pci_ram_top();
return 0;
}

View File

@ -3,14 +3,23 @@
# Copyright (c) 2016 Google, Inc
ifdef CONFIG_HAVE_MRC
obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += car.o
obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += me_status.o
obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += report_platform.o
obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += mrc.o
obj-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += car.o
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += me_status.o
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += report_platform.o
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += mrc.o
endif
obj-y += cpu.o
obj-y += lpc.o
ifndef CONFIG_TARGET_EFI_APP
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o
ifndef CONFIG_$(SPL_)X86_64
obj-y += microcode.o
endif
endif
obj-y += pch.o
ifdef CONFIG_SPL
ifndef CONFIG_SPL_BUILD
obj-y += cpu_from_spl.o
endif
endif

View File

@ -235,7 +235,7 @@ mtrr_table_end:
.align 4
_dt_ucode_base_size:
/* These next two fields are filled in by ifdtool */
/* These next two fields are filled in by binman */
.globl ucode_base
ucode_base: /* Declared in microcode.h */
.long 0 /* microcode base */

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 Google, Inc
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/cpu_common.h>
#include <asm/intel_regs.h>
#include <asm/lapic.h>
#include <asm/lpc_common.h>
#include <asm/msr.h>
#include <asm/mtrr.h>
#include <asm/post.h>
#include <asm/microcode.h>
DECLARE_GLOBAL_DATA_PTR;
int arch_cpu_init(void)
{
int ret;
ret = x86_cpu_reinit_f();
return ret;
}

View File

@ -229,6 +229,21 @@ static int bd82x6x_ioctl(struct udevice *dev, enum pch_req_t req, void *data,
return -ENOENT;
return val & RCBA_AUDIO_CONFIG_MASK;
case PCH_REQ_PMBASE_INFO: {
struct pch_pmbase_info *pm = data;
int ret;
/* Find the base address of the powermanagement registers */
ret = dm_pci_read_config16(dev, 0x40, &pm->base);
if (ret)
return ret;
pm->base &= 0xfffe;
pm->gpio0_en_ofs = GPE0_EN;
pm->pm1_sts_ofs = PM1_STS;
pm->pm1_cnt_ofs = PM1_CNT;
return 0;
}
default:
return -ENOSYS;
}

View File

@ -322,7 +322,7 @@ static int start_aps(int ap_count, atomic_t *num_aps)
if (sipi_vector > max_vector_loc) {
printf("SIPI vector too large! 0x%08x\n",
sipi_vector);
return -1;
return -ENOSPC;
}
debug("Attempting to start %d APs\n", ap_count);
@ -364,7 +364,7 @@ static int start_aps(int ap_count, atomic_t *num_aps)
if (wait_for_aps(num_aps, ap_count, 10000, 50)) {
debug("Not all APs checked in: %d/%d\n",
atomic_read(num_aps), ap_count);
return -1;
return -EIO;
}
return 0;
@ -387,7 +387,7 @@ static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params)
if (wait_for_aps(&rec->cpus_entered, num_aps,
timeout_us, step_us)) {
debug("MP record %d timeout\n", i);
ret = -1;
ret = -ETIMEDOUT;
}
}
@ -508,7 +508,7 @@ int mp_init(struct mp_params *p)
if (p == NULL || p->flight_plan == NULL || p->num_records < 1) {
printf("Invalid MP parameters\n");
return -1;
return -EINVAL;
}
num_cpus = cpu_get_count(cpu);
@ -531,7 +531,7 @@ int mp_init(struct mp_params *p)
/* Load the SIPI vector */
ret = load_sipi_vector(&ap_count, num_cpus);
if (ap_count == NULL)
return -1;
return -ENOENT;
/*
* Make sure SIPI data hits RAM so the APs that come up will see

View File

@ -190,6 +190,19 @@ board_init_f_r_trampoline:
/* Re-enter U-Boot by calling board_init_f_r() */
call board_init_f_r
#ifdef CONFIG_TPL
.globl jump_to_spl
.type jump_to_spl, @function
jump_to_spl:
/* Reset stack to the top of CAR space */
movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %esp
#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE
subl $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %esp
#endif
jmp *%eax
#endif
die:
hlt
jmp die

View File

@ -2,7 +2,7 @@
/*
* 64-bit x86 Startup Code
*
* (C) Copyright 216 Google, Inc
* Copyright 2019 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/

View File

@ -0,0 +1,71 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* 32-bit x86 Startup Code when running from SPL
*
* Copyright 2018 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <config.h>
.section .text.start
.code32
.globl _start
.type _start, @function
_start:
/* Set up memory using the existing stack */
movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %eax
#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE
subl $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %eax
#endif
/*
* We don't subject CONFIG_DCACHE_RAM_MRC_VAR_SIZE since memory is
* already set up. This has the happy side-effect of putting gd in a
* new place separate from SPL, so the memset() in
* board_init_f_init_reserve() does not cause any problems (otherwise
* it would zero out the gd and crash)
*/
call board_init_f_alloc_reserve
mov %eax, %esp
call board_init_f_init_reserve
xorl %eax, %eax
call board_init_f
call board_init_f_r
/* Should not return here */
jmp .
.globl board_init_f_r_trampoline
.type board_init_f_r_trampoline, @function
board_init_f_r_trampoline:
/*
* SPL has been executed and SDRAM has been initialised, U-Boot code
* has been copied into RAM, BSS has been cleared and relocation
* adjustments have been made. It is now time to jump into the in-RAM
* copy of U-Boot
*
* %eax = Address of top of new stack
*/
/* Stack grows down from top of SDRAM */
movl %eax, %esp
/* Re-enter U-Boot by calling board_init_f_r() */
call board_init_f_r
die:
hlt
jmp die
hlt
.align 4
_dt_ucode_base_size:
/* These next two fields are filled in by binman */
.globl ucode_base
ucode_base: /* Declared in microcode.h */
.long 0 /* microcode base */
.globl ucode_size
ucode_size: /* Declared in microcode.h */
.long 0 /* microcode size */

View File

@ -0,0 +1,49 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* 32-bit x86 Startup Code when running from TPL
*
* Copyright 2018 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <config.h>
.section .text.start
.code32
.globl _start
.type _start, @function
_start:
/* Set up memory using the existing stack */
mov %esp, %eax
call board_init_f_alloc_reserve
mov %eax, %esp
call board_init_f_init_reserve
xorl %eax, %eax
call board_init_f
call board_init_f_r
/* Should not return here */
jmp .
.globl board_init_f_r_trampoline
.type board_init_f_r_trampoline, @function
board_init_f_r_trampoline:
/*
* TPL has been executed: SDRAM has been initialised, BSS has been
* cleared.
*
* %eax = Address of top of new stack
*/
/* Stack grows down from top of SDRAM */
movl %eax, %esp
/* Re-enter SPL by calling board_init_f_r() */
call board_init_f_r
die:
hlt
jmp die
hlt

View File

@ -54,7 +54,7 @@ SECTIONS
/DISCARD/ : { *(.interp*) }
/DISCARD/ : { *(.gnu*) }
#ifdef CONFIG_SPL_X86_16BIT_INIT
#if defined(CONFIG_SPL_X86_16BIT_INIT) || defined(CONFIG_TPL_X86_16BIT_INIT)
/*
* The following expressions place the 16-bit Real-Mode code and
* Reset Vector at the end of the Flash ROM

View File

@ -61,3 +61,8 @@ int print_cpuinfo(void)
{
return 0;
}
int x86_cpu_reinit_f(void)
{
return 0;
}

View File

@ -9,6 +9,12 @@
/include/ "rtc.dtsi"
/include/ "tsc_timer.dtsi"
#ifdef CONFIG_CHROMEOS
#include "chromeos-x86.dtsi"
#include "flashmap-x86-ro.dtsi"
#include "flashmap-8mb-rw.dtsi"
#endif
/ {
model = "Google Samus";
compatible = "google,samus", "intel,broadwell";
@ -17,6 +23,7 @@
spi0 = &spi;
usb0 = &usb_0;
usb1 = &usb_1;
cros-ec0 = &cros_ec;
};
config {
@ -73,6 +80,7 @@
/* Put this first: it is the default */
gpio_unused: gpio-unused {
u-boot,dm-pre-reloc;
mode-gpio;
direction = <PIN_INPUT>;
owner = <OWNER_GPIO>;
@ -80,6 +88,7 @@
};
gpio_acpi_sci: acpi-sci {
u-boot,dm-pre-reloc;
mode-gpio;
direction = <PIN_INPUT>;
invert;
@ -87,6 +96,7 @@
};
gpio_acpi_smi: acpi-smi {
u-boot,dm-pre-reloc;
mode-gpio;
direction = <PIN_INPUT>;
invert;
@ -94,12 +104,14 @@
};
gpio_input: gpio-input {
u-boot,dm-pre-reloc;
mode-gpio;
direction = <PIN_INPUT>;
owner = <OWNER_GPIO>;
};
gpio_input_invert: gpio-input-invert {
u-boot,dm-pre-reloc;
mode-gpio;
direction = <PIN_INPUT>;
owner = <OWNER_GPIO>;
@ -107,9 +119,11 @@
};
gpio_native: gpio-native {
u-boot,dm-pre-reloc;
};
gpio_out_high: gpio-out-high {
u-boot,dm-pre-reloc;
mode-gpio;
direction = <PIN_OUTPUT>;
output-value = <1>;
@ -118,6 +132,7 @@
};
gpio_out_low: gpio-out-low {
u-boot,dm-pre-reloc;
mode-gpio;
direction = <PIN_OUTPUT>;
output-value = <0>;
@ -126,6 +141,7 @@
};
gpio_pirq: gpio-pirq {
u-boot,dm-pre-reloc;
mode-gpio;
direction = <PIN_INPUT>;
owner = <OWNER_GPIO>;
@ -133,6 +149,7 @@
};
soc_gpio@0 {
u-boot,dm-pre-reloc;
config =
<0 &gpio_unused 0>, /* unused */
<1 &gpio_unused 0>, /* unused */
@ -250,8 +267,10 @@
spd {
#address-cells = <1>;
#size-cells = <0>;
u-boot,dm-pre-reloc;
samsung_4 {
reg = <6>;
u-boot,dm-pre-reloc;
data = [91 20 f1 03 04 11 05 0b
03 11 01 08 0a 00 50 01
78 78 90 50 90 11 50 e0
@ -291,6 +310,7 @@
* columns 10, density 4096 mb, x32
*/
reg = <8>;
u-boot,dm-pre-reloc;
data = [91 20 f1 03 04 11 05 0b
03 11 01 08 0a 00 50 01
78 78 90 50 90 11 50 e0
@ -326,6 +346,7 @@
};
samsung_8 {
reg = <10>;
u-boot,dm-pre-reloc;
data = [91 20 f1 03 04 12 05 0a
03 11 01 08 0a 00 50 01
78 78 90 50 90 11 50 e0
@ -365,6 +386,7 @@
* columns 11, density 4096 mb, x16
*/
reg = <12>;
u-boot,dm-pre-reloc;
data = [91 20 f1 03 04 12 05 0a
03 11 01 08 0a 00 50 01
78 78 90 50 90 11 50 e0
@ -404,6 +426,7 @@
* columns 11, density 8192 mb, x16
*/
reg = <13>;
u-boot,dm-pre-reloc;
data = [91 20 f1 03 05 1a 05 0a
03 11 01 08 0a 00 50 01
78 78 90 50 90 11 50 e0
@ -443,6 +466,7 @@
* columns 11, density 8192 mb, x16
*/
reg = <15>;
u-boot,dm-pre-reloc;
data = [91 20 f1 03 05 1a 05 0a
03 11 01 08 0a 00 50 01
78 78 90 50 90 11 50 e0
@ -540,7 +564,7 @@
compatible = "ehci-pci";
};
pch@1f,0 {
pch: pch@1f,0 {
reg = <0x0000f800 0 0 0 0>;
compatible = "intel,broadwell-pch";
u-boot,dm-pre-reloc;
@ -559,10 +583,12 @@
power-enable-gpio = <&gpio_a 23 0>;
spi: spi {
u-boot,dm-pre-reloc;
#address-cells = <1>;
#size-cells = <0>;
compatible = "intel,ich9-spi";
spi-flash@0 {
fwstore_spi: spi-flash@0 {
u-boot,dm-pre-reloc;
#size-cells = <1>;
#address-cells = <1>;
reg = <0>;
@ -570,6 +596,7 @@
"jedec,spi-nor";
memory-map = <0xff800000 0x00800000>;
rw-mrc-cache {
u-boot,dm-pre-reloc;
label = "rw-mrc-cache";
reg = <0x003e0000 0x00010000>;
};
@ -609,7 +636,8 @@
#size-cells = <0>;
u-boot,dm-pre-reloc;
intel,gen-dec = <0x800 0xfc 0x900 0xfc>;
cros-ec@200 {
cros_ec: cros-ec {
u-boot,dm-pre-reloc;
compatible = "google,cros-ec-lpc";
reg = <0x204 1 0x200 1 0x880 0x80>;
@ -630,7 +658,7 @@
sata@1f,2 {
compatible = "intel,wildcatpoint-ahci";
reg = <0x0000fa00 0 0 0 0>;
u-boot,dm-pre-reloc;
u-boot,dm-pre-proper;
intel,sata-mode = "ahci";
intel,sata-port-map = <1>;
intel,sata-port0-gen3-tx = <0x72>;
@ -645,12 +673,19 @@
};
tpm {
u-boot,dm-pre-reloc;
reg = <0xfed40000 0x5000>;
compatible = "infineon,slb9635lpc";
secdata {
u-boot,dm-pre-reloc;
compatible = "google,tpm-secdata";
};
};
microcode {
u-boot,dm-pre-reloc;
update@0 {
u-boot,dm-pre-reloc;
#include "microcode/mc0306d4_00000018.dtsi"
};
};
@ -668,3 +703,13 @@
};
};
&rtc {
#address-cells = <1>;
#size-cells = <0>;
nvdata {
u-boot,dm-pre-reloc;
compatible = "google,cmos-nvdata";
reg = <0x26>;
};
};

View File

@ -1,5 +1,5 @@
/ {
reset {
reset: reset {
compatible = "x86,reset";
u-boot,dm-pre-reloc;
};

View File

@ -1,5 +1,5 @@
/ {
rtc {
rtc: rtc {
compatible = "motorola,mc146818";
u-boot,dm-pre-reloc;
reg = <0x70 2>;

View File

@ -6,86 +6,128 @@
#include <config.h>
#ifdef CONFIG_ROM_SIZE
#ifdef CONFIG_CHROMEOS
/ {
binman {
filename = "u-boot.rom";
end-at-4gb;
sort-by-offset;
pad-byte = <0xff>;
size = <CONFIG_ROM_SIZE>;
#ifdef CONFIG_HAVE_INTEL_ME
intel-descriptor {
filename = CONFIG_FLASH_DESCRIPTOR_FILE;
};
intel-me {
filename = CONFIG_INTEL_ME_FILE;
};
#endif
#ifdef CONFIG_SPL
u-boot-spl-with-ucode-ptr {
offset = <CONFIG_SPL_TEXT_BASE>;
};
u-boot-dtb-with-ucode2 {
type = "u-boot-dtb-with-ucode";
};
u-boot {
offset = <0xfff00000>;
multiple-images;
rom: rom {
};
};
};
#else
u-boot-with-ucode-ptr {
offset = <CONFIG_SYS_TEXT_BASE>;
};
#endif
u-boot-dtb-with-ucode {
};
u-boot-ucode {
align = <16>;
};
#ifdef CONFIG_HAVE_MRC
intel-mrc {
offset = <CONFIG_X86_MRC_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_FSP
intel-fsp {
filename = CONFIG_FSP_FILE;
offset = <CONFIG_FSP_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_CMC
intel-cmc {
filename = CONFIG_CMC_FILE;
offset = <CONFIG_CMC_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_VGA_BIOS
intel-vga {
filename = CONFIG_VGA_BIOS_FILE;
offset = <CONFIG_VGA_BIOS_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_VBT
intel-vbt {
filename = CONFIG_VBT_FILE;
offset = <CONFIG_VBT_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_REFCODE
intel-refcode {
offset = <CONFIG_X86_REFCODE_ADDR>;
};
#endif
#ifdef CONFIG_SPL
x86-start16-spl {
offset = <CONFIG_SYS_X86_START16>;
};
#else
x86-start16 {
offset = <CONFIG_SYS_X86_START16>;
};
#endif
/ {
rom: binman {
};
};
#endif
#ifdef CONFIG_ROM_SIZE
&rom {
filename = "u-boot.rom";
end-at-4gb;
sort-by-offset;
pad-byte = <0xff>;
size = <CONFIG_ROM_SIZE>;
#ifdef CONFIG_HAVE_INTEL_ME
intel-descriptor {
filename = CONFIG_FLASH_DESCRIPTOR_FILE;
};
intel-me {
filename = CONFIG_INTEL_ME_FILE;
};
#endif
#ifdef CONFIG_TPL
u-boot-tpl-with-ucode-ptr {
offset = <CONFIG_TPL_TEXT_BASE>;
};
u-boot-tpl-dtb {
};
u-boot-spl {
offset = <CONFIG_SPL_TEXT_BASE>;
};
u-boot-spl-dtb {
};
u-boot {
offset = <CONFIG_SYS_TEXT_BASE>;
};
#elif defined(CONFIG_SPL)
u-boot-spl-with-ucode-ptr {
offset = <CONFIG_SPL_TEXT_BASE>;
};
u-boot-dtb-with-ucode2 {
type = "u-boot-dtb-with-ucode";
};
u-boot {
/*
* TODO(sjg@chromium.org):
* Normally we use CONFIG_SYS_TEXT_BASE as the flash offset. But
* for boards with textbase in SDRAM we cannot do this. Just use
* an assumed-valid value (1MB before the end of flash) here so
* that we can actually build an image for coreboot, etc.
* We need a better solution, perhaps a separate Kconfig.
*/
#if CONFIG_SYS_TEXT_BASE == 0x1110000
offset = <0xfff00000>;
#else
offset = <CONFIG_SYS_TEXT_BASE>;
#endif
};
#else
u-boot-with-ucode-ptr {
offset = <CONFIG_SYS_TEXT_BASE>;
};
#endif
u-boot-dtb-with-ucode {
};
u-boot-ucode {
align = <16>;
};
#ifdef CONFIG_HAVE_MRC
intel-mrc {
offset = <CONFIG_X86_MRC_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_FSP
intel-fsp {
filename = CONFIG_FSP_FILE;
offset = <CONFIG_FSP_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_CMC
intel-cmc {
filename = CONFIG_CMC_FILE;
offset = <CONFIG_CMC_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_VGA_BIOS
intel-vga {
filename = CONFIG_VGA_BIOS_FILE;
offset = <CONFIG_VGA_BIOS_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_VBT
intel-vbt {
filename = CONFIG_VBT_FILE;
offset = <CONFIG_VBT_ADDR>;
};
#endif
#ifdef CONFIG_HAVE_REFCODE
intel-refcode {
offset = <CONFIG_X86_REFCODE_ADDR>;
};
#endif
#ifdef CONFIG_TPL
x86-start16-tpl {
offset = <CONFIG_SYS_X86_START16>;
};
#elif defined(CONFIG_SPL)
x86-start16-spl {
offset = <CONFIG_SYS_X86_START16>;
};
#else
x86-start16 {
offset = <CONFIG_SYS_X86_START16>;
};
#endif
};
#endif

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Architecture-specific SPL handoff information for x86
*
* Copyright 2018 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#ifndef __x86_asm_handoff_h
#define __x86_asm_handoff_h
struct arch_spl_handoff {
};
#endif

View File

@ -103,4 +103,15 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry);
*/
int mrccache_save(void);
/**
* mrccache_spl_save() - Save to the MRC region from SPL
*
* When SPL is used to set up the memory controller we want to save the MRC
* data in SPL to avoid needing to pass it up to U-Boot proper to save. This
* function handles that.
*
* @return 0 if saved to SPI flash successfully, other error if failed
*/
int mrccache_spl_save(void);
#endif /* _ASM_MRCCACHE_H */

View File

@ -2,6 +2,19 @@
/*
* Copyright (C) 2017 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* This file is required for SPL to build, but is empty.
*/
#ifndef __asm_spl_h
#define __asm_spl_h
#define CONFIG_SPL_BOARD_LOAD_IMAGE
enum {
BOOT_DEVICE_SPI = 10,
BOOT_DEVICE_BOARD,
BOOT_DEVICE_CROS_VBOOT,
};
void jump_to_spl(ulong entry);
#endif

View File

@ -13,7 +13,27 @@ extern char gdt_rom[];
/* cpu/.../cpu.c */
int arch_cpu_init(void);
/**
* x86_cpu_init_f() - Set up basic features of the x86 CPU
*
* 0 on success, -ve on error
*/
int x86_cpu_init_f(void);
/**
* x86_cpu_reinit_f() - Set up the CPU a second time
*
* Once cpu_init_f() has been called (e.g. in SPL) we should not call it
* again (e.g. in U-Boot proper) since it sets up the state from scratch.
* Call this function in later phases of U-Boot instead. It reads the CPU
* identify so that CPU functions can be used correctly, but does not change
* anything.
*
* @return 0 (indicating success, to mimic cpu_init_f())
*/
int x86_cpu_reinit_f(void);
int cpu_init_f(void);
void setup_gdt(struct global_data *id, u64 *gdt_addr);
/*

View File

@ -43,7 +43,14 @@ ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_CMD_ZBOOT) += zimage.o
endif
obj-$(CONFIG_HAVE_FSP) += fsp/
obj-$(CONFIG_SPL_BUILD) += spl.o
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_TPL_BUILD
obj-y += tpl.o
else
obj-y += spl.o
endif
endif
lib-$(CONFIG_USE_PRIVATE_LIBGCC) += div64.o

View File

@ -35,7 +35,7 @@ void bootm_announce_and_cleanup(void)
timestamp_add_now(TS_U_BOOT_START_KERNEL);
#endif
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
#ifdef CONFIG_BOOTSTAGE_REPORT
#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
bootstage_report();
#endif

View File

@ -100,7 +100,7 @@ temp_ram_init_romstack:
.long temp_ram_init_params
temp_ram_init_params:
_dt_ucode_base_size:
/* These next two fields are filled in by ifdtool */
/* These next two fields are filled in by binman */
.globl ucode_base
ucode_base: /* Declared in microcode.h */
.long 0 /* microcode base */

View File

@ -18,7 +18,10 @@ __weak ulong board_get_usable_ram_top(ulong total_size)
int init_cache_f_r(void)
{
#if CONFIG_IS_ENABLED(X86_32BIT_INIT) && !defined(CONFIG_HAVE_FSP)
#if (CONFIG_IS_ENABLED(X86_32BIT_INIT) || \
(!defined(CONFIG_SPL_BUILD) && \
!CONFIG_IS_ENABLED(CONFIG_X86_RUN_64BIT))) && \
!defined(CONFIG_HAVE_FSP)
int ret;
ret = mtrr_commit(false);

View File

@ -113,8 +113,10 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry,
ulong base_addr;
int ret;
if (!is_mrc_cache(cur))
if (!is_mrc_cache(cur)) {
debug("%s: Cache data not valid\n", __func__);
return -EINVAL;
}
/* Find the last used block */
base_addr = entry->base + entry->offset;
@ -159,18 +161,11 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry,
return 0;
}
int mrccache_reserve(void)
static void mrccache_setup(void *data)
{
struct mrc_data_container *cache;
struct mrc_data_container *cache = data;
u16 checksum;
if (!gd->arch.mrc_output_len)
return 0;
/* adjust stack pointer to store pure cache data plus the header */
gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE);
cache = (struct mrc_data_container *)gd->start_addr_sp;
cache->signature = MRC_DATA_SIGNATURE;
cache->data_size = gd->arch.mrc_output_len;
checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size);
@ -182,6 +177,16 @@ int mrccache_reserve(void)
/* gd->arch.mrc_output now points to the container */
gd->arch.mrc_output = (char *)cache;
}
int mrccache_reserve(void)
{
if (!gd->arch.mrc_output_len)
return 0;
/* adjust stack pointer to store pure cache data plus the header */
gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE);
mrccache_setup((void *)gd->start_addr_sp);
gd->start_addr_sp &= ~0xf;
@ -202,17 +207,23 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
return -ENOENT;
}
if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2))
if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) {
debug("%s: Cannot find memory map\n", __func__);
return -EINVAL;
}
entry->base = reg[0];
/* Find the place where we put the MRC cache */
mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache");
if (mrc_node < 0)
if (mrc_node < 0) {
debug("%s: Cannot find node\n", __func__);
return -EPERM;
}
if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2))
if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) {
debug("%s: Cannot find address\n", __func__);
return -EINVAL;
}
entry->offset = reg[0];
entry->length = reg[1];
@ -256,3 +267,18 @@ err_entry:
debug("%s: Failed: %d\n", __func__, ret);
return ret;
}
int mrccache_spl_save(void)
{
void *data;
int size;
size = gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE;
data = malloc(size);
if (!data)
return log_msg_ret("Allocate MRC cache block", -ENOMEM);
mrccache_setup(data);
gd->arch.mrc_output = data;
return mrccache_save();
}

View File

@ -5,8 +5,10 @@
#include <common.h>
#include <debug_uart.h>
#include <malloc.h>
#include <spl.h>
#include <asm/cpu.h>
#include <asm/mrccache.h>
#include <asm/mtrr.h>
#include <asm/processor.h>
#include <asm-generic/sections.h>
@ -20,6 +22,7 @@ __weak int arch_cpu_init_dm(void)
static int x86_spl_init(void)
{
#ifndef CONFIG_TPL
/*
* TODO(sjg@chromium.org): We use this area of RAM for the stack
* and global_data in SPL. Once U-Boot starts up and releocates it
@ -27,6 +30,7 @@ static int x86_spl_init(void)
* place it immediately below CONFIG_SYS_TEXT_BASE.
*/
char *ptr = (char *)0x110000;
#endif
int ret;
debug("%s starting\n", __func__);
@ -35,27 +39,44 @@ static int x86_spl_init(void)
debug("%s: spl_init() failed\n", __func__);
return ret;
}
#ifdef CONFIG_TPL
/* Do a mini-init if TPL has already done the full init */
ret = x86_cpu_reinit_f();
#else
ret = arch_cpu_init();
#endif
if (ret) {
debug("%s: arch_cpu_init() failed\n", __func__);
return ret;
}
#ifndef CONFIG_TPL
ret = arch_cpu_init_dm();
if (ret) {
debug("%s: arch_cpu_init_dm() failed\n", __func__);
return ret;
}
#endif
preloader_console_init();
#ifndef CONFIG_TPL
ret = print_cpuinfo();
if (ret) {
debug("%s: print_cpuinfo() failed\n", __func__);
return ret;
}
#endif
ret = dram_init();
if (ret) {
debug("%s: dram_init() failed\n", __func__);
return ret;
}
if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) {
ret = mrccache_spl_save();
if (ret)
debug("%s: Failed to write to mrccache (err=%d)\n",
__func__, ret);
}
#ifndef CONFIG_TPL
memset(&__bss_start, 0, (ulong)&__bss_end - (ulong)&__bss_start);
/* TODO(sjg@chromium.org): Consider calling cpu_init_r() here */
@ -80,9 +101,11 @@ static int x86_spl_init(void)
(1ULL << 32) - CONFIG_XIP_ROM_SIZE,
CONFIG_XIP_ROM_SIZE);
if (ret) {
debug("%s: SPI cache setup failed\n", __func__);
debug("%s: SPI cache setup failed (err=%d)\n", __func__, ret);
return ret;
}
mtrr_commit(true);
#endif
return 0;
}
@ -96,9 +119,17 @@ void board_init_f(ulong flags)
debug("Error %d\n", ret);
hang();
}
#ifdef CONFIG_TPL
gd->bd = malloc(sizeof(*gd->bd));
if (!gd->bd) {
printf("Out of memory for bd_info size %x\n", sizeof(*gd->bd));
hang();
}
board_init_r(gd, 0);
#else
/* Uninit CAR and jump to board_init_f_r() */
board_init_f_r_trampoline(gd->start_addr_sp);
#endif
}
void board_init_f_r(void)
@ -144,6 +175,7 @@ int spl_spi_load_image(void)
return -EPERM;
}
#ifdef CONFIG_X86_RUN_64BIT
void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
{
int ret;
@ -154,3 +186,11 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
while (1)
;
}
#endif
void spl_board_init(void)
{
#ifndef CONFIG_TPL
preloader_console_init();
#endif
}

118
arch/x86/lib/tpl.c Normal file
View File

@ -0,0 +1,118 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 Google, Inc
*/
#include <common.h>
#include <debug_uart.h>
#include <spl.h>
#include <asm/cpu.h>
#include <asm/mtrr.h>
#include <asm/processor.h>
#include <asm-generic/sections.h>
DECLARE_GLOBAL_DATA_PTR;
__weak int arch_cpu_init_dm(void)
{
return 0;
}
static int x86_tpl_init(void)
{
int ret;
debug("%s starting\n", __func__);
ret = spl_init();
if (ret) {
debug("%s: spl_init() failed\n", __func__);
return ret;
}
ret = arch_cpu_init();
if (ret) {
debug("%s: arch_cpu_init() failed\n", __func__);
return ret;
}
ret = arch_cpu_init_dm();
if (ret) {
debug("%s: arch_cpu_init_dm() failed\n", __func__);
return ret;
}
preloader_console_init();
ret = print_cpuinfo();
if (ret) {
debug("%s: print_cpuinfo() failed\n", __func__);
return ret;
}
return 0;
}
void board_init_f(ulong flags)
{
int ret;
ret = x86_tpl_init();
if (ret) {
debug("Error %d\n", ret);
hang();
}
/* Uninit CAR and jump to board_init_f_r() */
board_init_r(gd, 0);
}
void board_init_f_r(void)
{
/* Not used since we never call board_init_f_r_trampoline() */
while (1);
}
u32 spl_boot_device(void)
{
return IS_ENABLED(CONFIG_CHROMEOS) ? BOOT_DEVICE_CROS_VBOOT :
BOOT_DEVICE_BOARD;
}
int spl_start_uboot(void)
{
return 0;
}
void spl_board_announce_boot_device(void)
{
printf("SPI flash");
}
static int spl_board_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
spl_image->size = CONFIG_SYS_MONITOR_LEN; /* We don't know SPL size */
spl_image->entry_point = CONFIG_SPL_TEXT_BASE;
spl_image->load_addr = CONFIG_SPL_TEXT_BASE;
spl_image->os = IH_OS_U_BOOT;
spl_image->name = "U-Boot";
debug("Loading to %lx\n", spl_image->load_addr);
return 0;
}
SPL_LOAD_IMAGE_METHOD("SPI", 0, BOOT_DEVICE_BOARD, spl_board_load_image);
int spl_spi_load_image(void)
{
return -EPERM;
}
void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
{
printf("Jumping to U-Boot SPL at %lx\n", (ulong)spl_image->entry_point);
jump_to_spl(spl_image->entry_point);
while (1)
;
}
void spl_board_init(void)
{
preloader_console_init();
}

View File

@ -52,6 +52,14 @@ config TARGET_CHROMEBOOK_SAMUS
Chrome OS EC connected on LPC, and it provides a 2560x1700 high
resolution touch-enabled LCD display.
config TARGET_CHROMEBOOK_SAMUS_TPL
bool "Chromebook samus booting from TPL"
help
This is a version of Samus which boots into TPL, then to SPL and
U-Boot proper. This is useful where verified boot must select
between different A/B versions of SPL/U-Boot, to allow upgrading of
almost all U-Boot code in the field.
endchoice
source "board/google/chromebook_link/Kconfig"

View File

@ -1,4 +1,4 @@
if TARGET_CHROMEBOOK_SAMUS
if TARGET_CHROMEBOOK_SAMUS || TARGET_CHROMEBOOK_SAMUS_TPL
config SYS_BOARD
default "chromebook_samus"
@ -10,7 +10,8 @@ config SYS_SOC
default "broadwell"
config SYS_CONFIG_NAME
default "chromebook_samus"
default "chromebook_samus" if TARGET_CHROMEBOOK_SAMUS
default "chromebook_samus" if TARGET_CHROMEBOOK_SAMUS_TPL
config SYS_TEXT_BASE
default 0xffe00000
@ -39,3 +40,12 @@ config SYS_CAR_SIZE
default 0x40000
endif
if TARGET_CHROMEBOOK_SAMUS_TPL
config BOARD_SPECIFIC_OPTIONS_TPL # dummy
def_bool y
select SPL
select TPL
endif

View File

@ -4,3 +4,10 @@ S: Maintained
F: board/google/chromebook_samus/
F: include/configs/chromebook_samus.h
F: configs/chromebook_samus_defconfig
CHROMEBOOK SAMUS TPL BOARD
M: Simon Glass <sjg@chromium.org>
S: Maintained
F: board/google/chromebook_samus/
F: include/configs/chromebook_samus.h
F: configs/chromebook_samus_tpl_defconfig

View File

@ -1,6 +1,6 @@
CONFIG_X86=y
CONFIG_SYS_TEXT_BASE=0xFFE00000
CONFIG_SYS_MALLOC_F_LEN=0x1c00
CONFIG_SYS_MALLOC_F_LEN=0x1d00
CONFIG_NR_DRAM_BANKS=8
CONFIG_DEBUG_UART_BOARD_INIT=y
CONFIG_DEBUG_UART_BASE=0x3f8

View File

@ -0,0 +1,82 @@
CONFIG_X86=y
CONFIG_SYS_TEXT_BASE=0xffed0000
CONFIG_SYS_MALLOC_F_LEN=0x1a00
CONFIG_NR_DRAM_BANKS=8
CONFIG_DEBUG_UART_BOARD_INIT=y
CONFIG_DEBUG_UART_BASE=0x3f8
CONFIG_DEBUG_UART_CLOCK=1843200
CONFIG_VENDOR_GOOGLE=y
CONFIG_TARGET_CHROMEBOOK_SAMUS_TPL=y
CONFIG_DEBUG_UART=y
CONFIG_HAVE_MRC=y
CONFIG_HAVE_REFCODE=y
CONFIG_SMP=y
CONFIG_HAVE_VGA_BIOS=y
CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
CONFIG_SYS_CONSOLE_INFO_QUIET=y
CONFIG_MISC_INIT_R=y
CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_LAST_STAGE_INIT=y
CONFIG_BLOBLIST=y
CONFIG_BLOBLIST_SIZE=0x1000
CONFIG_BLOBLIST_ADDR=0xff7c0000
CONFIG_HANDOFF=y
CONFIG_SPL_TEXT_BASE=0xffe70000
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SPL_NET_SUPPORT=y
CONFIG_SPL_PCI=y
CONFIG_SPL_PCH_SUPPORT=y
CONFIG_TPL_PCI=y
CONFIG_TPL_PCH_SUPPORT=y
CONFIG_HUSH_PARSER=y
CONFIG_CMD_CPU=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPIO=y
CONFIG_CMD_I2C=y
CONFIG_CMD_PART=y
CONFIG_CMD_SATA=y
CONFIG_CMD_SF=y
CONFIG_CMD_SPI=y
CONFIG_CMD_USB=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_TIME=y
CONFIG_CMD_SOUND=y
CONFIG_CMD_BOOTSTAGE=y
CONFIG_CMD_TPM=y
CONFIG_CMD_TPM_TEST=y
CONFIG_CMD_EXT2=y
CONFIG_CMD_EXT4=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_MAC_PARTITION=y
# CONFIG_SPL_MAC_PARTITION is not set
# CONFIG_SPL_DOS_PARTITION is not set
CONFIG_ISO_PARTITION=y
CONFIG_EFI_PARTITION=y
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_DEFAULT_DEVICE_TREE="chromebook_samus"
# CONFIG_NET is not set
CONFIG_REGMAP=y
CONFIG_SYSCON=y
CONFIG_CPU=y
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_DW=y
CONFIG_TPL_MISC=y
CONFIG_CROS_EC=y
CONFIG_CROS_EC_LPC=y
CONFIG_SYS_NS16550=y
CONFIG_SOUND=y
CONFIG_SOUND_I8254=y
CONFIG_SOUND_RT5677=y
CONFIG_SPI=y
CONFIG_TPM_TIS_LPC=y
CONFIG_USB_STORAGE=y
CONFIG_USB_KEYBOARD=y
CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
CONFIG_FRAMEBUFFER_VESA_MODE_11A=y
CONFIG_CONSOLE_SCROLL_LINES=5
CONFIG_TPM=y

View File

@ -185,6 +185,22 @@ If you are using em100, then this command will flash write -Boot:
em100 -s -d filename.rom -c W25Q64CV -r
Flash map for samus / broadwell:
fffff800 SYS_X86_START16
ffff0000 RESET_SEG_START
fffd8000 TPL_TEXT_BASE
fffa0000 X86_MRC_ADDR
fff90000 VGA_BIOS_ADDR
ffed0000 SYS_TEXT_BASE
ffea0000 X86_REFCODE_ADDR
ffe70000 SPL_TEXT_BASE
ffbf8000 CONFIG_ENV_OFFSET (environemnt offset)
ffbe0000 rw-mrc-cache (Memory-reference-code cache)
ffa00000 <spare>
ff801000 intel-me (address set by descriptor.bin)
ff800000 intel-descriptor
---
Intel Crown Bay specific instructions for bare mode:

View File

@ -546,7 +546,7 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
ns = of_n_size_cells(np);
*sizep = of_read_number(prop + na, ns);
if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0)
if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
return of_translate_address(np, prop);
else
return of_read_number(prop, na);

View File

@ -1482,7 +1482,7 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable)
UCLASS_DRIVER(cros_ec) = {
.id = UCLASS_CROS_EC,
.name = "cros_ec",
.name = "cros-ec",
.per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
.post_bind = dm_scan_fdt_dev,
.flags = DM_UC_FLAG_ALLOC_PRIV_DMA,

View File

@ -306,7 +306,7 @@ int dm_pci_run_vga_bios(struct udevice *dev, int (*int15_handler)(void),
goto err;
#endif
} else {
#if defined(CONFIG_X86) && CONFIG_IS_ENABLED(X86_32BIT_INIT)
#if defined(CONFIG_X86) && (CONFIG_IS_ENABLED(X86_32BIT_INIT) || CONFIG_TPL)
bios_set_interrupt_handler(0x15, int15_handler);
bios_run_on_x86(dev, (unsigned long)ram, vesa_mode,

View File

@ -7,15 +7,75 @@
#include <common.h>
#include <dm.h>
#include <efi_loader.h>
#include <pch.h>
#include <sysreset.h>
#include <asm/acpi_s3.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <efi_loader.h>
static __efi_runtime int x86_sysreset_request(struct udevice *dev,
enum sysreset_t type)
struct x86_sysreset_platdata {
struct udevice *pch;
};
/*
* Power down the machine by using the power management sleep control
* of the chipset. This will currently only work on Intel chipsets.
* However, adapting it to new chipsets is fairly simple. You will
* have to find the IO address of the power management register block
* in your southbridge, and look up the appropriate SLP_TYP_S5 value
* from your southbridge's data sheet.
*
* This function never returns.
*/
int pch_sysreset_power_off(struct udevice *dev)
{
struct x86_sysreset_platdata *plat = dev_get_platdata(dev);
struct pch_pmbase_info pm;
u32 reg32;
int ret;
if (!plat->pch)
return -ENOENT;
ret = pch_ioctl(plat->pch, PCH_REQ_PMBASE_INFO, &pm, sizeof(pm));
if (ret)
return ret;
/*
* Mask interrupts or system might stay in a coma, not executing code
* anymore, but not powered off either.
*/
asm("cli");
/*
* Avoid any GPI waking the system from S5* or the system might stay in
* a coma
*/
outl(0x00000000, pm.base + pm.gpio0_en_ofs);
/* Clear Power Button Status */
outw(PWRBTN_STS, pm.base + pm.pm1_sts_ofs);
/* PMBASE + 4, Bit 10-12, Sleeping Type, * set to 111 -> S5, soft_off */
reg32 = inl(pm.base + pm.pm1_cnt_ofs);
/* Set Sleeping Type to S5 (poweroff) */
reg32 &= ~(SLP_EN | SLP_TYP);
reg32 |= SLP_TYP_S5;
outl(reg32, pm.base + pm.pm1_cnt_ofs);
/* Now set the Sleep Enable bit */
reg32 |= SLP_EN;
outl(reg32, pm.base + pm.pm1_cnt_ofs);
for (;;)
asm("hlt");
}
static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type)
{
int value;
int ret;
switch (type) {
case SYSRESET_WARM:
@ -24,6 +84,11 @@ static __efi_runtime int x86_sysreset_request(struct udevice *dev,
case SYSRESET_COLD:
value = SYS_RST | RST_CPU | FULL_RST;
break;
case SYSRESET_POWER_OFF:
ret = pch_sysreset_power_off(dev);
if (ret)
return ret;
return -EINPROGRESS;
default:
return -ENOSYS;
}
@ -33,17 +98,29 @@ static __efi_runtime int x86_sysreset_request(struct udevice *dev,
return -EINPROGRESS;
}
static int x86_sysreset_get_last(struct udevice *dev)
{
return SYSRESET_POWER;
}
#ifdef CONFIG_EFI_LOADER
void __efi_runtime EFIAPI efi_reset_system(
enum efi_reset_type reset_type,
efi_status_t reset_status,
unsigned long data_size, void *reset_data)
{
int value;
/*
* inline this code since we are not caused in the context of a
* udevice and passing NULL to x86_sysreset_request() is too horrible.
*/
if (reset_type == EFI_RESET_COLD ||
reset_type == EFI_RESET_PLATFORM_SPECIFIC)
x86_sysreset_request(NULL, SYSRESET_COLD);
else if (reset_type == EFI_RESET_WARM)
x86_sysreset_request(NULL, SYSRESET_WARM);
value = SYS_RST | RST_CPU | FULL_RST;
else /* assume EFI_RESET_WARM since we cannot return an error */
value = SYS_RST | RST_CPU;
outb(value, IO_PORT_RESET);
/* TODO EFI_RESET_SHUTDOWN */
@ -51,6 +128,15 @@ void __efi_runtime EFIAPI efi_reset_system(
}
#endif
static int x86_sysreset_probe(struct udevice *dev)
{
struct x86_sysreset_platdata *plat = dev_get_platdata(dev);
/* Locate the PCH if there is one. It isn't essential */
uclass_first_device(UCLASS_PCH, &plat->pch);
return 0;
}
static const struct udevice_id x86_sysreset_ids[] = {
{ .compatible = "x86,reset" },
@ -59,6 +145,7 @@ static const struct udevice_id x86_sysreset_ids[] = {
static struct sysreset_ops x86_sysreset_ops = {
.request = x86_sysreset_request,
.get_last = x86_sysreset_get_last,
};
U_BOOT_DRIVER(x86_sysreset) = {
@ -66,4 +153,6 @@ U_BOOT_DRIVER(x86_sysreset) = {
.id = UCLASS_SYSRESET,
.of_match = x86_sysreset_ids,
.ops = &x86_sysreset_ops,
.probe = x86_sysreset_probe,
.platdata_auto_alloc_size = sizeof(struct x86_sysreset_platdata),
};

View File

@ -18,9 +18,6 @@
#define CONFIG_ENV_SECT_SIZE 0x1000
#define CONFIG_ENV_OFFSET 0x003f8000
#define BOOT_DEVICE_SPI 10
#define CONFIG_SPL_BOARD_LOAD_IMAGE
#define BOOT_DEVICE_BOARD 11
#endif /* __CONFIG_H */

View File

@ -23,4 +23,6 @@
#define CONFIG_ENV_SECT_SIZE 0x1000
#define CONFIG_ENV_OFFSET 0x003f8000
#define CONFIG_TPL_TEXT_BASE 0xfffd8000
#endif /* __CONFIG_H */

View File

@ -33,11 +33,6 @@
#define CONFIG_SYS_ATA_IDE1_OFFSET 0x170
#define CONFIG_ATAPI
/* SPI is not supported */
#define BOOT_DEVICE_SPI 10
#define CONFIG_SPL_BOARD_LOAD_IMAGE
#define BOOT_DEVICE_BOARD 11
#endif /* __CONFIG_H */

View File

@ -36,7 +36,6 @@
/*-----------------------------------------------------------------------
* Real Time Clock Configuration
*/
#define CONFIG_RTC_MC146818
#define CONFIG_SYS_ISA_IO_BASE_ADDRESS 0
#define CONFIG_SYS_ISA_IO CONFIG_SYS_ISA_IO_BASE_ADDRESS

View File

@ -16,6 +16,9 @@ enum pch_req_t {
/* Returns HDA config info if Azalia V1CTL enabled, -ENOENT if not */
PCH_REQ_HDA_CONFIG,
/* Fills out a struct pch_pmbase_info if available */
PCH_REQ_PMBASE_INFO,
PCH_REQ_TEST1, /* Test requests for sandbox driver */
PCH_REQ_TEST2,
PCH_REQ_TEST3,
@ -23,6 +26,21 @@ enum pch_req_t {
PCH_REQ_COUNT, /* Number of ioctrls supported */
};
/**
* struct pch_pmbase_info - Information filled in by PCH_REQ_PMBASE_INFO
*
* @pmbase: IO address of power-management controller
* @gpio0_en_ofs: Offset of GPIO0 enable register
* @pm1_sts_ofs: Offset of status register
* @pm1_cnt_ofs: Offset of control register
*/
struct pch_pmbase_info {
u16 base;
u8 gpio0_en_ofs;
u8 pm1_sts_ofs;
u8 pm1_cnt_ofs;
};
/**
* struct pch_ops - Operations for the Platform Controller Hub
*

View File

@ -546,11 +546,7 @@ extern void pci_cfgfunc_do_nothing(struct pci_controller* hose, pci_dev_t dev,
extern void pci_cfgfunc_config_device(struct pci_controller* hose, pci_dev_t dev,
struct pci_config_table *);
#ifdef CONFIG_NR_DRAM_BANKS
#define MAX_PCI_REGIONS (CONFIG_NR_DRAM_BANKS + 7)
#else
#define MAX_PCI_REGIONS 7
#endif
#define MAX_PCI_REGIONS 7
#define INDIRECT_TYPE_NO_PCIE_LINK 1

View File

@ -228,7 +228,11 @@ ifeq ($(CONFIG_SYS_SOC),"at91")
ALL-y += $(obj)/boot.bin
endif
ifdef CONFIG_TPL_BUILD
ALL-$(CONFIG_TPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-16bit-tpl.bin
else
ALL-$(CONFIG_SPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-16bit-spl.bin
endif
ALL-$(CONFIG_ARCH_ZYNQ) += $(obj)/boot.bin
ALL-$(CONFIG_ARCH_ZYNQMP) += $(obj)/boot.bin
@ -253,8 +257,20 @@ else
FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit
endif
# Build the .dtb file if:
# - we are not using OF_PLATDATA
# - we are using OF_CONTROL
# - we have either OF_SEPARATE or OF_HOSTFILE
build_dtb :=
ifeq ($(CONFIG_$(SPL_TPL_)OF_PLATDATA),)
ifneq ($(CONFIG_$(SPL_TPL_)OF_CONTROL),)
ifeq ($(CONFIG_OF_SEPARATE)$(CONFIG_OF_HOSTFILE),y)
build_dtb := y
endif
endif
endif
ifeq ($(CONFIG_$(SPL_TPL_)OF_CONTROL)$(CONFIG_OF_SEPARATE)$(CONFIG_$(SPL_TPL_)OF_PLATDATA),yy)
ifneq ($(build_dtb),)
$(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin \
$(if $(CONFIG_SPL_SEPARATE_BSS),,$(obj)/$(SPL_BIN)-pad.bin) \
$(FINAL_DTB_CONTAINER) FORCE
@ -316,7 +332,7 @@ quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
OBJCOPYFLAGS_$(SPL_BIN)-nodtb.bin = $(SPL_OBJCFLAGS) -O binary \
$(if $(CONFIG_SPL_X86_16BIT_INIT),-R .start16 -R .resetvec)
$(if $(CONFIG_$(SPL_TPL_)X86_16BIT_INIT),-R .start16 -R .resetvec)
$(obj)/$(SPL_BIN)-nodtb.bin: $(obj)/$(SPL_BIN) FORCE
$(call if_changed,objcopy)
@ -325,6 +341,10 @@ OBJCOPYFLAGS_u-boot-x86-16bit-spl.bin := -O binary -j .start16 -j .resetvec
$(obj)/u-boot-x86-16bit-spl.bin: $(obj)/u-boot-spl FORCE
$(call if_changed,objcopy)
OBJCOPYFLAGS_u-boot-x86-16bit-tpl.bin := -O binary -j .start16 -j .resetvec
$(obj)/u-boot-x86-16bit-tpl.bin: $(obj)/u-boot-tpl FORCE
$(call if_changed,objcopy)
LDFLAGS_$(SPL_BIN) += -T u-boot-spl.lds $(LDFLAGS_FINAL)
# Avoid 'Not enough room for program headers' error on binutils 2.28 onwards.

View File

@ -342,6 +342,13 @@ size:
Sets the image size in bytes, for example 'size = <0x100000>' for a
1MB image.
offset:
This is similar to 'offset' in entries, setting the offset of a section
within the image or section containing it. The first byte of the section
is normally at offset 0. If 'offset' is not provided, binman sets it to
the end of the previous region, or the start of the image's entry area
(normally 0) if there is no previous region.
align-size:
This sets the alignment of the image size. For example, to ensure
that the image ends on a 512-byte boundary, use 'align-size = <512>'.

View File

@ -57,7 +57,7 @@ class Section(object):
self._name = name
self._node = node
self._image = image
self._offset = 0
self._offset = None
self._size = None
self._align_size = None
self._pad_before = 0
@ -75,6 +75,7 @@ class Section(object):
def _ReadNode(self):
"""Read properties from the section node"""
self._offset = fdt_util.GetInt(self._node, 'offset')
self._size = fdt_util.GetInt(self._node, 'size')
self._align_size = fdt_util.GetInt(self._node, 'align-size')
if tools.NotPowerOfTwo(self._align_size):
@ -130,7 +131,7 @@ class Section(object):
entry.AddMissingProperties()
def SetCalculatedProperties(self):
state.SetInt(self._node, 'offset', self._offset)
state.SetInt(self._node, 'offset', self._offset or 0)
state.SetInt(self._node, 'size', self._size)
image_pos = self._image_pos
if self._parent_section:
@ -424,8 +425,8 @@ class Section(object):
Args:
fd: File to write the map to
"""
Entry.WriteMapLine(fd, indent, self._name, self._offset, self._size,
self._image_pos)
Entry.WriteMapLine(fd, indent, self._name, self._offset or 0,
self._size, self._image_pos)
for entry in self._entries.values():
entry.WriteMap(fd, indent + 1)

View File

@ -133,8 +133,8 @@ def Binman(options, args):
if name not in options.image:
del images[name]
skip.append(name)
if skip:
print 'Skipping images: %s\n' % ', '.join(skip)
if skip and options.verbosity >= 2:
print 'Skipping images: %s' % ', '.join(skip)
state.Prepare(images, dtb)

View File

@ -67,7 +67,8 @@ class Entry_section(Entry):
def Pack(self, offset):
"""Pack all entries into the section"""
self._section.PackEntries()
self._section.SetOffset(offset)
if self._section._offset is None:
self._section.SetOffset(offset)
self.size = self._section.GetSize()
return super(Entry_section, self).Pack(offset)

View File

@ -51,10 +51,10 @@ class Entry_text(Entry):
self.text_label, = self.GetEntryArgsOrProps(
[EntryArg('text-label', str)])
self.value, = self.GetEntryArgsOrProps([EntryArg(self.text_label, str)])
def ObtainContents(self):
if not self.value:
self.Raise("No value provided for text label '%s'" %
self.text_label)
def ObtainContents(self):
self.SetContents(self.value)
return True

View File

@ -18,6 +18,7 @@ class Entry_vblock(Entry):
"""An entry which contains a Chromium OS verified boot block
Properties / Entry arguments:
- content: List of phandles to entries to sign
- keydir: Directory containing the public keys to use
- keyblock: Name of the key file to use (inside keydir)
- signprivate: Name of provide key file to use (inside keydir)

View File

@ -187,7 +187,8 @@ class TestFunctional(unittest.TestCase):
return control.Binman(options, args)
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
entry_args=None, images=None, use_real_dtb=False):
entry_args=None, images=None, use_real_dtb=False,
verbosity=None):
"""Run binman with a given test file
Args:
@ -210,6 +211,8 @@ class TestFunctional(unittest.TestCase):
args.append('-up')
if not use_real_dtb:
args.append('--fake-dtb')
if verbosity is not None:
args.append('-v%d' % verbosity)
if entry_args:
for arg, value in entry_args.iteritems():
args.append('-a%s=%s' % (arg, value))
@ -1459,13 +1462,22 @@ class TestFunctional(unittest.TestCase):
def testSelectImage(self):
"""Test that we can select which images to build"""
with test_util.capture_sys_output() as (stdout, stderr):
retcode = self._DoTestFile('006_dual_image.dts', images=['image2'])
self.assertEqual(0, retcode)
self.assertIn('Skipping images: image1', stdout.getvalue())
expected = 'Skipping images: image1'
self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
# We should only get the expected message in verbose mode
for verbosity in (None, 2):
with test_util.capture_sys_output() as (stdout, stderr):
retcode = self._DoTestFile('006_dual_image.dts',
verbosity=verbosity,
images=['image2'])
self.assertEqual(0, retcode)
if verbosity:
self.assertIn(expected, stdout.getvalue())
else:
self.assertNotIn(expected, stdout.getvalue())
self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
def testUpdateFdtAll(self):
"""Test that all device trees are updated with offset/size info"""
@ -1771,6 +1783,24 @@ class TestFunctional(unittest.TestCase):
data = self._DoReadFile('100_intel_refcode.dts')
self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
def testSectionOffset(self):
"""Tests use of a section with an offset"""
data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
map=True)
self.assertEqual('''ImagePos Offset Size Name
00000000 00000000 00000038 main-section
00000004 00000004 00000010 section@0
00000004 00000000 00000004 u-boot
00000018 00000018 00000010 section@1
00000018 00000000 00000004 u-boot
0000002c 0000002c 00000004 section@2
0000002c 00000000 00000004 u-boot
''', map_data)
self.assertEqual(data,
4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x21) +
4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x61) +
4 * chr(0x26) + U_BOOT_DATA + 8 * chr(0x26))
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
pad-byte = <0x26>;
size = <0x38>;
section@0 {
read-only;
offset = <0x4>;
size = <0x10>;
pad-byte = <0x21>;
u-boot {
};
};
section@1 {
size = <0x10>;
pad-byte = <0x61>;
offset = <0x18>;
u-boot {
};
};
section@2 {
offset = <0x2c>;
u-boot {
};
};
};
};