avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
30
u-boot/arch/x86/cpu/broadwell/Kconfig
Normal file
30
u-boot/arch/x86/cpu/broadwell/Kconfig
Normal file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright (C) 2016 Google Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config INTEL_BROADWELL
|
||||
bool
|
||||
select CACHE_MRC_BIN
|
||||
|
||||
if INTEL_BROADWELL
|
||||
|
||||
config DCACHE_RAM_BASE
|
||||
default 0xff7c0000
|
||||
|
||||
config DCACHE_RAM_SIZE
|
||||
default 0x40000
|
||||
|
||||
config DCACHE_RAM_MRC_VAR_SIZE
|
||||
default 0x30000
|
||||
|
||||
config CPU_SPECIFIC_OPTIONS
|
||||
def_bool y
|
||||
select SMM_TSEG
|
||||
select X86_RAMTEST
|
||||
|
||||
config SMM_TSEG_SIZE
|
||||
hex
|
||||
default 0x800000
|
||||
|
||||
endif
|
||||
17
u-boot/arch/x86/cpu/broadwell/Makefile
Normal file
17
u-boot/arch/x86/cpu/broadwell/Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Copyright (c) 2016 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += cpu.o
|
||||
obj-y += iobp.o
|
||||
obj-y += lpc.o
|
||||
obj-y += me.o
|
||||
obj-y += northbridge.o
|
||||
obj-y += pch.o
|
||||
obj-y += pinctrl_broadwell.o
|
||||
obj-y += power_state.o
|
||||
obj-y += refcode.o
|
||||
obj-y += sata.o
|
||||
obj-y += sdram.o
|
||||
761
u-boot/arch/x86/cpu/broadwell/cpu.c
Normal file
761
u-boot/arch/x86/cpu/broadwell/cpu.c
Normal file
@@ -0,0 +1,761 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* 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,
|
||||
};
|
||||
|
||||
int arch_cpu_init_dm(void)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
/* Start up the LPC so we have serial */
|
||||
ret = uclass_first_device(UCLASS_LPC, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
ret = cpu_set_flex_ratio_to_tdp_nominal();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_max_freq(void)
|
||||
{
|
||||
msr_t msr, perf_ctl, platform_info;
|
||||
|
||||
/* Check for configurable TDP option */
|
||||
platform_info = msr_read(MSR_PLATFORM_INFO);
|
||||
|
||||
if ((platform_info.hi >> 1) & 3) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
perf_ctl.hi = 0;
|
||||
msr_write(IA32_PERF_CTL, perf_ctl);
|
||||
|
||||
debug("CPU: frequency set to %d MHz\n",
|
||||
((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK);
|
||||
}
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
post_code(POST_CPU_INIT);
|
||||
|
||||
return x86_cpu_init_f();
|
||||
}
|
||||
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
char processor_name[CPU_MAX_NAME_LEN];
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
set_max_freq();
|
||||
|
||||
ret = cpu_common_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
gd->arch.pei_boot_mode = PEI_BOOT_NONE;
|
||||
|
||||
/* Print processor name */
|
||||
name = cpu_get_name(processor_name);
|
||||
printf("CPU: %s\n", name);
|
||||
|
||||
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)
|
||||
{
|
||||
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, "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, "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,
|
||||
"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,
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
144
u-boot/arch/x86/cpu/broadwell/iobp.c
Normal file
144
u-boot/arch/x86/cpu/broadwell/iobp.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* Modified from coreboot
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/pch.h>
|
||||
|
||||
#define IOBP_RETRY 1000
|
||||
|
||||
/* IO Buffer Programming */
|
||||
#define IOBPIRI 0x2330
|
||||
#define IOBPD 0x2334
|
||||
#define IOBPS 0x2338
|
||||
#define IOBPS_READY 0x0001
|
||||
#define IOBPS_TX_MASK 0x0006
|
||||
#define IOBPS_MASK 0xff00
|
||||
#define IOBPS_READ 0x0600
|
||||
#define IOBPS_WRITE 0x0700
|
||||
#define IOBPU 0x233a
|
||||
#define IOBPU_MAGIC 0xf000
|
||||
#define IOBP_PCICFG_READ 0x0400
|
||||
#define IOBP_PCICFG_WRITE 0x0500
|
||||
|
||||
static inline int iobp_poll(void)
|
||||
{
|
||||
unsigned try;
|
||||
|
||||
for (try = IOBP_RETRY; try > 0; try--) {
|
||||
u16 status = readw(RCB_REG(IOBPS));
|
||||
if ((status & IOBPS_READY) == 0)
|
||||
return 1;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
printf("IOBP: timeout waiting for transaction to complete\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pch_iobp_trans_start(u32 address, int op)
|
||||
{
|
||||
if (!iobp_poll())
|
||||
return 0;
|
||||
|
||||
/* Set the address */
|
||||
writel(address, RCB_REG(IOBPIRI));
|
||||
|
||||
/* READ OPCODE */
|
||||
clrsetbits_le16(RCB_REG(IOBPS), IOBPS_MASK, op);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pch_iobp_trans_finish(void)
|
||||
{
|
||||
u16 status;
|
||||
|
||||
/* Undocumented magic */
|
||||
writew(IOBPU_MAGIC, RCB_REG(IOBPU));
|
||||
|
||||
/* Set ready bit */
|
||||
setbits_le16(RCB_REG(IOBPS), IOBPS_READY);
|
||||
|
||||
if (!iobp_poll())
|
||||
return 1;
|
||||
|
||||
/* Check for successful transaction */
|
||||
status = readw(RCB_REG(IOBPS));
|
||||
if (status & IOBPS_TX_MASK)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 pch_iobp_read(u32 address)
|
||||
{
|
||||
if (!pch_iobp_trans_start(address, IOBPS_READ))
|
||||
return 0;
|
||||
if (pch_iobp_trans_finish()) {
|
||||
printf("IOBP: read 0x%08x failed\n", address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read IOBP data */
|
||||
return readl(RCB_REG(IOBPD));
|
||||
}
|
||||
|
||||
int pch_iobp_write(u32 address, u32 data)
|
||||
{
|
||||
if (!pch_iobp_trans_start(address, IOBPS_WRITE))
|
||||
return -EIO;
|
||||
|
||||
writel(data, RCB_REG(IOBPD));
|
||||
|
||||
if (pch_iobp_trans_finish()) {
|
||||
printf("IOBP: write 0x%08x failed\n", address);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
|
||||
{
|
||||
u32 data = pch_iobp_read(address);
|
||||
|
||||
/* Update the data */
|
||||
data &= andvalue;
|
||||
data |= orvalue;
|
||||
|
||||
return pch_iobp_write(address, data);
|
||||
}
|
||||
|
||||
int pch_iobp_exec(u32 addr, u16 op_code, u8 route_id, u32 *data, u8 *resp)
|
||||
{
|
||||
if (!data || !resp)
|
||||
return 0;
|
||||
|
||||
*resp = -1;
|
||||
if (!iobp_poll())
|
||||
return -EIO;
|
||||
|
||||
writel(addr, RCB_REG(IOBPIRI));
|
||||
clrsetbits_le16(RCB_REG(IOBPS), 0xff00, op_code);
|
||||
writew(IOBPU_MAGIC | route_id, RCB_REG(IOBPU));
|
||||
|
||||
writel(*data, RCB_REG(IOBPD));
|
||||
/* Set IOBPS[0] to trigger IOBP transaction*/
|
||||
setbits_le16(RCB_REG(IOBPS), 1);
|
||||
|
||||
if (!iobp_poll())
|
||||
return -EIO;
|
||||
|
||||
*resp = (readw(RCB_REG(IOBPS)) & IOBPS_TX_MASK) >> 1;
|
||||
*data = readl(RCB_REG(IOBPD));
|
||||
|
||||
return 0;
|
||||
}
|
||||
77
u-boot/arch/x86/cpu/broadwell/lpc.c
Normal file
77
u-boot/arch/x86/cpu/broadwell/lpc.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* From coreboot broadwell support
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <pch.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/lpc_common.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/spi.h>
|
||||
|
||||
static void set_spi_speed(void)
|
||||
{
|
||||
u32 fdod;
|
||||
u8 ssfc;
|
||||
|
||||
/* Observe SPI Descriptor Component Section 0 */
|
||||
writel(0x1000, SPI_REG(SPIBAR_FDOC));
|
||||
|
||||
/* Extract the Write/Erase SPI Frequency from descriptor */
|
||||
fdod = readl(SPI_REG(SPIBAR_FDOD));
|
||||
fdod >>= 24;
|
||||
fdod &= 7;
|
||||
|
||||
/* Set Software Sequence frequency to match */
|
||||
ssfc = readb(SPI_REG(SPIBAR_SSFC + 2));
|
||||
ssfc &= ~7;
|
||||
ssfc |= fdod;
|
||||
writeb(ssfc, SPI_REG(SPIBAR_SSFC + 2));
|
||||
}
|
||||
|
||||
static int broadwell_lpc_early_init(struct udevice *dev)
|
||||
{
|
||||
set_spi_speed();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc_init_extra(struct udevice *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broadwell_lpc_probe(struct udevice *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!(gd->flags & GD_FLG_RELOC)) {
|
||||
ret = lpc_common_early_init(dev);
|
||||
if (ret) {
|
||||
debug("%s: lpc_early_init() failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return broadwell_lpc_early_init(dev);
|
||||
}
|
||||
|
||||
return lpc_init_extra(dev);
|
||||
}
|
||||
|
||||
static const struct udevice_id broadwell_lpc_ids[] = {
|
||||
{ .compatible = "intel,broadwell-lpc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(broadwell_lpc_drv) = {
|
||||
.name = "lpc",
|
||||
.id = UCLASS_LPC,
|
||||
.of_match = broadwell_lpc_ids,
|
||||
.probe = broadwell_lpc_probe,
|
||||
};
|
||||
57
u-boot/arch/x86/cpu/broadwell/me.c
Normal file
57
u-boot/arch/x86/cpu/broadwell/me.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Based on code from coreboot src/soc/intel/broadwell/me_status.c
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <asm/arch/me.h>
|
||||
|
||||
static inline void me_read_dword_ptr(struct udevice *dev, void *ptr, int offset)
|
||||
{
|
||||
u32 dword;
|
||||
|
||||
dm_pci_read_config32(dev, offset, &dword);
|
||||
memcpy(ptr, &dword, sizeof(dword));
|
||||
}
|
||||
|
||||
int intel_me_hsio_version(struct udevice *dev, uint16_t *versionp,
|
||||
uint16_t *checksump)
|
||||
{
|
||||
int count;
|
||||
u32 hsiover;
|
||||
struct me_hfs hfs;
|
||||
|
||||
/* Query for HSIO version, overloads H_GS and HFS */
|
||||
dm_pci_write_config32(dev, PCI_ME_H_GS,
|
||||
ME_HSIO_MESSAGE | ME_HSIO_CMD_GETHSIOVER);
|
||||
|
||||
/* Must wait for ME acknowledgement */
|
||||
for (count = ME_RETRY; count > 0; --count) {
|
||||
me_read_dword_ptr(dev, &hfs, PCI_ME_HFS);
|
||||
if (hfs.bios_msg_ack)
|
||||
break;
|
||||
udelay(ME_DELAY);
|
||||
}
|
||||
if (!count) {
|
||||
debug("ERROR: ME failed to respond\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* HSIO version should be in HFS_5 */
|
||||
dm_pci_read_config32(dev, PCI_ME_HFS5, &hsiover);
|
||||
*versionp = hsiover >> 16;
|
||||
*checksump = hsiover & 0xffff;
|
||||
|
||||
debug("ME: HSIO Version : %d (CRC 0x%04x)\n",
|
||||
*versionp, *checksump);
|
||||
|
||||
/* Reset registers to normal behavior */
|
||||
dm_pci_write_config32(dev, PCI_ME_H_GS,
|
||||
ME_HSIO_MESSAGE | ME_HSIO_CMD_GETHSIOVER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
59
u-boot/arch/x86/cpu/broadwell/northbridge.c
Normal file
59
u-boot/arch/x86/cpu/broadwell/northbridge.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Chromium Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/iomap.h>
|
||||
#include <asm/arch/pch.h>
|
||||
|
||||
static int broadwell_northbridge_early_init(struct udevice *dev)
|
||||
{
|
||||
/* Move earlier? */
|
||||
dm_pci_write_config32(dev, PCIEXBAR + 4, 0);
|
||||
/* 64MiB - 0-63 buses */
|
||||
dm_pci_write_config32(dev, PCIEXBAR, MCFG_BASE_ADDRESS | 4 | 1);
|
||||
|
||||
dm_pci_write_config32(dev, MCHBAR, MCH_BASE_ADDRESS | 1);
|
||||
dm_pci_write_config32(dev, DMIBAR, DMI_BASE_ADDRESS | 1);
|
||||
dm_pci_write_config32(dev, EPBAR, EP_BASE_ADDRESS | 1);
|
||||
writel(EDRAM_BASE_ADDRESS | 1, MCH_BASE_ADDRESS + EDRAMBAR);
|
||||
writel(GDXC_BASE_ADDRESS | 1, MCH_BASE_ADDRESS + GDXCBAR);
|
||||
|
||||
/* Set C0000-FFFFF to access RAM on both reads and writes */
|
||||
dm_pci_write_config8(dev, PAM0, 0x30);
|
||||
dm_pci_write_config8(dev, PAM1, 0x33);
|
||||
dm_pci_write_config8(dev, PAM2, 0x33);
|
||||
dm_pci_write_config8(dev, PAM3, 0x33);
|
||||
dm_pci_write_config8(dev, PAM4, 0x33);
|
||||
dm_pci_write_config8(dev, PAM5, 0x33);
|
||||
dm_pci_write_config8(dev, PAM6, 0x33);
|
||||
|
||||
/* Device enable: IGD and Mini-HD */
|
||||
dm_pci_write_config32(dev, DEVEN, DEVEN_D0EN | DEVEN_D2EN | DEVEN_D3EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broadwell_northbridge_probe(struct udevice *dev)
|
||||
{
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return broadwell_northbridge_early_init(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id broadwell_northbridge_ids[] = {
|
||||
{ .compatible = "intel,broadwell-northbridge" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(broadwell_northbridge_drv) = {
|
||||
.name = "broadwell_northbridge",
|
||||
.id = UCLASS_NORTHBRIDGE,
|
||||
.of_match = broadwell_northbridge_ids,
|
||||
.probe = broadwell_northbridge_probe,
|
||||
};
|
||||
541
u-boot/arch/x86/cpu/broadwell/pch.c
Normal file
541
u-boot/arch/x86/cpu/broadwell/pch.c
Normal file
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <pch.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/i8259.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/ioapic.h>
|
||||
#include <asm/lpc_common.h>
|
||||
#include <asm/pch_common.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/iomap.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/pm.h>
|
||||
#include <asm/arch/rcb.h>
|
||||
#include <asm/arch/spi.h>
|
||||
|
||||
#define BIOS_CTRL 0xdc
|
||||
|
||||
bool cpu_is_ult(void)
|
||||
{
|
||||
u32 fm = cpu_get_family_model();
|
||||
|
||||
return fm == BROADWELL_FAMILY_ULT || fm == HASWELL_FAMILY_ULT;
|
||||
}
|
||||
|
||||
static int broadwell_pch_early_init(struct udevice *dev)
|
||||
{
|
||||
struct gpio_desc desc;
|
||||
struct udevice *bus;
|
||||
pci_dev_t bdf;
|
||||
int ret;
|
||||
|
||||
dm_pci_write_config32(dev, PCH_RCBA, RCB_BASE_ADDRESS | 1);
|
||||
|
||||
dm_pci_write_config32(dev, PMBASE, ACPI_BASE_ADDRESS | 1);
|
||||
dm_pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
|
||||
dm_pci_write_config32(dev, GPIO_BASE, GPIO_BASE_ADDRESS | 1);
|
||||
dm_pci_write_config8(dev, GPIO_CNTL, GPIO_EN);
|
||||
|
||||
/* Enable IOAPIC */
|
||||
writew(0x1000, RCB_REG(OIC));
|
||||
/* Read back for posted write */
|
||||
readw(RCB_REG(OIC));
|
||||
|
||||
/* Set HPET address and enable it */
|
||||
clrsetbits_le32(RCB_REG(HPTC), 3, 1 << 7);
|
||||
/* Read back for posted write */
|
||||
readl(RCB_REG(HPTC));
|
||||
/* Enable HPET to start counter */
|
||||
setbits_le32(HPET_BASE_ADDRESS + 0x10, 1 << 0);
|
||||
|
||||
setbits_le32(RCB_REG(GCS), 1 << 5);
|
||||
|
||||
/*
|
||||
* Enable PP3300_AUTOBAHN_EN after initial GPIO setup
|
||||
* to prevent possible brownout. This will cause the GPIOs to be set
|
||||
* up if it has not been done already.
|
||||
*/
|
||||
ret = gpio_request_by_name(dev, "power-enable-gpio", 0, &desc,
|
||||
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 8.14 Additional PCI Express Programming Steps, step #1 */
|
||||
bdf = PCI_BDF(0, 0x1c, 0);
|
||||
bus = pci_get_controller(dev);
|
||||
pci_bus_clrset_config32(bus, bdf, 0xf4, 0x60, 0);
|
||||
pci_bus_clrset_config32(bus, bdf, 0xf4, 0x80, 0x80);
|
||||
pci_bus_clrset_config32(bus, bdf, 0xe2, 0x30, 0x30);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pch_misc_init(struct udevice *dev)
|
||||
{
|
||||
/* Setup SLP signal assertion, SLP_S4=4s, SLP_S3=50ms */
|
||||
dm_pci_clrset_config8(dev, GEN_PMCON_3, 3 << 4 | 1 << 10,
|
||||
1 << 3 | 1 << 11 | 1 << 12);
|
||||
/* Prepare sleep mode */
|
||||
clrsetio_32(ACPI_BASE_ADDRESS + PM1_CNT, SLP_TYP, SCI_EN);
|
||||
|
||||
/* Setup NMI on errors, disable SERR */
|
||||
clrsetio_8(0x61, 0xf0, 1 << 2);
|
||||
/* Disable NMI sources */
|
||||
setio_8(0x70, 1 << 7);
|
||||
/* Indicate DRAM init done for MRC */
|
||||
dm_pci_clrset_config8(dev, GEN_PMCON_2, 0, 1 << 7);
|
||||
|
||||
/* Clear status bits to prevent unexpected wake */
|
||||
setbits_le32(RCB_REG(0x3310), 0x0000002f);
|
||||
clrsetbits_le32(RCB_REG(0x3f02), 0x0000000f, 0);
|
||||
/* Enable PCIe Relaxed Order */
|
||||
setbits_le32(RCB_REG(0x2314), 1 << 31 | 1 << 7);
|
||||
setbits_le32(RCB_REG(0x1114), 1 << 15 | 1 << 14);
|
||||
/* Setup SERIRQ, enable continuous mode */
|
||||
dm_pci_clrset_config8(dev, SERIRQ_CNTL, 0, 1 << 7 | 1 << 6);
|
||||
};
|
||||
|
||||
static void pch_enable_ioapic(void)
|
||||
{
|
||||
u32 reg32;
|
||||
|
||||
/* Make sure this is a unique ID within system */
|
||||
io_apic_set_id(0x04);
|
||||
|
||||
/* affirm full set of redirection table entries ("write once") */
|
||||
reg32 = io_apic_read(0x01);
|
||||
|
||||
/* PCH-LP has 39 redirection entries */
|
||||
reg32 &= ~0x00ff0000;
|
||||
reg32 |= 0x00270000;
|
||||
|
||||
io_apic_write(0x01, reg32);
|
||||
|
||||
/*
|
||||
* Select Boot Configuration register (0x03) and
|
||||
* use Processor System Bus (0x01) to deliver interrupts.
|
||||
*/
|
||||
io_apic_write(0x03, 0x01);
|
||||
}
|
||||
|
||||
/* Enable all requested GPE */
|
||||
void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4)
|
||||
{
|
||||
outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0));
|
||||
outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32));
|
||||
outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_94_64));
|
||||
outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD));
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable GPIO SMI events - it would be good to put this in the GPIO driver
|
||||
* but it would need a new driver operation.
|
||||
*/
|
||||
int enable_alt_smi(struct udevice *pch, u32 mask)
|
||||
{
|
||||
struct pch_lp_gpio_regs *regs;
|
||||
u32 gpiobase;
|
||||
int ret;
|
||||
|
||||
ret = pch_get_gpio_base(pch, &gpiobase);
|
||||
if (ret) {
|
||||
debug("%s: invalid GPIOBASE address (%08x)\n", __func__,
|
||||
gpiobase);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regs = (struct pch_lp_gpio_regs *)gpiobase;
|
||||
setio_32(regs->alt_gpi_smi_en, mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pch_power_options(struct udevice *dev)
|
||||
{
|
||||
int pwr_on_after_power_fail = MAINBOARD_POWER_OFF;
|
||||
const char *state;
|
||||
u32 enable[4];
|
||||
u16 reg16;
|
||||
int ret;
|
||||
|
||||
dm_pci_read_config16(dev, GEN_PMCON_3, ®16);
|
||||
reg16 &= 0xfffe;
|
||||
switch (pwr_on_after_power_fail) {
|
||||
case MAINBOARD_POWER_OFF:
|
||||
reg16 |= 1;
|
||||
state = "off";
|
||||
break;
|
||||
case MAINBOARD_POWER_ON:
|
||||
reg16 &= ~1;
|
||||
state = "on";
|
||||
break;
|
||||
case MAINBOARD_POWER_KEEP:
|
||||
reg16 &= ~1;
|
||||
state = "state keep";
|
||||
break;
|
||||
default:
|
||||
state = "undefined";
|
||||
}
|
||||
dm_pci_write_config16(dev, GEN_PMCON_3, reg16);
|
||||
debug("Set power %s after power failure.\n", state);
|
||||
|
||||
/* GPE setup based on device tree configuration */
|
||||
ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
|
||||
"intel,gpe0-en", enable, ARRAY_SIZE(enable));
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
enable_all_gpe(enable[0], enable[1], enable[2], enable[3]);
|
||||
|
||||
/* SMI setup based on device tree configuration */
|
||||
enable_alt_smi(dev, fdtdec_get_int(gd->fdt_blob, dev->of_offset,
|
||||
"intel,alt-gp-smi-enable", 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Magic register settings for power management */
|
||||
static void pch_pm_init_magic(struct udevice *dev)
|
||||
{
|
||||
dm_pci_write_config8(dev, 0xa9, 0x46);
|
||||
clrbits_le32(RCB_REG(0x232c), 1),
|
||||
setbits_le32(RCB_REG(0x1100), 0x0000c13f);
|
||||
clrsetbits_le32(RCB_REG(0x2320), 0x60, 0x10);
|
||||
writel(0x00012fff, RCB_REG(0x3314));
|
||||
clrsetbits_le32(RCB_REG(0x3318), 0x000f0330, 0x0dcf0400);
|
||||
writel(0x04000000, RCB_REG(0x3324));
|
||||
writel(0x00041400, RCB_REG(0x3368));
|
||||
writel(0x3f8ddbff, RCB_REG(0x3388));
|
||||
writel(0x00007001, RCB_REG(0x33ac));
|
||||
writel(0x00181900, RCB_REG(0x33b0));
|
||||
writel(0x00060A00, RCB_REG(0x33c0));
|
||||
writel(0x06200840, RCB_REG(0x33d0));
|
||||
writel(0x01010101, RCB_REG(0x3a28));
|
||||
writel(0x040c0404, RCB_REG(0x3a2c));
|
||||
writel(0x9000000a, RCB_REG(0x3a9c));
|
||||
writel(0x03808033, RCB_REG(0x2b1c));
|
||||
writel(0x80000009, RCB_REG(0x2b34));
|
||||
writel(0x022ddfff, RCB_REG(0x3348));
|
||||
writel(0x00000001, RCB_REG(0x334c));
|
||||
writel(0x0001c000, RCB_REG(0x3358));
|
||||
writel(0x3f8ddbff, RCB_REG(0x3380));
|
||||
writel(0x0001c7e1, RCB_REG(0x3384));
|
||||
writel(0x0001c7e1, RCB_REG(0x338c));
|
||||
writel(0x0001c000, RCB_REG(0x3398));
|
||||
writel(0x00181900, RCB_REG(0x33a8));
|
||||
writel(0x00080000, RCB_REG(0x33dc));
|
||||
writel(0x00000001, RCB_REG(0x33e0));
|
||||
writel(0x0000040c, RCB_REG(0x3a20));
|
||||
writel(0x01010101, RCB_REG(0x3a24));
|
||||
writel(0x01010101, RCB_REG(0x3a30));
|
||||
dm_pci_clrset_config32(dev, 0xac, 0x00200000, 0);
|
||||
setbits_le32(RCB_REG(0x0410), 0x00000003);
|
||||
setbits_le32(RCB_REG(0x2618), 0x08000000);
|
||||
setbits_le32(RCB_REG(0x2300), 0x00000002);
|
||||
setbits_le32(RCB_REG(0x2600), 0x00000008);
|
||||
writel(0x00007001, RCB_REG(0x33b4));
|
||||
writel(0x022ddfff, RCB_REG(0x3350));
|
||||
writel(0x00000001, RCB_REG(0x3354));
|
||||
/* Power Optimizer */
|
||||
setbits_le32(RCB_REG(0x33d4), 0x08000000);
|
||||
/*
|
||||
* This stops the LCD from turning on:
|
||||
* setbits_le32(RCB_REG(0x33c8), 0x08000080);
|
||||
*/
|
||||
writel(0x0000883c, RCB_REG(0x2b10));
|
||||
writel(0x1e0a4616, RCB_REG(0x2b14));
|
||||
writel(0x40000005, RCB_REG(0x2b24));
|
||||
writel(0x0005db01, RCB_REG(0x2b20));
|
||||
writel(0x05145005, RCB_REG(0x3a80));
|
||||
writel(0x00001005, RCB_REG(0x3a84));
|
||||
setbits_le32(RCB_REG(0x33d4), 0x2fff2fb1);
|
||||
setbits_le32(RCB_REG(0x33c8), 0x00008000);
|
||||
};
|
||||
|
||||
static int pch_type(struct udevice *dev)
|
||||
{
|
||||
u16 type;
|
||||
|
||||
dm_pci_read_config16(dev, PCI_DEVICE_ID, &type);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* Return 1 if PCH type is WildcatPoint */
|
||||
static int pch_is_wpt(struct udevice *dev)
|
||||
{
|
||||
return ((pch_type(dev) & 0xfff0) == 0x9cc0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Return 1 if PCH type is WildcatPoint ULX */
|
||||
static int pch_is_wpt_ulx(struct udevice *dev)
|
||||
{
|
||||
u16 lpcid = pch_type(dev);
|
||||
|
||||
switch (lpcid) {
|
||||
case PCH_WPT_BDW_Y_SAMPLE:
|
||||
case PCH_WPT_BDW_Y_PREMIUM:
|
||||
case PCH_WPT_BDW_Y_BASE:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 pch_read_soft_strap(int id)
|
||||
{
|
||||
clrbits_le32(SPI_REG(SPIBAR_FDOC), 0x00007ffc);
|
||||
setbits_le32(SPI_REG(SPIBAR_FDOC), 0x00004000 | id * 4);
|
||||
|
||||
return readl(SPI_REG(SPIBAR_FDOD));
|
||||
}
|
||||
|
||||
static void pch_enable_mphy(struct udevice *dev)
|
||||
{
|
||||
u32 data_and = 0xffffffff;
|
||||
u32 data_or = (1 << 14) | (1 << 13) | (1 << 12);
|
||||
|
||||
data_or |= (1 << 0);
|
||||
if (pch_is_wpt(dev)) {
|
||||
data_and &= ~((1 << 7) | (1 << 6) | (1 << 3));
|
||||
data_or |= (1 << 5) | (1 << 4);
|
||||
|
||||
if (pch_is_wpt_ulx(dev)) {
|
||||
/* Check if SATA and USB3 MPHY are enabled */
|
||||
u32 strap19 = pch_read_soft_strap(19);
|
||||
strap19 &= ((1 << 31) | (1 << 30));
|
||||
strap19 >>= 30;
|
||||
if (strap19 == 3) {
|
||||
data_or |= (1 << 3);
|
||||
debug("Enable ULX MPHY PG control in single domain\n");
|
||||
} else if (strap19 == 0) {
|
||||
debug("Enable ULX MPHY PG control in split domains\n");
|
||||
} else {
|
||||
debug("Invalid PCH Soft Strap 19 configuration\n");
|
||||
}
|
||||
} else {
|
||||
data_or |= (1 << 3);
|
||||
}
|
||||
}
|
||||
|
||||
pch_iobp_update(0xCF000000, data_and, data_or);
|
||||
}
|
||||
|
||||
static void pch_init_deep_sx(bool deep_sx_enable_ac, bool deep_sx_enable_dc)
|
||||
{
|
||||
if (deep_sx_enable_ac) {
|
||||
setbits_le32(RCB_REG(DEEP_S3_POL), DEEP_S3_EN_AC);
|
||||
setbits_le32(RCB_REG(DEEP_S5_POL), DEEP_S5_EN_AC);
|
||||
}
|
||||
|
||||
if (deep_sx_enable_dc) {
|
||||
setbits_le32(RCB_REG(DEEP_S3_POL), DEEP_S3_EN_DC);
|
||||
setbits_le32(RCB_REG(DEEP_S5_POL), DEEP_S5_EN_DC);
|
||||
}
|
||||
|
||||
if (deep_sx_enable_ac || deep_sx_enable_dc) {
|
||||
setbits_le32(RCB_REG(DEEP_SX_CONFIG),
|
||||
DEEP_SX_WAKE_PIN_EN | DEEP_SX_GP27_PIN_EN);
|
||||
}
|
||||
}
|
||||
|
||||
/* Power Management init */
|
||||
static void pch_pm_init(struct udevice *dev)
|
||||
{
|
||||
debug("PCH PM init\n");
|
||||
|
||||
pch_init_deep_sx(false, false);
|
||||
pch_enable_mphy(dev);
|
||||
pch_pm_init_magic(dev);
|
||||
|
||||
if (pch_is_wpt(dev)) {
|
||||
setbits_le32(RCB_REG(0x33e0), 1 << 4 | 1 << 1);
|
||||
setbits_le32(RCB_REG(0x2b1c), 1 << 22 | 1 << 14 | 1 << 13);
|
||||
writel(0x16bf0002, RCB_REG(0x33e4));
|
||||
setbits_le32(RCB_REG(0x33e4), 0x1);
|
||||
}
|
||||
|
||||
pch_iobp_update(0xCA000000, ~0UL, 0x00000009);
|
||||
|
||||
/* Set RCBA 0x2b1c[29]=1 if DSP disabled */
|
||||
if (readl(RCB_REG(FD)) & PCH_DISABLE_ADSPD)
|
||||
setbits_le32(RCB_REG(0x2b1c), 1 << 29);
|
||||
}
|
||||
|
||||
static void pch_cg_init(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bus = pci_get_controller(dev);
|
||||
u32 reg32;
|
||||
u16 reg16;
|
||||
ulong val;
|
||||
|
||||
/* DMI */
|
||||
setbits_le32(RCB_REG(0x2234), 0xf);
|
||||
|
||||
dm_pci_read_config16(dev, GEN_PMCON_1, ®16);
|
||||
reg16 &= ~(1 << 10); /* Disable BIOS_PCI_EXP_EN for native PME */
|
||||
if (pch_is_wpt(dev))
|
||||
reg16 &= ~(1 << 11);
|
||||
else
|
||||
reg16 |= 1 << 11;
|
||||
reg16 |= 1 << 5 | 1 << 6 | 1 << 7 | 1 << 12;
|
||||
reg16 |= 1 << 2; /* PCI CLKRUN# Enable */
|
||||
dm_pci_write_config16(dev, GEN_PMCON_1, reg16);
|
||||
|
||||
/*
|
||||
* RCBA + 0x2614[27:25,14:13,10,8] = 101,11,1,1
|
||||
* RCBA + 0x2614[23:16] = 0x20
|
||||
* RCBA + 0x2614[30:28] = 0x0
|
||||
* RCBA + 0x2614[26] = 1 (IF 0:2.0@0x08 >= 0x0b)
|
||||
*/
|
||||
clrsetbits_le32(RCB_REG(0x2614), 0x64ff0000, 0x0a206500);
|
||||
|
||||
/* Check for 0:2.0@0x08 >= 0x0b */
|
||||
pci_bus_read_config(bus, PCI_BDF(0, 0x2, 0), 0x8, &val, PCI_SIZE_8);
|
||||
if (pch_is_wpt(dev) || val >= 0x0b)
|
||||
setbits_le32(RCB_REG(0x2614), 1 << 26);
|
||||
|
||||
setbits_le32(RCB_REG(0x900), 0x0000031f);
|
||||
|
||||
reg32 = readl(RCB_REG(CG));
|
||||
if (readl(RCB_REG(0x3454)) & (1 << 4))
|
||||
reg32 &= ~(1 << 29); /* LPC Dynamic */
|
||||
else
|
||||
reg32 |= (1 << 29); /* LPC Dynamic */
|
||||
reg32 |= 1 << 31; /* LP LPC */
|
||||
reg32 |= 1 << 30; /* LP BLA */
|
||||
if (readl(RCB_REG(0x3454)) & (1 << 4))
|
||||
reg32 &= ~(1 << 29);
|
||||
else
|
||||
reg32 |= 1 << 29;
|
||||
reg32 |= 1 << 28; /* GPIO Dynamic */
|
||||
reg32 |= 1 << 27; /* HPET Dynamic */
|
||||
reg32 |= 1 << 26; /* Generic Platform Event Clock */
|
||||
if (readl(RCB_REG(BUC)) & PCH_DISABLE_GBE)
|
||||
reg32 |= 1 << 23; /* GbE Static */
|
||||
if (readl(RCB_REG(FD)) & PCH_DISABLE_HD_AUDIO)
|
||||
reg32 |= 1 << 21; /* HDA Static */
|
||||
reg32 |= 1 << 22; /* HDA Dynamic */
|
||||
writel(reg32, RCB_REG(CG));
|
||||
|
||||
/* PCH-LP LPC */
|
||||
if (pch_is_wpt(dev))
|
||||
clrsetbits_le32(RCB_REG(0x3434), 0x1f, 0x17);
|
||||
else
|
||||
setbits_le32(RCB_REG(0x3434), 0x7);
|
||||
|
||||
/* SPI */
|
||||
setbits_le32(RCB_REG(0x38c0), 0x3c07);
|
||||
|
||||
pch_iobp_update(0xCE00C000, ~1UL, 0x00000000);
|
||||
}
|
||||
|
||||
static void systemagent_init(void)
|
||||
{
|
||||
/* Enable Power Aware Interrupt Routing */
|
||||
clrsetbits_8(MCHBAR_REG(MCH_PAIR), 0x7, 0x4); /* Fixed Priority */
|
||||
|
||||
/*
|
||||
* Set bits 0+1 of BIOS_RESET_CPL to indicate to the CPU
|
||||
* that BIOS has initialized memory and power management
|
||||
*/
|
||||
setbits_8(MCHBAR_REG(BIOS_RESET_CPL), 3);
|
||||
debug("Set BIOS_RESET_CPL\n");
|
||||
|
||||
/* Configure turbo power limits 1ms after reset complete bit */
|
||||
mdelay(1);
|
||||
|
||||
cpu_set_power_limits(28);
|
||||
}
|
||||
|
||||
static int broadwell_pch_init(struct udevice *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Enable upper 128 bytes of CMOS */
|
||||
setbits_le32(RCB_REG(RC), 1 << 2);
|
||||
|
||||
/*
|
||||
* TODO: TCO timer halt - this hangs
|
||||
* setio_16(ACPI_BASE_ADDRESS + TCO1_CNT, TCO_TMR_HLT);
|
||||
*/
|
||||
|
||||
/* Disable unused device (always) */
|
||||
setbits_le32(RCB_REG(FD), PCH_DISABLE_ALWAYS);
|
||||
|
||||
pch_misc_init(dev);
|
||||
|
||||
/* Interrupt configuration */
|
||||
pch_enable_ioapic();
|
||||
|
||||
/* Initialize power management */
|
||||
ret = pch_power_options(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
pch_pm_init(dev);
|
||||
pch_cg_init(dev);
|
||||
systemagent_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broadwell_pch_probe(struct udevice *dev)
|
||||
{
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return broadwell_pch_early_init(dev);
|
||||
else
|
||||
return broadwell_pch_init(dev);
|
||||
}
|
||||
|
||||
static int broadwell_pch_get_spi_base(struct udevice *dev, ulong *sbasep)
|
||||
{
|
||||
u32 rcba;
|
||||
|
||||
dm_pci_read_config32(dev, PCH_RCBA, &rcba);
|
||||
/* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */
|
||||
rcba = rcba & 0xffffc000;
|
||||
*sbasep = rcba + 0x3800;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broadwell_set_spi_protect(struct udevice *dev, bool protect)
|
||||
{
|
||||
return lpc_set_spi_protect(dev, BIOS_CTRL, protect);
|
||||
}
|
||||
|
||||
static int broadwell_get_gpio_base(struct udevice *dev, u32 *gbasep)
|
||||
{
|
||||
dm_pci_read_config32(dev, GPIO_BASE, gbasep);
|
||||
*gbasep &= PCI_BASE_ADDRESS_IO_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static const struct udevice_id broadwell_pch_ids[] = {
|
||||
{ .compatible = "intel,broadwell-pch" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(broadwell_pch) = {
|
||||
.name = "broadwell_pch",
|
||||
.id = UCLASS_PCH,
|
||||
.of_match = broadwell_pch_ids,
|
||||
.probe = broadwell_pch_probe,
|
||||
.ops = &broadwell_pch_ops,
|
||||
};
|
||||
278
u-boot/arch/x86/cpu/broadwell/pinctrl_broadwell.c
Normal file
278
u-boot/arch/x86/cpu/broadwell/pinctrl_broadwell.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <pch.h>
|
||||
#include <pci.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <dt-bindings/gpio/x86-gpio.h>
|
||||
#include <dm/pinctrl.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
enum {
|
||||
MAX_GPIOS = 95,
|
||||
};
|
||||
|
||||
#define PIRQ_SHIFT 16
|
||||
#define CONF_MASK 0xffff
|
||||
|
||||
struct pin_info {
|
||||
int node;
|
||||
int phandle;
|
||||
bool mode_gpio;
|
||||
bool dir_input;
|
||||
bool invert;
|
||||
bool trigger_level;
|
||||
bool output_high;
|
||||
bool sense_disable;
|
||||
bool owner_gpio;
|
||||
bool route_smi;
|
||||
bool irq_enable;
|
||||
bool reset_rsmrst;
|
||||
bool pirq_apic_route;
|
||||
};
|
||||
|
||||
static int broadwell_pinctrl_read_configs(struct udevice *dev,
|
||||
struct pin_info *conf, int max_pins)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
int count = 0;
|
||||
int node;
|
||||
|
||||
debug("%s: starting\n", __func__);
|
||||
for (node = fdt_first_subnode(blob, dev->of_offset);
|
||||
node > 0;
|
||||
node = fdt_next_subnode(blob, node)) {
|
||||
int phandle = fdt_get_phandle(blob, node);
|
||||
|
||||
if (!phandle)
|
||||
continue;
|
||||
if (count == max_pins)
|
||||
return -ENOSPC;
|
||||
|
||||
/* We've found a new configuration */
|
||||
memset(conf, '\0', sizeof(*conf));
|
||||
conf->node = node;
|
||||
conf->phandle = phandle;
|
||||
conf->mode_gpio = fdtdec_get_bool(blob, node, "mode-gpio");
|
||||
if (fdtdec_get_int(blob, node, "direction", -1) == PIN_INPUT)
|
||||
conf->dir_input = true;
|
||||
conf->invert = fdtdec_get_bool(blob, node, "invert");
|
||||
if (fdtdec_get_int(blob, node, "trigger", -1) == TRIGGER_LEVEL)
|
||||
conf->trigger_level = true;
|
||||
if (fdtdec_get_int(blob, node, "output-value", -1) == 1)
|
||||
conf->output_high = true;
|
||||
conf->sense_disable = fdtdec_get_bool(blob, node,
|
||||
"sense-disable");
|
||||
if (fdtdec_get_int(blob, node, "owner", -1) == OWNER_GPIO)
|
||||
conf->owner_gpio = true;
|
||||
if (fdtdec_get_int(blob, node, "route", -1) == ROUTE_SMI)
|
||||
conf->route_smi = true;
|
||||
conf->irq_enable = fdtdec_get_bool(blob, node, "irq-enable");
|
||||
conf->reset_rsmrst = fdtdec_get_bool(blob, node,
|
||||
"reset-rsmrst");
|
||||
if (fdtdec_get_int(blob, node, "pirq-apic", -1) ==
|
||||
PIRQ_APIC_ROUTE)
|
||||
conf->pirq_apic_route = true;
|
||||
debug("config: phandle=%d\n", phandle);
|
||||
count++;
|
||||
conf++;
|
||||
}
|
||||
debug("%s: Found %d configurations\n", __func__, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int broadwell_pinctrl_lookup_phandle(struct pin_info *conf,
|
||||
int conf_count, int phandle)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < conf_count; i++) {
|
||||
if (conf[i].phandle == phandle)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int broadwell_pinctrl_read_pins(struct udevice *dev,
|
||||
struct pin_info *conf, int conf_count, int gpio_conf[],
|
||||
int num_gpios)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
int count = 0;
|
||||
int node;
|
||||
|
||||
for (node = fdt_first_subnode(blob, dev->of_offset);
|
||||
node > 0;
|
||||
node = fdt_next_subnode(blob, node)) {
|
||||
int len, i;
|
||||
const u32 *prop = fdt_getprop(blob, node, "config", &len);
|
||||
|
||||
if (!prop)
|
||||
continue;
|
||||
|
||||
/* There are three cells per pin */
|
||||
count = len / (sizeof(u32) * 3);
|
||||
debug("Found %d GPIOs to configure\n", count);
|
||||
for (i = 0; i < count; i++) {
|
||||
uint gpio = fdt32_to_cpu(prop[i * 3]);
|
||||
uint phandle = fdt32_to_cpu(prop[i * 3 + 1]);
|
||||
int val;
|
||||
|
||||
if (gpio >= num_gpios) {
|
||||
debug("%s: GPIO %d out of range\n", __func__,
|
||||
gpio);
|
||||
return -EDOM;
|
||||
}
|
||||
val = broadwell_pinctrl_lookup_phandle(conf, conf_count,
|
||||
phandle);
|
||||
if (val < 0) {
|
||||
debug("%s: Cannot find phandle %d\n", __func__,
|
||||
phandle);
|
||||
return -EINVAL;
|
||||
}
|
||||
gpio_conf[gpio] = val |
|
||||
fdt32_to_cpu(prop[i * 3 + 2]) << PIRQ_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void broadwell_pinctrl_commit(struct pch_lp_gpio_regs *regs,
|
||||
struct pin_info *pin_info,
|
||||
int gpio_conf[], int count)
|
||||
{
|
||||
u32 owner_gpio[GPIO_BANKS] = {0};
|
||||
u32 route_smi[GPIO_BANKS] = {0};
|
||||
u32 irq_enable[GPIO_BANKS] = {0};
|
||||
u32 reset_rsmrst[GPIO_BANKS] = {0};
|
||||
u32 pirq2apic = 0;
|
||||
int set, bit, gpio = 0;
|
||||
|
||||
for (gpio = 0; gpio < MAX_GPIOS; gpio++) {
|
||||
int confnum = gpio_conf[gpio] & CONF_MASK;
|
||||
struct pin_info *pin = &pin_info[confnum];
|
||||
u32 val;
|
||||
|
||||
val = pin->mode_gpio << CONFA_MODE_SHIFT |
|
||||
pin->dir_input << CONFA_DIR_SHIFT |
|
||||
pin->invert << CONFA_INVERT_SHIFT |
|
||||
pin->trigger_level << CONFA_TRIGGER_SHIFT |
|
||||
pin->output_high << CONFA_OUTPUT_SHIFT;
|
||||
outl(val, ®s->config[gpio].conf_a);
|
||||
outl(pin->sense_disable << CONFB_SENSE_SHIFT,
|
||||
®s->config[gpio].conf_b);
|
||||
|
||||
/* Determine set and bit based on GPIO number */
|
||||
set = gpio / GPIO_PER_BANK;
|
||||
bit = gpio % GPIO_PER_BANK;
|
||||
|
||||
/* Apply settings to set specific bits */
|
||||
owner_gpio[set] |= pin->owner_gpio << bit;
|
||||
route_smi[set] |= pin->route_smi << bit;
|
||||
irq_enable[set] |= pin->irq_enable << bit;
|
||||
reset_rsmrst[set] |= pin->reset_rsmrst << bit;
|
||||
|
||||
/* PIRQ to IO-APIC map */
|
||||
if (pin->pirq_apic_route)
|
||||
pirq2apic |= gpio_conf[gpio] >> PIRQ_SHIFT;
|
||||
debug("gpio %d: conf %d, mode_gpio %d, dir_input %d, output_high %d\n",
|
||||
gpio, confnum, pin->mode_gpio, pin->dir_input,
|
||||
pin->output_high);
|
||||
}
|
||||
|
||||
for (set = 0; set < GPIO_BANKS; set++) {
|
||||
outl(owner_gpio[set], ®s->own[set]);
|
||||
outl(route_smi[set], ®s->gpi_route[set]);
|
||||
outl(irq_enable[set], ®s->gpi_ie[set]);
|
||||
outl(reset_rsmrst[set], ®s->rst_sel[set]);
|
||||
}
|
||||
|
||||
outl(pirq2apic, ®s->pirq_to_ioxapic);
|
||||
}
|
||||
|
||||
static int broadwell_pinctrl_probe(struct udevice *dev)
|
||||
{
|
||||
struct pch_lp_gpio_regs *regs;
|
||||
struct pin_info conf[12];
|
||||
int gpio_conf[MAX_GPIOS];
|
||||
struct udevice *pch;
|
||||
int conf_count;
|
||||
u32 gpiobase;
|
||||
int ret;
|
||||
|
||||
ret = uclass_first_device(UCLASS_PCH, &pch);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!pch)
|
||||
return -ENODEV;
|
||||
debug("%s: start\n", __func__);
|
||||
|
||||
/* Only init once, before relocation */
|
||||
if (gd->flags & GD_FLG_RELOC)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Get the memory/io base address to configure every pins.
|
||||
* IOBASE is used to configure the mode/pads
|
||||
* GPIOBASE is used to configure the direction and default value
|
||||
*/
|
||||
ret = pch_get_gpio_base(pch, &gpiobase);
|
||||
if (ret) {
|
||||
debug("%s: invalid GPIOBASE address (%08x)\n", __func__,
|
||||
gpiobase);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
conf_count = broadwell_pinctrl_read_configs(dev, conf,
|
||||
ARRAY_SIZE(conf));
|
||||
if (conf_count < 0) {
|
||||
debug("%s: Cannot read configs: err=%d\n", __func__, ret);
|
||||
return conf_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assume that pin settings are provided for every pin. Pins not
|
||||
* mentioned will get the first config mentioned in the list.
|
||||
*/
|
||||
ret = broadwell_pinctrl_read_pins(dev, conf, conf_count, gpio_conf,
|
||||
MAX_GPIOS);
|
||||
if (ret) {
|
||||
debug("%s: Cannot read pin settings: err=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regs = (struct pch_lp_gpio_regs *)gpiobase;
|
||||
broadwell_pinctrl_commit(regs, conf, gpio_conf, ARRAY_SIZE(conf));
|
||||
|
||||
debug("%s: done\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id broadwell_pinctrl_match[] = {
|
||||
{ .compatible = "intel,x86-broadwell-pinctrl",
|
||||
.data = X86_SYSCON_PINCONF },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(broadwell_pinctrl) = {
|
||||
.name = "broadwell_pinctrl",
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = broadwell_pinctrl_match,
|
||||
.probe = broadwell_pinctrl_probe,
|
||||
};
|
||||
90
u-boot/arch/x86/cpu/broadwell/power_state.c
Normal file
90
u-boot/arch/x86/cpu/broadwell/power_state.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* From coreboot src/soc/intel/broadwell/romstage/power_state.c
|
||||
*
|
||||
* Copyright (C) 2016 Google, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <pci.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/arch/iomap.h>
|
||||
#include <asm/arch/lpc.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/pm.h>
|
||||
|
||||
/* Return 0, 3, or 5 to indicate the previous sleep state. */
|
||||
static int prev_sleep_state(struct chipset_power_state *ps)
|
||||
{
|
||||
/* Default to S0. */
|
||||
int prev_sleep_state = SLEEP_STATE_S0;
|
||||
|
||||
if (ps->pm1_sts & WAK_STS) {
|
||||
switch ((ps->pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) {
|
||||
#if CONFIG_HAVE_ACPI_RESUME
|
||||
case SLP_TYP_S3:
|
||||
prev_sleep_state = SLEEP_STATE_S3;
|
||||
break;
|
||||
#endif
|
||||
case SLP_TYP_S5:
|
||||
prev_sleep_state = SLEEP_STATE_S5;
|
||||
break;
|
||||
}
|
||||
/* Clear SLP_TYP. */
|
||||
outl(ps->pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT);
|
||||
}
|
||||
|
||||
if (ps->gen_pmcon3 & (PWR_FLR | SUS_PWR_FLR))
|
||||
prev_sleep_state = SLEEP_STATE_S5;
|
||||
|
||||
return prev_sleep_state;
|
||||
}
|
||||
|
||||
static void dump_power_state(struct chipset_power_state *ps)
|
||||
{
|
||||
debug("PM1_STS: %04x\n", ps->pm1_sts);
|
||||
debug("PM1_EN: %04x\n", ps->pm1_en);
|
||||
debug("PM1_CNT: %08x\n", ps->pm1_cnt);
|
||||
debug("TCO_STS: %04x %04x\n", ps->tco1_sts, ps->tco2_sts);
|
||||
|
||||
debug("GPE0_STS: %08x %08x %08x %08x\n",
|
||||
ps->gpe0_sts[0], ps->gpe0_sts[1],
|
||||
ps->gpe0_sts[2], ps->gpe0_sts[3]);
|
||||
debug("GPE0_EN: %08x %08x %08x %08x\n",
|
||||
ps->gpe0_en[0], ps->gpe0_en[1],
|
||||
ps->gpe0_en[2], ps->gpe0_en[3]);
|
||||
|
||||
debug("GEN_PMCON: %04x %04x %04x\n",
|
||||
ps->gen_pmcon1, ps->gen_pmcon2, ps->gen_pmcon3);
|
||||
|
||||
debug("Previous Sleep State: S%d\n",
|
||||
ps->prev_sleep_state);
|
||||
}
|
||||
|
||||
/* Fill power state structure from ACPI PM registers */
|
||||
void power_state_get(struct udevice *pch_dev, struct chipset_power_state *ps)
|
||||
{
|
||||
ps->pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
|
||||
ps->pm1_en = inw(ACPI_BASE_ADDRESS + PM1_EN);
|
||||
ps->pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
|
||||
ps->tco1_sts = inw(ACPI_BASE_ADDRESS + TCO1_STS);
|
||||
ps->tco2_sts = inw(ACPI_BASE_ADDRESS + TCO2_STS);
|
||||
ps->gpe0_sts[0] = inl(ACPI_BASE_ADDRESS + GPE0_STS(0));
|
||||
ps->gpe0_sts[1] = inl(ACPI_BASE_ADDRESS + GPE0_STS(1));
|
||||
ps->gpe0_sts[2] = inl(ACPI_BASE_ADDRESS + GPE0_STS(2));
|
||||
ps->gpe0_sts[3] = inl(ACPI_BASE_ADDRESS + GPE0_STS(3));
|
||||
ps->gpe0_en[0] = inl(ACPI_BASE_ADDRESS + GPE0_EN(0));
|
||||
ps->gpe0_en[1] = inl(ACPI_BASE_ADDRESS + GPE0_EN(1));
|
||||
ps->gpe0_en[2] = inl(ACPI_BASE_ADDRESS + GPE0_EN(2));
|
||||
ps->gpe0_en[3] = inl(ACPI_BASE_ADDRESS + GPE0_EN(3));
|
||||
|
||||
dm_pci_read_config16(pch_dev, GEN_PMCON_1, &ps->gen_pmcon1);
|
||||
dm_pci_read_config16(pch_dev, GEN_PMCON_2, &ps->gen_pmcon2);
|
||||
dm_pci_read_config16(pch_dev, GEN_PMCON_3, &ps->gen_pmcon3);
|
||||
|
||||
ps->prev_sleep_state = prev_sleep_state(ps);
|
||||
|
||||
dump_power_state(ps);
|
||||
}
|
||||
113
u-boot/arch/x86/cpu/broadwell/refcode.c
Normal file
113
u-boot/arch/x86/cpu/broadwell/refcode.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Read a coreboot rmodule and execute it.
|
||||
* The rmodule_header struct is from coreboot.
|
||||
*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <asm/arch/pei_data.h>
|
||||
|
||||
#define RMODULE_MAGIC 0xf8fe
|
||||
#define RMODULE_VERSION_1 1
|
||||
|
||||
/*
|
||||
* All fields with '_offset' in the name are byte offsets into the flat blob.
|
||||
* The linker and the linker script takes are of assigning the values.
|
||||
*/
|
||||
struct rmodule_header {
|
||||
uint16_t magic;
|
||||
uint8_t version;
|
||||
uint8_t type;
|
||||
/* The payload represents the program's loadable code and data */
|
||||
uint32_t payload_begin_offset;
|
||||
uint32_t payload_end_offset;
|
||||
/* Begin and of relocation information about the program module */
|
||||
uint32_t relocations_begin_offset;
|
||||
uint32_t relocations_end_offset;
|
||||
/*
|
||||
* The starting address of the linked program. This address is vital
|
||||
* for determining relocation offsets as the relocation info and other
|
||||
* symbols (bss, entry point) need this value as a basis to calculate
|
||||
* the offsets.
|
||||
*/
|
||||
uint32_t module_link_start_address;
|
||||
/*
|
||||
* The module_program_size is the size of memory used while running
|
||||
* the program. The program is assumed to consume a contiguous amount
|
||||
* of memory
|
||||
*/
|
||||
uint32_t module_program_size;
|
||||
/* This is program's execution entry point */
|
||||
uint32_t module_entry_point;
|
||||
/*
|
||||
* Optional parameter structure that can be used to pass data into
|
||||
* the module
|
||||
*/
|
||||
uint32_t parameters_begin;
|
||||
uint32_t parameters_end;
|
||||
/* BSS section information so the loader can clear the bss */
|
||||
uint32_t bss_begin;
|
||||
uint32_t bss_end;
|
||||
/* Add some room for growth */
|
||||
uint32_t padding[4];
|
||||
} __packed;
|
||||
|
||||
int cpu_run_reference_code(void)
|
||||
{
|
||||
struct pei_data _pei_data __aligned(8);
|
||||
struct pei_data *pei_data = &_pei_data;
|
||||
asmlinkage int (*func)(void *);
|
||||
struct rmodule_header *hdr;
|
||||
char *src, *dest;
|
||||
int ret, dummy;
|
||||
int size;
|
||||
|
||||
hdr = (struct rmodule_header *)CONFIG_X86_REFCODE_ADDR;
|
||||
debug("Extracting code from rmodule at %p\n", hdr);
|
||||
if (hdr->magic != RMODULE_MAGIC) {
|
||||
debug("Invalid rmodule magic\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (hdr->module_link_start_address != 0) {
|
||||
debug("Link start address must be 0\n");
|
||||
return -EPERM;
|
||||
}
|
||||
if (hdr->module_entry_point != 0) {
|
||||
debug("Entry point must be 0\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
memset(pei_data, '\0', sizeof(struct pei_data));
|
||||
broadwell_fill_pei_data(pei_data);
|
||||
mainboard_fill_pei_data(pei_data);
|
||||
pei_data->saved_data = (void *)&dummy;
|
||||
|
||||
src = (char *)hdr + hdr->payload_begin_offset;
|
||||
dest = (char *)CONFIG_X86_REFCODE_RUN_ADDR;
|
||||
|
||||
size = hdr->payload_end_offset - hdr->payload_begin_offset;
|
||||
debug("Copying refcode from %p to %p, size %x\n", src, dest, size);
|
||||
memcpy(dest, src, size);
|
||||
|
||||
size = hdr->bss_end - hdr->bss_begin;
|
||||
debug("Zeroing BSS at %p, size %x\n", dest + hdr->bss_begin, size);
|
||||
memset(dest + hdr->bss_begin, '\0', size);
|
||||
|
||||
func = (asmlinkage int (*)(void *))dest;
|
||||
debug("Running reference code at %p\n", func);
|
||||
#ifdef DEBUG
|
||||
print_buffer(CONFIG_X86_REFCODE_RUN_ADDR, (void *)func, 1, 0x40, 0);
|
||||
#endif
|
||||
ret = func(pei_data);
|
||||
if (ret != 0) {
|
||||
debug("Reference code returned %d\n", ret);
|
||||
return -EL2HLT;
|
||||
}
|
||||
debug("Refereence code completed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
269
u-boot/arch/x86/cpu/broadwell/sata.c
Normal file
269
u-boot/arch/x86/cpu/broadwell/sata.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* From coreboot src/soc/intel/broadwell/sata.c
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/lpc_common.h>
|
||||
#include <asm/pch_common.h>
|
||||
#include <asm/pch_common.h>
|
||||
#include <asm/arch/pch.h>
|
||||
|
||||
struct sata_platdata {
|
||||
int port_map;
|
||||
uint port0_gen3_tx;
|
||||
uint port1_gen3_tx;
|
||||
uint port0_gen3_dtle;
|
||||
uint port1_gen3_dtle;
|
||||
|
||||
/*
|
||||
* SATA DEVSLP Mux
|
||||
* 0 = port 0 DEVSLP on DEVSLP0/GPIO33
|
||||
* 1 = port 3 DEVSLP on DEVSLP0/GPIO33
|
||||
*/
|
||||
int devslp_mux;
|
||||
|
||||
/*
|
||||
* DEVSLP Disable
|
||||
* 0: DEVSLP is enabled
|
||||
* 1: DEVSLP is disabled
|
||||
*/
|
||||
int devslp_disable;
|
||||
};
|
||||
|
||||
static void broadwell_sata_init(struct udevice *dev)
|
||||
{
|
||||
struct sata_platdata *plat = dev_get_platdata(dev);
|
||||
u32 reg32;
|
||||
u8 *abar;
|
||||
u16 reg16;
|
||||
int port;
|
||||
|
||||
debug("SATA: Initializing controller in AHCI mode.\n");
|
||||
|
||||
/* Set timings */
|
||||
dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE);
|
||||
dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE);
|
||||
|
||||
/* for AHCI, Port Enable is managed in memory mapped space */
|
||||
dm_pci_read_config16(dev, 0x92, ®16);
|
||||
reg16 &= ~0xf;
|
||||
reg16 |= 0x8000 | plat->port_map;
|
||||
dm_pci_write_config16(dev, 0x92, reg16);
|
||||
udelay(2);
|
||||
|
||||
/* Setup register 98h */
|
||||
dm_pci_read_config32(dev, 0x98, ®32);
|
||||
reg32 &= ~((1 << 31) | (1 << 30));
|
||||
reg32 |= 1 << 23;
|
||||
reg32 |= 1 << 24; /* Enable MPHY Dynamic Power Gating */
|
||||
dm_pci_write_config32(dev, 0x98, reg32);
|
||||
|
||||
/* Setup register 9Ch */
|
||||
reg16 = 0; /* Disable alternate ID */
|
||||
reg16 = 1 << 5; /* BWG step 12 */
|
||||
dm_pci_write_config16(dev, 0x9c, reg16);
|
||||
|
||||
/* SATA Initialization register */
|
||||
reg32 = 0x183;
|
||||
reg32 |= (plat->port_map ^ 0xf) << 24;
|
||||
reg32 |= (plat->devslp_mux & 1) << 15;
|
||||
dm_pci_write_config32(dev, 0x94, reg32);
|
||||
|
||||
/* Initialize AHCI memory-mapped space */
|
||||
dm_pci_read_config32(dev, PCI_BASE_ADDRESS_5, ®32);
|
||||
abar = (u8 *)reg32;
|
||||
debug("ABAR: %p\n", abar);
|
||||
|
||||
/* CAP (HBA Capabilities) : enable power management */
|
||||
clrsetbits_le32(abar + 0x00, 0x00020060 /* SXS+EMS+PMS */,
|
||||
0x0c006000 /* PSC+SSC+SALP+SSS */ |
|
||||
1 << 18); /* SAM: SATA AHCI MODE ONLY */
|
||||
|
||||
/* PI (Ports implemented) */
|
||||
writel(plat->port_map, abar + 0x0c);
|
||||
(void) readl(abar + 0x0c); /* Read back 1 */
|
||||
(void) readl(abar + 0x0c); /* Read back 2 */
|
||||
|
||||
/* CAP2 (HBA Capabilities Extended)*/
|
||||
if (plat->devslp_disable) {
|
||||
clrbits_le32(abar + 0x24, 1 << 3);
|
||||
} else {
|
||||
/* Enable DEVSLP */
|
||||
setbits_le32(abar + 0x24, 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2);
|
||||
|
||||
for (port = 0; port < 4; port++) {
|
||||
if (!(plat->port_map & (1 << port)))
|
||||
continue;
|
||||
/* DEVSLP DSP */
|
||||
setbits_le32(abar + 0x144 + (0x80 * port), 1 << 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Static Power Gating for unused ports */
|
||||
reg32 = readl(RCB_REG(0x3a84));
|
||||
/* Port 3 and 2 disabled */
|
||||
if ((plat->port_map & ((1 << 3)|(1 << 2))) == 0)
|
||||
reg32 |= (1 << 24) | (1 << 26);
|
||||
/* Port 1 and 0 disabled */
|
||||
if ((plat->port_map & ((1 << 1)|(1 << 0))) == 0)
|
||||
reg32 |= (1 << 20) | (1 << 18);
|
||||
writel(reg32, RCB_REG(0x3a84));
|
||||
|
||||
/* Set Gen3 Transmitter settings if needed */
|
||||
if (plat->port0_gen3_tx)
|
||||
pch_iobp_update(SATA_IOBP_SP0_SECRT88,
|
||||
~(SATA_SECRT88_VADJ_MASK <<
|
||||
SATA_SECRT88_VADJ_SHIFT),
|
||||
(plat->port0_gen3_tx &
|
||||
SATA_SECRT88_VADJ_MASK)
|
||||
<< SATA_SECRT88_VADJ_SHIFT);
|
||||
|
||||
if (plat->port1_gen3_tx)
|
||||
pch_iobp_update(SATA_IOBP_SP1_SECRT88,
|
||||
~(SATA_SECRT88_VADJ_MASK <<
|
||||
SATA_SECRT88_VADJ_SHIFT),
|
||||
(plat->port1_gen3_tx &
|
||||
SATA_SECRT88_VADJ_MASK)
|
||||
<< SATA_SECRT88_VADJ_SHIFT);
|
||||
|
||||
/* Set Gen3 DTLE DATA / EDGE registers if needed */
|
||||
if (plat->port0_gen3_dtle) {
|
||||
pch_iobp_update(SATA_IOBP_SP0DTLE_DATA,
|
||||
~(SATA_DTLE_MASK << SATA_DTLE_DATA_SHIFT),
|
||||
(plat->port0_gen3_dtle & SATA_DTLE_MASK)
|
||||
<< SATA_DTLE_DATA_SHIFT);
|
||||
|
||||
pch_iobp_update(SATA_IOBP_SP0DTLE_EDGE,
|
||||
~(SATA_DTLE_MASK << SATA_DTLE_EDGE_SHIFT),
|
||||
(plat->port0_gen3_dtle & SATA_DTLE_MASK)
|
||||
<< SATA_DTLE_EDGE_SHIFT);
|
||||
}
|
||||
|
||||
if (plat->port1_gen3_dtle) {
|
||||
pch_iobp_update(SATA_IOBP_SP1DTLE_DATA,
|
||||
~(SATA_DTLE_MASK << SATA_DTLE_DATA_SHIFT),
|
||||
(plat->port1_gen3_dtle & SATA_DTLE_MASK)
|
||||
<< SATA_DTLE_DATA_SHIFT);
|
||||
|
||||
pch_iobp_update(SATA_IOBP_SP1DTLE_EDGE,
|
||||
~(SATA_DTLE_MASK << SATA_DTLE_EDGE_SHIFT),
|
||||
(plat->port1_gen3_dtle & SATA_DTLE_MASK)
|
||||
<< SATA_DTLE_EDGE_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Additional Programming Requirements for Power Optimizer
|
||||
*/
|
||||
|
||||
/* Step 1 */
|
||||
pch_common_sir_write(dev, 0x64, 0x883c9003);
|
||||
|
||||
/* Step 2: SIR 68h[15:0] = 880Ah */
|
||||
reg32 = pch_common_sir_read(dev, 0x68);
|
||||
reg32 &= 0xffff0000;
|
||||
reg32 |= 0x880a;
|
||||
pch_common_sir_write(dev, 0x68, reg32);
|
||||
|
||||
/* Step 3: SIR 60h[3] = 1 */
|
||||
reg32 = pch_common_sir_read(dev, 0x60);
|
||||
reg32 |= (1 << 3);
|
||||
pch_common_sir_write(dev, 0x60, reg32);
|
||||
|
||||
/* Step 4: SIR 60h[0] = 1 */
|
||||
reg32 = pch_common_sir_read(dev, 0x60);
|
||||
reg32 |= (1 << 0);
|
||||
pch_common_sir_write(dev, 0x60, reg32);
|
||||
|
||||
/* Step 5: SIR 60h[1] = 1 */
|
||||
reg32 = pch_common_sir_read(dev, 0x60);
|
||||
reg32 |= (1 << 1);
|
||||
pch_common_sir_write(dev, 0x60, reg32);
|
||||
|
||||
/* Clock Gating */
|
||||
pch_common_sir_write(dev, 0x70, 0x3f00bf1f);
|
||||
pch_common_sir_write(dev, 0x54, 0xcf000f0f);
|
||||
pch_common_sir_write(dev, 0x58, 0x00190000);
|
||||
clrsetbits_le32(RCB_REG(0x333c), 0x00300000, 0x00c00000);
|
||||
|
||||
dm_pci_read_config32(dev, 0x300, ®32);
|
||||
reg32 |= 1 << 17 | 1 << 16 | 1 << 19;
|
||||
reg32 |= 1 << 31 | 1 << 30 | 1 << 29;
|
||||
dm_pci_write_config32(dev, 0x300, reg32);
|
||||
|
||||
dm_pci_read_config32(dev, 0x98, ®32);
|
||||
reg32 |= 1 << 29;
|
||||
dm_pci_write_config32(dev, 0x98, reg32);
|
||||
|
||||
/* Register Lock */
|
||||
dm_pci_read_config32(dev, 0x9c, ®32);
|
||||
reg32 |= 1 << 31;
|
||||
dm_pci_write_config32(dev, 0x9c, reg32);
|
||||
}
|
||||
|
||||
static int broadwell_sata_enable(struct udevice *dev)
|
||||
{
|
||||
struct sata_platdata *plat = dev_get_platdata(dev);
|
||||
struct gpio_desc desc;
|
||||
u16 map;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Set SATA controller mode early so the resource allocator can
|
||||
* properly assign IO/Memory resources for the controller.
|
||||
*/
|
||||
map = 0x0060;
|
||||
|
||||
map |= (plat->port_map ^ 0x3f) << 8;
|
||||
dm_pci_write_config16(dev, 0x90, map);
|
||||
|
||||
ret = gpio_request_by_name(dev, "reset-gpio", 0, &desc, GPIOD_IS_OUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broadwell_sata_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct sata_platdata *plat = dev_get_platdata(dev);
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
|
||||
plat->port_map = fdtdec_get_int(blob, node, "intel,sata-port-map", 0);
|
||||
plat->port0_gen3_tx = fdtdec_get_int(blob, node,
|
||||
"intel,sata-port0-gen3-tx", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broadwell_sata_probe(struct udevice *dev)
|
||||
{
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return broadwell_sata_enable(dev);
|
||||
else
|
||||
broadwell_sata_init(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id broadwell_ahci_ids[] = {
|
||||
{ .compatible = "intel,wildcatpoint-ahci" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(ahci_broadwell_drv) = {
|
||||
.name = "ahci_broadwell",
|
||||
.id = UCLASS_AHCI,
|
||||
.of_match = broadwell_ahci_ids,
|
||||
.ofdata_to_platdata = broadwell_sata_ofdata_to_platdata,
|
||||
.probe = broadwell_sata_probe,
|
||||
.platdata_auto_alloc_size = sizeof(struct sata_platdata),
|
||||
};
|
||||
302
u-boot/arch/x86/cpu/broadwell/sdram.c
Normal file
302
u-boot/arch/x86/cpu/broadwell/sdram.c
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* From coreboot src/soc/intel/broadwell/romstage/raminit.c
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <pci.h>
|
||||
#include <syscon.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/lpc_common.h>
|
||||
#include <asm/mrccache.h>
|
||||
#include <asm/mrc_common.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/arch/iomap.h>
|
||||
#include <asm/arch/me.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/pei_data.h>
|
||||
#include <asm/arch/pm.h>
|
||||
|
||||
ulong board_get_usable_ram_top(ulong total_size)
|
||||
{
|
||||
return mrc_common_board_get_usable_ram_top(total_size);
|
||||
}
|
||||
|
||||
void dram_init_banksize(void)
|
||||
{
|
||||
mrc_common_dram_init_banksize();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/*
|
||||
* Base of DPR is top of usable DRAM below 4GiB. The register has
|
||||
* 1 MiB alignment and reports the TOP of the range, the base
|
||||
* must be calculated from the size in MiB in bits 11:4.
|
||||
*/
|
||||
u32 dpr, tom;
|
||||
|
||||
dm_pci_read_config32(dev, DPR, &dpr);
|
||||
tom = dpr & ~((1 << 20) - 1);
|
||||
|
||||
debug("dpt %08x tom %08x\n", dpr, tom);
|
||||
/* Subtract DMA Protected Range size if enabled */
|
||||
if (dpr & DPR_EPM)
|
||||
tom -= (dpr & DPR_SIZE_MASK) << 16;
|
||||
|
||||
return (unsigned long)tom;
|
||||
}
|
||||
|
||||
/**
|
||||
* sdram_find() - Find available memory
|
||||
*
|
||||
* This is a bit complicated since on x86 there are system memory holes all
|
||||
* over the place. We create a list of available memory blocks
|
||||
*
|
||||
* @dev: Northbridge device
|
||||
*/
|
||||
static int sdram_find(struct udevice *dev)
|
||||
{
|
||||
struct memory_info *info = &gd->arch.meminfo;
|
||||
ulong top_of_ram;
|
||||
|
||||
top_of_ram = get_top_of_ram(dev);
|
||||
mrc_add_memory_area(info, 0, top_of_ram);
|
||||
|
||||
/* Add MTRRs for memory */
|
||||
mtrr_add_request(MTRR_TYPE_WRBACK, 0, 2ULL << 30);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_mrc_cache(struct pei_data *pei_data)
|
||||
{
|
||||
struct mrc_data_container *mrc_cache;
|
||||
struct mrc_region entry;
|
||||
int ret;
|
||||
|
||||
ret = mrccache_get_region(NULL, &entry);
|
||||
if (ret)
|
||||
return ret;
|
||||
mrc_cache = mrccache_find_current(&entry);
|
||||
if (!mrc_cache)
|
||||
return -ENOENT;
|
||||
|
||||
pei_data->saved_data = mrc_cache->data;
|
||||
pei_data->saved_data_size = mrc_cache->data_size;
|
||||
debug("%s: at %p, size %x checksum %04x\n", __func__,
|
||||
pei_data->saved_data, pei_data->saved_data_size,
|
||||
mrc_cache->checksum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
struct pei_data _pei_data __aligned(8);
|
||||
struct pei_data *pei_data = &_pei_data;
|
||||
struct udevice *dev, *me_dev, *pch_dev;
|
||||
struct chipset_power_state ps;
|
||||
const void *spd_data;
|
||||
int ret, size;
|
||||
|
||||
memset(pei_data, '\0', sizeof(struct pei_data));
|
||||
|
||||
/* Print ME state before MRC */
|
||||
ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
intel_me_status(me_dev);
|
||||
|
||||
/* Save ME HSIO version */
|
||||
ret = uclass_first_device(UCLASS_PCH, &pch_dev);
|
||||
if (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);
|
||||
|
||||
broadwell_fill_pei_data(pei_data);
|
||||
mainboard_fill_pei_data(pei_data);
|
||||
|
||||
ret = uclass_first_device(UCLASS_NORTHBRIDGE, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
size = 256;
|
||||
ret = mrc_locate_spd(dev, size, &spd_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
memcpy(pei_data->spd_data[0][0], spd_data, size);
|
||||
memcpy(pei_data->spd_data[1][0], spd_data, size);
|
||||
|
||||
ret = prepare_mrc_cache(pei_data);
|
||||
if (ret)
|
||||
debug("prepare_mrc_cache failed: %d\n", ret);
|
||||
|
||||
debug("PEI version %#x\n", pei_data->pei_version);
|
||||
ret = mrc_common_init(dev, pei_data, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
debug("Memory init done\n");
|
||||
|
||||
ret = sdram_find(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
gd->ram_size = gd->arch.meminfo.total_32bit_memory;
|
||||
debug("RAM size %llx\n", (unsigned long long)gd->ram_size);
|
||||
|
||||
debug("MRC output data length %#x at %p\n", pei_data->data_to_save_size,
|
||||
pei_data->data_to_save);
|
||||
/* S3 resume: don't save scrambler seed or MRC data */
|
||||
if (pei_data->boot_mode != SLEEP_STATE_S3) {
|
||||
/*
|
||||
* This will be copied to SDRAM in reserve_arch(), then written
|
||||
* to SPI flash in mrccache_save()
|
||||
*/
|
||||
gd->arch.mrc_output = (char *)pei_data->data_to_save;
|
||||
gd->arch.mrc_output_len = pei_data->data_to_save_size;
|
||||
}
|
||||
gd->arch.pei_meminfo = pei_data->meminfo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use this hook to save our SDRAM parameters */
|
||||
int misc_init_r(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mrccache_save();
|
||||
if (ret)
|
||||
printf("Unable to save MRC data: %d\n", ret);
|
||||
else
|
||||
debug("Saved MRC cache data\n");
|
||||
|
||||
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 },
|
||||
{ .compatible = "intel,gma", .data = X86_SYSCON_GMA },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(syscon_intel_me) = {
|
||||
.name = "intel_me_syscon",
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = broadwell_syscon_ids,
|
||||
};
|
||||
Reference in New Issue
Block a user