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:
2026-03-03 21:46:32 +02:00
parent fe3ba02c96
commit 68d74d3181
11967 changed files with 2221897 additions and 0 deletions

View 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

View 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

View 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),
};

View 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;
}

View 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,
};

View 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;
}

View 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,
};

View 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, &reg16);
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, &reg16);
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,
};

View 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, &regs->config[gpio].conf_a);
outl(pin->sense_disable << CONFB_SENSE_SHIFT,
&regs->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], &regs->own[set]);
outl(route_smi[set], &regs->gpi_route[set]);
outl(irq_enable[set], &regs->gpi_ie[set]);
outl(reset_rsmrst[set], &regs->rst_sel[set]);
}
outl(pirq2apic, &regs->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,
};

View 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);
}

View 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;
}

View 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, &reg16);
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, &reg32);
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, &reg32);
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, &reg32);
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, &reg32);
reg32 |= 1 << 29;
dm_pci_write_config32(dev, 0x98, reg32);
/* Register Lock */
dm_pci_read_config32(dev, 0x9c, &reg32);
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),
};

View 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,
};