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:
35
u-boot/arch/x86/cpu/Makefile
Normal file
35
u-boot/arch/x86/cpu/Makefile
Normal file
@@ -0,0 +1,35 @@
|
||||
#
|
||||
# (C) Copyright 2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# (C) Copyright 2002
|
||||
# Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
extra-y = start.o
|
||||
obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o
|
||||
obj-y += interrupts.o cpu.o cpu_x86.o call64.o
|
||||
|
||||
AFLAGS_REMOVE_call32.o := -mregparm=3 \
|
||||
$(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32)
|
||||
AFLAGS_call32.o := -fpic -fshort-wchar
|
||||
|
||||
extra-y += call32.o
|
||||
|
||||
obj-y += intel_common/
|
||||
obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/
|
||||
obj-$(CONFIG_INTEL_BROADWELL) += broadwell/
|
||||
obj-$(CONFIG_SYS_COREBOOT) += coreboot/
|
||||
obj-$(CONFIG_EFI_APP) += efi/
|
||||
obj-$(CONFIG_QEMU) += qemu/
|
||||
obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/
|
||||
obj-$(CONFIG_INTEL_QUARK) += quark/
|
||||
obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/
|
||||
obj-y += irq.o lapic.o ioapic.o
|
||||
obj-$(CONFIG_SMP) += mp_init.o
|
||||
obj-y += mtrr.o
|
||||
obj-$(CONFIG_PCI) += pci.o
|
||||
obj-$(CONFIG_SMP) += sipi_vector.o
|
||||
obj-y += turbo.o
|
||||
9
u-boot/arch/x86/cpu/baytrail/Kconfig
Normal file
9
u-boot/arch/x86/cpu/baytrail/Kconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Copyright (C) 2015 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
config INTEL_BAYTRAIL
|
||||
bool
|
||||
select HAVE_FSP if !EFI
|
||||
11
u-boot/arch/x86/cpu/baytrail/Makefile
Normal file
11
u-boot/arch/x86/cpu/baytrail/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Copyright (C) 2015 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += cpu.o
|
||||
obj-y += early_uart.o
|
||||
obj-y += fsp_configs.o
|
||||
obj-y += valleyview.o
|
||||
obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o
|
||||
163
u-boot/arch/x86/cpu/baytrail/acpi.c
Normal file
163
u-boot/arch/x86/cpu/baytrail/acpi.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/acpi_table.h>
|
||||
#include <asm/ioapic.h>
|
||||
#include <asm/mpspec.h>
|
||||
#include <asm/tables.h>
|
||||
#include <asm/arch/iomap.h>
|
||||
|
||||
void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs,
|
||||
void *dsdt)
|
||||
{
|
||||
struct acpi_table_header *header = &(fadt->header);
|
||||
u16 pmbase = ACPI_BASE_ADDRESS;
|
||||
|
||||
memset((void *)fadt, 0, sizeof(struct acpi_fadt));
|
||||
|
||||
acpi_fill_header(header, "FACP");
|
||||
header->length = sizeof(struct acpi_fadt);
|
||||
header->revision = 4;
|
||||
|
||||
fadt->firmware_ctrl = (u32)facs;
|
||||
fadt->dsdt = (u32)dsdt;
|
||||
fadt->preferred_pm_profile = ACPI_PM_MOBILE;
|
||||
fadt->sci_int = 9;
|
||||
fadt->smi_cmd = 0;
|
||||
fadt->acpi_enable = 0;
|
||||
fadt->acpi_disable = 0;
|
||||
fadt->s4bios_req = 0;
|
||||
fadt->pstate_cnt = 0;
|
||||
fadt->pm1a_evt_blk = pmbase;
|
||||
fadt->pm1b_evt_blk = 0x0;
|
||||
fadt->pm1a_cnt_blk = pmbase + 0x4;
|
||||
fadt->pm1b_cnt_blk = 0x0;
|
||||
fadt->pm2_cnt_blk = pmbase + 0x50;
|
||||
fadt->pm_tmr_blk = pmbase + 0x8;
|
||||
fadt->gpe0_blk = pmbase + 0x20;
|
||||
fadt->gpe1_blk = 0;
|
||||
fadt->pm1_evt_len = 4;
|
||||
fadt->pm1_cnt_len = 2;
|
||||
fadt->pm2_cnt_len = 1;
|
||||
fadt->pm_tmr_len = 4;
|
||||
fadt->gpe0_blk_len = 8;
|
||||
fadt->gpe1_blk_len = 0;
|
||||
fadt->gpe1_base = 0;
|
||||
fadt->cst_cnt = 0;
|
||||
fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
|
||||
fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
|
||||
fadt->flush_size = 0;
|
||||
fadt->flush_stride = 0;
|
||||
fadt->duty_offset = 1;
|
||||
fadt->duty_width = 0;
|
||||
fadt->day_alrm = 0x0d;
|
||||
fadt->mon_alrm = 0x00;
|
||||
fadt->century = 0x00;
|
||||
fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
|
||||
fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
|
||||
ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON |
|
||||
ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_RESET_REGISTER |
|
||||
ACPI_FADT_PLATFORM_CLOCK;
|
||||
|
||||
fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->reset_reg.bit_width = 8;
|
||||
fadt->reset_reg.bit_offset = 0;
|
||||
fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
|
||||
fadt->reset_reg.addrl = IO_PORT_RESET;
|
||||
fadt->reset_reg.addrh = 0;
|
||||
fadt->reset_value = SYS_RST | RST_CPU;
|
||||
|
||||
fadt->x_firmware_ctl_l = (u32)facs;
|
||||
fadt->x_firmware_ctl_h = 0;
|
||||
fadt->x_dsdt_l = (u32)dsdt;
|
||||
fadt->x_dsdt_h = 0;
|
||||
|
||||
fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8;
|
||||
fadt->x_pm1a_evt_blk.bit_offset = 0;
|
||||
fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
|
||||
fadt->x_pm1a_evt_blk.addrl = fadt->pm1a_evt_blk;
|
||||
fadt->x_pm1a_evt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm1b_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm1b_evt_blk.bit_width = 0;
|
||||
fadt->x_pm1b_evt_blk.bit_offset = 0;
|
||||
fadt->x_pm1b_evt_blk.access_size = 0;
|
||||
fadt->x_pm1b_evt_blk.addrl = 0x0;
|
||||
fadt->x_pm1b_evt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm1a_cnt_blk.bit_width = fadt->pm1_cnt_len * 8;
|
||||
fadt->x_pm1a_cnt_blk.bit_offset = 0;
|
||||
fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
|
||||
fadt->x_pm1a_cnt_blk.addrl = fadt->pm1a_cnt_blk;
|
||||
fadt->x_pm1a_cnt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm1b_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm1b_cnt_blk.bit_width = 0;
|
||||
fadt->x_pm1b_cnt_blk.bit_offset = 0;
|
||||
fadt->x_pm1b_cnt_blk.access_size = 0;
|
||||
fadt->x_pm1b_cnt_blk.addrl = 0x0;
|
||||
fadt->x_pm1b_cnt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm2_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm2_cnt_blk.bit_width = fadt->pm2_cnt_len * 8;
|
||||
fadt->x_pm2_cnt_blk.bit_offset = 0;
|
||||
fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
|
||||
fadt->x_pm2_cnt_blk.addrl = fadt->pm2_cnt_blk;
|
||||
fadt->x_pm2_cnt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm_tmr_blk.bit_width = fadt->pm_tmr_len * 8;
|
||||
fadt->x_pm_tmr_blk.bit_offset = 0;
|
||||
fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
|
||||
fadt->x_pm_tmr_blk.addrl = fadt->pm_tmr_blk;
|
||||
fadt->x_pm_tmr_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_gpe0_blk.bit_width = fadt->gpe0_blk_len * 8;
|
||||
fadt->x_gpe0_blk.bit_offset = 0;
|
||||
fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
|
||||
fadt->x_gpe0_blk.addrl = fadt->gpe0_blk;
|
||||
fadt->x_gpe0_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_gpe1_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_gpe1_blk.bit_width = 0;
|
||||
fadt->x_gpe1_blk.bit_offset = 0;
|
||||
fadt->x_gpe1_blk.access_size = 0;
|
||||
fadt->x_gpe1_blk.addrl = 0x0;
|
||||
fadt->x_gpe1_blk.addrh = 0x0;
|
||||
|
||||
header->checksum = table_compute_checksum(fadt, header->length);
|
||||
}
|
||||
|
||||
static int acpi_create_madt_irq_overrides(u32 current)
|
||||
{
|
||||
struct acpi_madt_irqoverride *irqovr;
|
||||
u16 sci_flags = MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_HIGH;
|
||||
int length = 0;
|
||||
|
||||
irqovr = (void *)current;
|
||||
length += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0);
|
||||
|
||||
irqovr = (void *)(current + length);
|
||||
length += acpi_create_madt_irqoverride(irqovr, 0, 9, 9, sci_flags);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
u32 acpi_fill_madt(u32 current)
|
||||
{
|
||||
current += acpi_create_madt_lapics(current);
|
||||
|
||||
current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current,
|
||||
io_apic_read(IO_APIC_ID) >> 24, IO_APIC_ADDR, 0);
|
||||
|
||||
current += acpi_create_madt_irq_overrides(current);
|
||||
|
||||
return current;
|
||||
}
|
||||
158
u-boot/arch/x86/cpu/baytrail/cpu.c
Normal file
158
u-boot/arch/x86/cpu/baytrail/cpu.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Based on code from coreboot
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu.h>
|
||||
#include <dm.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu_x86.h>
|
||||
#include <asm/lapic.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/turbo.h>
|
||||
|
||||
static void set_max_freq(void)
|
||||
{
|
||||
msr_t perf_ctl;
|
||||
msr_t msr;
|
||||
|
||||
/* Enable speed step */
|
||||
msr = msr_read(MSR_IA32_MISC_ENABLES);
|
||||
msr.lo |= (1 << 16);
|
||||
msr_write(MSR_IA32_MISC_ENABLES, msr);
|
||||
|
||||
/*
|
||||
* Set guaranteed ratio [21:16] from IACORE_RATIOS to bits [15:8] of
|
||||
* the PERF_CTL
|
||||
*/
|
||||
msr = msr_read(MSR_IACORE_RATIOS);
|
||||
perf_ctl.lo = (msr.lo & 0x3f0000) >> 8;
|
||||
|
||||
/*
|
||||
* Set guaranteed vid [21:16] from IACORE_VIDS to bits [7:0] of
|
||||
* the PERF_CTL
|
||||
*/
|
||||
msr = msr_read(MSR_IACORE_VIDS);
|
||||
perf_ctl.lo |= (msr.lo & 0x7f0000) >> 16;
|
||||
perf_ctl.hi = 0;
|
||||
|
||||
msr_write(MSR_IA32_PERF_CTL, perf_ctl);
|
||||
}
|
||||
|
||||
static int cpu_x86_baytrail_probe(struct udevice *dev)
|
||||
{
|
||||
if (!ll_boot_init())
|
||||
return 0;
|
||||
debug("Init BayTrail core\n");
|
||||
|
||||
/*
|
||||
* On BayTrail the turbo disable bit is actually scoped at the
|
||||
* building-block level, not package. For non-BSP cores that are
|
||||
* within a building block, enable turbo. The cores within the BSP's
|
||||
* building block will just see it already enabled and move on.
|
||||
*/
|
||||
if (lapicid())
|
||||
turbo_enable();
|
||||
|
||||
/* Dynamic L2 shrink enable and threshold */
|
||||
msr_clrsetbits_64(MSR_PMG_CST_CONFIG_CONTROL, 0x3f000f, 0xe0008),
|
||||
|
||||
/* Disable C1E */
|
||||
msr_clrsetbits_64(MSR_POWER_CTL, 2, 0);
|
||||
msr_setbits_64(MSR_POWER_MISC, 0x44);
|
||||
|
||||
/* Set this core to max frequency ratio */
|
||||
set_max_freq();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned bus_freq(void)
|
||||
{
|
||||
msr_t clk_info = msr_read(MSR_BSEL_CR_OVERCLOCK_CONTROL);
|
||||
switch (clk_info.lo & 0x3) {
|
||||
case 0:
|
||||
return 83333333;
|
||||
case 1:
|
||||
return 100000000;
|
||||
case 2:
|
||||
return 133333333;
|
||||
case 3:
|
||||
return 116666666;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long tsc_freq(void)
|
||||
{
|
||||
msr_t platform_info;
|
||||
ulong bclk = bus_freq();
|
||||
|
||||
if (!bclk)
|
||||
return 0;
|
||||
|
||||
platform_info = msr_read(MSR_PLATFORM_INFO);
|
||||
|
||||
return bclk * ((platform_info.lo >> 8) & 0xff);
|
||||
}
|
||||
|
||||
static int baytrail_get_info(struct udevice *dev, struct cpu_info *info)
|
||||
{
|
||||
info->cpu_freq = tsc_freq();
|
||||
info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int baytrail_get_count(struct udevice *dev)
|
||||
{
|
||||
int ecx = 0;
|
||||
|
||||
/*
|
||||
* Use the algorithm described in Intel 64 and IA-32 Architectures
|
||||
* Software Developer's Manual Volume 3 (3A, 3B & 3C): System
|
||||
* Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping
|
||||
* of CPUID Extended Topology Leaf.
|
||||
*/
|
||||
while (1) {
|
||||
struct cpuid_result leaf_b;
|
||||
|
||||
leaf_b = cpuid_ext(0xb, ecx);
|
||||
|
||||
/*
|
||||
* Bay Trail doesn't have hyperthreading so just determine the
|
||||
* number of cores by from level type (ecx[15:8] == * 2)
|
||||
*/
|
||||
if ((leaf_b.ecx & 0xff00) == 0x0200)
|
||||
return leaf_b.ebx & 0xffff;
|
||||
|
||||
ecx++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cpu_ops cpu_x86_baytrail_ops = {
|
||||
.get_desc = cpu_x86_get_desc,
|
||||
.get_info = baytrail_get_info,
|
||||
.get_count = baytrail_get_count,
|
||||
};
|
||||
|
||||
static const struct udevice_id cpu_x86_baytrail_ids[] = {
|
||||
{ .compatible = "intel,baytrail-cpu" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(cpu_x86_baytrail_drv) = {
|
||||
.name = "cpu_x86_baytrail",
|
||||
.id = UCLASS_CPU,
|
||||
.of_match = cpu_x86_baytrail_ids,
|
||||
.bind = cpu_x86_bind,
|
||||
.probe = cpu_x86_baytrail_probe,
|
||||
.ops = &cpu_x86_baytrail_ops,
|
||||
};
|
||||
82
u-boot/arch/x86/cpu/baytrail/early_uart.c
Normal file
82
u-boot/arch/x86/cpu/baytrail/early_uart.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define PCI_DEV_CONFIG(segbus, dev, fn) ( \
|
||||
(((segbus) & 0xfff) << 20) | \
|
||||
(((dev) & 0x1f) << 15) | \
|
||||
(((fn) & 0x07) << 12))
|
||||
|
||||
/* Platform Controller Unit */
|
||||
#define LPC_DEV 0x1f
|
||||
#define LPC_FUNC 0
|
||||
|
||||
/* Enable UART */
|
||||
#define UART_CONT 0x80
|
||||
|
||||
/* SCORE Pad definitions */
|
||||
#define UART_RXD_PAD 82
|
||||
#define UART_TXD_PAD 83
|
||||
|
||||
/* Pad base: PAD_CONF0[n]= PAD_BASE + 16 * n */
|
||||
#define GPSCORE_PAD_BASE (IO_BASE_ADDRESS + IO_BASE_OFFSET_GPSCORE)
|
||||
|
||||
/* IO Memory */
|
||||
#define IO_BASE_ADDRESS 0xfed0c000
|
||||
#define IO_BASE_OFFSET_GPSCORE 0x0000
|
||||
#define IO_BASE_OFFSET_GPNCORE 0x1000
|
||||
#define IO_BASE_OFFSET_GPSSUS 0x2000
|
||||
#define IO_BASE_SIZE 0x4000
|
||||
|
||||
static inline unsigned int score_pconf0(int pad_num)
|
||||
{
|
||||
return GPSCORE_PAD_BASE + pad_num * 16;
|
||||
}
|
||||
|
||||
static void score_select_func(int pad, int func)
|
||||
{
|
||||
uint32_t reg;
|
||||
uint32_t pconf0_addr = score_pconf0(pad);
|
||||
|
||||
reg = readl(pconf0_addr);
|
||||
reg &= ~0x7;
|
||||
reg |= func & 0x7;
|
||||
writel(reg, pconf0_addr);
|
||||
}
|
||||
|
||||
static void x86_pci_write_config32(int dev, unsigned int where, u32 value)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
addr = CONFIG_PCIE_ECAM_BASE | dev | (where & ~3);
|
||||
writel(value, addr);
|
||||
}
|
||||
|
||||
/* This can be called after memory-mapped PCI is working */
|
||||
int setup_internal_uart(int enable)
|
||||
{
|
||||
/* Enable or disable the legacy UART hardware */
|
||||
x86_pci_write_config32(PCI_DEV_CONFIG(0, LPC_DEV, LPC_FUNC), UART_CONT,
|
||||
enable);
|
||||
|
||||
/* All done for the disable part, so just return */
|
||||
if (!enable)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Set up the pads to the UART function. This allows the signals to
|
||||
* leave the chip
|
||||
*/
|
||||
score_select_func(UART_RXD_PAD, 1);
|
||||
score_select_func(UART_TXD_PAD, 1);
|
||||
|
||||
/* TODO(sjg@chromium.org): Call debug_uart_init() */
|
||||
|
||||
return 0;
|
||||
}
|
||||
265
u-boot/arch/x86/cpu/baytrail/fsp_configs.c
Normal file
265
u-boot/arch/x86/cpu/baytrail/fsp_configs.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
* Copyright (C) 2015, Kodak Alaris, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Intel
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fdtdec.h>
|
||||
#include <asm/arch/fsp/azalia.h>
|
||||
#include <asm/fsp/fsp_support.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* ALC262 Verb Table - 10EC0262 */
|
||||
static const uint32_t verb_table_data13[] = {
|
||||
/* Pin Complex (NID 0x11) */
|
||||
0x01171cf0,
|
||||
0x01171d11,
|
||||
0x01171e11,
|
||||
0x01171f41,
|
||||
/* Pin Complex (NID 0x12) */
|
||||
0x01271cf0,
|
||||
0x01271d11,
|
||||
0x01271e11,
|
||||
0x01271f41,
|
||||
/* Pin Complex (NID 0x14) */
|
||||
0x01471c10,
|
||||
0x01471d40,
|
||||
0x01471e01,
|
||||
0x01471f01,
|
||||
/* Pin Complex (NID 0x15) */
|
||||
0x01571cf0,
|
||||
0x01571d11,
|
||||
0x01571e11,
|
||||
0x01571f41,
|
||||
/* Pin Complex (NID 0x16) */
|
||||
0x01671cf0,
|
||||
0x01671d11,
|
||||
0x01671e11,
|
||||
0x01671f41,
|
||||
/* Pin Complex (NID 0x18) */
|
||||
0x01871c20,
|
||||
0x01871d98,
|
||||
0x01871ea1,
|
||||
0x01871f01,
|
||||
/* Pin Complex (NID 0x19) */
|
||||
0x01971c21,
|
||||
0x01971d98,
|
||||
0x01971ea1,
|
||||
0x01971f02,
|
||||
/* Pin Complex (NID 0x1A) */
|
||||
0x01a71c2f,
|
||||
0x01a71d30,
|
||||
0x01a71e81,
|
||||
0x01a71f01,
|
||||
/* Pin Complex */
|
||||
0x01b71c1f,
|
||||
0x01b71d40,
|
||||
0x01b71e21,
|
||||
0x01b71f02,
|
||||
/* Pin Complex */
|
||||
0x01c71cf0,
|
||||
0x01c71d11,
|
||||
0x01c71e11,
|
||||
0x01c71f41,
|
||||
/* Pin Complex */
|
||||
0x01d71c01,
|
||||
0x01d71dc6,
|
||||
0x01d71e14,
|
||||
0x01d71f40,
|
||||
/* Pin Complex */
|
||||
0x01e71cf0,
|
||||
0x01e71d11,
|
||||
0x01e71e11,
|
||||
0x01e71f41,
|
||||
/* Pin Complex */
|
||||
0x01f71cf0,
|
||||
0x01f71d11,
|
||||
0x01f71e11,
|
||||
0x01f71f41,
|
||||
};
|
||||
|
||||
/*
|
||||
* This needs to be in ROM since if we put it in CAR, FSP init loses it when
|
||||
* it drops CAR.
|
||||
*
|
||||
* TODO(sjg@chromium.org): Move to device tree when FSP allows it
|
||||
*
|
||||
* VerbTable: (RealTek ALC262)
|
||||
* Revision ID = 0xFF, support all steps
|
||||
* Codec Verb Table For AZALIA
|
||||
* Codec Address: CAd value (0/1/2)
|
||||
* Codec Vendor: 0x10EC0262
|
||||
*/
|
||||
static const struct pch_azalia_verb_table azalia_verb_table[] = {
|
||||
{
|
||||
{
|
||||
0x10ec0262,
|
||||
0x0000,
|
||||
0xff,
|
||||
0x01,
|
||||
0x000b,
|
||||
0x0002,
|
||||
},
|
||||
verb_table_data13
|
||||
}
|
||||
};
|
||||
|
||||
const struct pch_azalia_config azalia_config = {
|
||||
.pme_enable = 1,
|
||||
.docking_supported = 1,
|
||||
.docking_attached = 0,
|
||||
.hdmi_codec_enable = 1,
|
||||
.azalia_v_ci_enable = 1,
|
||||
.rsvdbits = 0,
|
||||
.azalia_verb_table_num = 1,
|
||||
.azalia_verb_table = azalia_verb_table,
|
||||
.reset_wait_timer_us = 300
|
||||
};
|
||||
|
||||
/**
|
||||
* Override the FSP's configuration data.
|
||||
* If the device tree does not specify an integer setting, use the default
|
||||
* provided in Intel's Baytrail_FSP_Gold4.tgz release FSP/BayleyBayFsp.bsf file.
|
||||
*/
|
||||
void update_fsp_configs(struct fsp_config_data *config,
|
||||
struct fspinit_rtbuf *rt_buf)
|
||||
{
|
||||
struct upd_region *fsp_upd = &config->fsp_upd;
|
||||
struct memory_down_data *mem;
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node;
|
||||
|
||||
/* Initialize runtime buffer for fsp_init() */
|
||||
rt_buf->common.stack_top = config->common.stack_top - 32;
|
||||
rt_buf->common.boot_mode = config->common.boot_mode;
|
||||
rt_buf->common.upd_data = &config->fsp_upd;
|
||||
|
||||
fsp_upd->azalia_config_ptr = (uint32_t)&azalia_config;
|
||||
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_BAYTRAIL_FSP);
|
||||
if (node < 0) {
|
||||
debug("%s: Cannot find FSP node\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
fsp_upd->mrc_init_tseg_size = fdtdec_get_int(blob, node,
|
||||
"fsp,mrc-init-tseg-size",
|
||||
0);
|
||||
fsp_upd->mrc_init_mmio_size = fdtdec_get_int(blob, node,
|
||||
"fsp,mrc-init-mmio-size",
|
||||
0x800);
|
||||
fsp_upd->mrc_init_spd_addr1 = fdtdec_get_int(blob, node,
|
||||
"fsp,mrc-init-spd-addr1",
|
||||
0xa0);
|
||||
fsp_upd->mrc_init_spd_addr2 = fdtdec_get_int(blob, node,
|
||||
"fsp,mrc-init-spd-addr2",
|
||||
0xa2);
|
||||
fsp_upd->emmc_boot_mode = fdtdec_get_int(blob, node,
|
||||
"fsp,emmc-boot-mode", 2);
|
||||
fsp_upd->enable_sdio = fdtdec_get_bool(blob, node, "fsp,enable-sdio");
|
||||
fsp_upd->enable_sdcard = fdtdec_get_bool(blob, node,
|
||||
"fsp,enable-sdcard");
|
||||
fsp_upd->enable_hsuart0 = fdtdec_get_bool(blob, node,
|
||||
"fsp,enable-hsuart0");
|
||||
fsp_upd->enable_hsuart1 = fdtdec_get_bool(blob, node,
|
||||
"fsp,enable-hsuart1");
|
||||
fsp_upd->enable_spi = fdtdec_get_bool(blob, node, "fsp,enable-spi");
|
||||
fsp_upd->enable_sata = fdtdec_get_bool(blob, node, "fsp,enable-sata");
|
||||
fsp_upd->sata_mode = fdtdec_get_int(blob, node, "fsp,sata-mode", 1);
|
||||
fsp_upd->enable_azalia = fdtdec_get_bool(blob, node,
|
||||
"fsp,enable-azalia");
|
||||
fsp_upd->enable_xhci = fdtdec_get_bool(blob, node, "fsp,enable-xhci");
|
||||
fsp_upd->enable_lpe = fdtdec_get_bool(blob, node, "fsp,enable-lpe");
|
||||
fsp_upd->lpss_sio_enable_pci_mode = fdtdec_get_bool(blob, node,
|
||||
"fsp,lpss-sio-enable-pci-mode");
|
||||
fsp_upd->enable_dma0 = fdtdec_get_bool(blob, node, "fsp,enable-dma0");
|
||||
fsp_upd->enable_dma1 = fdtdec_get_bool(blob, node, "fsp,enable-dma1");
|
||||
fsp_upd->enable_i2_c0 = fdtdec_get_bool(blob, node, "fsp,enable-i2c0");
|
||||
fsp_upd->enable_i2_c1 = fdtdec_get_bool(blob, node, "fsp,enable-i2c1");
|
||||
fsp_upd->enable_i2_c2 = fdtdec_get_bool(blob, node, "fsp,enable-i2c2");
|
||||
fsp_upd->enable_i2_c3 = fdtdec_get_bool(blob, node, "fsp,enable-i2c3");
|
||||
fsp_upd->enable_i2_c4 = fdtdec_get_bool(blob, node, "fsp,enable-i2c4");
|
||||
fsp_upd->enable_i2_c5 = fdtdec_get_bool(blob, node, "fsp,enable-i2c5");
|
||||
fsp_upd->enable_i2_c6 = fdtdec_get_bool(blob, node, "fsp,enable-i2c6");
|
||||
fsp_upd->enable_pwm0 = fdtdec_get_bool(blob, node, "fsp,enable-pwm0");
|
||||
fsp_upd->enable_pwm1 = fdtdec_get_bool(blob, node, "fsp,enable-pwm1");
|
||||
fsp_upd->enable_hsi = fdtdec_get_bool(blob, node, "fsp,enable-hsi");
|
||||
fsp_upd->igd_dvmt50_pre_alloc = fdtdec_get_int(blob, node,
|
||||
"fsp,igd-dvmt50-pre-alloc", 2);
|
||||
fsp_upd->aperture_size = fdtdec_get_int(blob, node, "fsp,aperture-size",
|
||||
2);
|
||||
fsp_upd->gtt_size = fdtdec_get_int(blob, node, "fsp,gtt-size", 2);
|
||||
fsp_upd->serial_debug_port_address = fdtdec_get_int(blob, node,
|
||||
"fsp,serial-debug-port-address", 0x3f8);
|
||||
fsp_upd->serial_debug_port_type = fdtdec_get_int(blob, node,
|
||||
"fsp,serial-debug-port-type", 1);
|
||||
fsp_upd->mrc_debug_msg = fdtdec_get_bool(blob, node,
|
||||
"fsp,mrc-debug-msg");
|
||||
fsp_upd->isp_enable = fdtdec_get_bool(blob, node, "fsp,isp-enable");
|
||||
fsp_upd->scc_enable_pci_mode = fdtdec_get_bool(blob, node,
|
||||
"fsp,scc-enable-pci-mode");
|
||||
fsp_upd->igd_render_standby = fdtdec_get_bool(blob, node,
|
||||
"fsp,igd-render-standby");
|
||||
fsp_upd->txe_uma_enable = fdtdec_get_bool(blob, node,
|
||||
"fsp,txe-uma-enable");
|
||||
fsp_upd->os_selection = fdtdec_get_int(blob, node, "fsp,os-selection",
|
||||
4);
|
||||
fsp_upd->emmc45_ddr50_enabled = fdtdec_get_bool(blob, node,
|
||||
"fsp,emmc45-ddr50-enabled");
|
||||
fsp_upd->emmc45_hs200_enabled = fdtdec_get_bool(blob, node,
|
||||
"fsp,emmc45-hs200-enabled");
|
||||
fsp_upd->emmc45_retune_timer_value = fdtdec_get_int(blob, node,
|
||||
"fsp,emmc45-retune-timer-value", 8);
|
||||
fsp_upd->enable_igd = fdtdec_get_bool(blob, node, "fsp,enable-igd");
|
||||
|
||||
mem = &fsp_upd->memory_params;
|
||||
mem->enable_memory_down = fdtdec_get_bool(blob, node,
|
||||
"fsp,enable-memory-down");
|
||||
if (mem->enable_memory_down) {
|
||||
node = fdtdec_next_compatible(blob, node,
|
||||
COMPAT_INTEL_BAYTRAIL_FSP_MDP);
|
||||
if (node < 0) {
|
||||
debug("%s: Cannot find FSP memory-down-params node\n",
|
||||
__func__);
|
||||
} else {
|
||||
mem->dram_speed = fdtdec_get_int(blob, node,
|
||||
"fsp,dram-speed",
|
||||
0x02);
|
||||
mem->dram_type = fdtdec_get_int(blob, node,
|
||||
"fsp,dram-type", 0x01);
|
||||
mem->dimm_0_enable = fdtdec_get_bool(blob, node,
|
||||
"fsp,dimm-0-enable");
|
||||
mem->dimm_1_enable = fdtdec_get_bool(blob, node,
|
||||
"fsp,dimm-1-enable");
|
||||
mem->dimm_width = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-width",
|
||||
0x00);
|
||||
mem->dimm_density = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-density",
|
||||
0x01);
|
||||
mem->dimm_bus_width = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-bus-width", 0x03);
|
||||
mem->dimm_sides = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-sides",
|
||||
0x00);
|
||||
mem->dimm_tcl = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-tcl", 0x09);
|
||||
mem->dimm_trpt_rcd = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-trpt-rcd", 0x09);
|
||||
mem->dimm_twr = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-twr", 0x0A);
|
||||
mem->dimm_twtr = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-twtr", 0x05);
|
||||
mem->dimm_trrd = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-trrd", 0x04);
|
||||
mem->dimm_trtp = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-trtp", 0x05);
|
||||
mem->dimm_tfaw = fdtdec_get_int(blob, node,
|
||||
"fsp,dimm-tfaw", 0x14);
|
||||
}
|
||||
}
|
||||
}
|
||||
62
u-boot/arch/x86/cpu/baytrail/valleyview.c
Normal file
62
u-boot/arch/x86/cpu/baytrail/valleyview.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mmc.h>
|
||||
#include <pci_ids.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/mrccache.h>
|
||||
#include <asm/post.h>
|
||||
|
||||
static struct pci_device_id mmc_supported[] = {
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SDIO },
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SDCARD },
|
||||
{},
|
||||
};
|
||||
|
||||
int cpu_mmc_init(bd_t *bis)
|
||||
{
|
||||
return pci_mmc_init("ValleyView SDHCI", mmc_supported);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_EFI_APP
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
post_code(POST_CPU_INIT);
|
||||
|
||||
ret = x86_cpu_init_f();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_misc_init(void)
|
||||
{
|
||||
if (!ll_boot_init())
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
/*
|
||||
* We intend not to check any return value here, as even MRC cache
|
||||
* is not saved successfully, it is not a severe error that will
|
||||
* prevent system from continuing to boot.
|
||||
*/
|
||||
mrccache_save();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void reset_cpu(ulong addr)
|
||||
{
|
||||
/* cold reset */
|
||||
x86_full_reset();
|
||||
}
|
||||
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,
|
||||
};
|
||||
64
u-boot/arch/x86/cpu/call32.S
Normal file
64
u-boot/arch/x86/cpu/call32.S
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* (C) Copyright 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/msr-index.h>
|
||||
#include <asm/processor-flags.h>
|
||||
|
||||
/*
|
||||
* rdi - 32-bit code segment selector
|
||||
* rsi - target address
|
||||
* rdx - table address (0 if none)
|
||||
*/
|
||||
.code64
|
||||
.globl cpu_call32
|
||||
cpu_call32:
|
||||
cli
|
||||
|
||||
/* Save table pointer */
|
||||
mov %edx, %ebx
|
||||
|
||||
/*
|
||||
* Debugging option, this outputs characters to the console UART
|
||||
* mov $0x3f8,%edx
|
||||
* mov $'a',%al
|
||||
* out %al,(%dx)
|
||||
*/
|
||||
|
||||
pushf
|
||||
push %rdi /* 32-bit code segment */
|
||||
lea compat(%rip), %rax
|
||||
push %rax
|
||||
.byte 0x48 /* REX prefix to force 64-bit far return */
|
||||
retf
|
||||
.code32
|
||||
compat:
|
||||
/*
|
||||
* We are now in compatibility mode with a default operand size of
|
||||
* 32 bits. First disable paging.
|
||||
*/
|
||||
movl %cr0, %eax
|
||||
andl $~X86_CR0_PG, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Invalidate TLB */
|
||||
xorl %eax, %eax
|
||||
movl %eax, %cr3
|
||||
|
||||
/* Disable Long mode in EFER (Extended Feature Enable Register) */
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
btr $_EFER_LME, %eax
|
||||
wrmsr
|
||||
|
||||
/* Set up table pointer for _x86boot_start */
|
||||
mov %ebx, %ecx
|
||||
|
||||
/* Jump to the required target */
|
||||
pushl %edi /* 32-bit code segment */
|
||||
pushl %esi /* 32-bit target address */
|
||||
retf
|
||||
93
u-boot/arch/x86/cpu/call64.S
Normal file
93
u-boot/arch/x86/cpu/call64.S
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* (C) Copyright 2014 Google, Inc
|
||||
* Copyright (C) 1991, 1992, 1993 Linus Torvalds
|
||||
*
|
||||
* Parts of this copied from Linux arch/x86/boot/compressed/head_64.S
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/msr-index.h>
|
||||
#include <asm/processor-flags.h>
|
||||
|
||||
.code32
|
||||
.globl cpu_call64
|
||||
cpu_call64:
|
||||
/*
|
||||
* cpu_call64(ulong pgtable, ulong setup_base, ulong target)
|
||||
*
|
||||
* eax - pgtable
|
||||
* edx - setup_base
|
||||
* ecx - target
|
||||
*/
|
||||
cli
|
||||
push %ecx /* arg2 = target */
|
||||
push %edx /* arg1 = setup_base */
|
||||
mov %eax, %ebx
|
||||
|
||||
/* Load new GDT with the 64bit segments using 32bit descriptor */
|
||||
leal gdt, %eax
|
||||
movl %eax, gdt+2
|
||||
lgdt gdt
|
||||
|
||||
/* Enable PAE mode */
|
||||
movl $(X86_CR4_PAE), %eax
|
||||
movl %eax, %cr4
|
||||
|
||||
/* Enable the boot page tables */
|
||||
leal (%ebx), %eax
|
||||
movl %eax, %cr3
|
||||
|
||||
/* Enable Long mode in EFER (Extended Feature Enable Register) */
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
btsl $_EFER_LME, %eax
|
||||
wrmsr
|
||||
|
||||
/* After gdt is loaded */
|
||||
xorl %eax, %eax
|
||||
lldt %ax
|
||||
movl $0x20, %eax
|
||||
ltr %ax
|
||||
|
||||
/*
|
||||
* Setup for the jump to 64bit mode
|
||||
*
|
||||
* When the jump is performed we will be in long mode but
|
||||
* in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
|
||||
* (and in turn EFER.LMA = 1). To jump into 64bit mode we use
|
||||
* the new gdt/idt that has __KERNEL_CS with CS.L = 1.
|
||||
* We place all of the values on our mini stack so lret can
|
||||
* used to perform that far jump. See the gdt below.
|
||||
*/
|
||||
pop %esi /* setup_base */
|
||||
|
||||
pushl $0x10
|
||||
leal lret_target, %eax
|
||||
pushl %eax
|
||||
|
||||
/* Enter paged protected Mode, activating Long Mode */
|
||||
movl $(X86_CR0_PG | X86_CR0_PE), %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Jump from 32bit compatibility mode into 64bit mode. */
|
||||
lret
|
||||
|
||||
code64:
|
||||
lret_target:
|
||||
pop %eax /* target */
|
||||
mov %eax, %eax /* Clear bits 63:32 */
|
||||
jmp *%eax /* Jump to the 64-bit target */
|
||||
|
||||
.data
|
||||
gdt:
|
||||
.word gdt_end - gdt - 1
|
||||
.long gdt /* Fixed up by code above */
|
||||
.word 0
|
||||
.quad 0x0000000000000000 /* NULL descriptor */
|
||||
.quad 0x00af9a000000ffff /* __KERNEL_CS */
|
||||
.quad 0x00cf92000000ffff /* __KERNEL_DS */
|
||||
.quad 0x0080890000000000 /* TS descriptor */
|
||||
.quad 0x0000000000000000 /* TS continued */
|
||||
gdt_end:
|
||||
17
u-boot/arch/x86/cpu/config.mk
Normal file
17
u-boot/arch/x86/cpu/config.mk
Normal file
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# (C) Copyright 2002
|
||||
# Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
CROSS_COMPILE ?= i386-linux-
|
||||
|
||||
PLATFORM_CPPFLAGS += -D__I386__
|
||||
|
||||
# DO NOT MODIFY THE FOLLOWING UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!
|
||||
LDPPFLAGS += -DRESET_SEG_START=$(CONFIG_RESET_SEG_START)
|
||||
LDPPFLAGS += -DRESET_SEG_SIZE=$(CONFIG_RESET_SEG_SIZE)
|
||||
LDPPFLAGS += -DRESET_VEC_LOC=$(CONFIG_RESET_VEC_LOC)
|
||||
LDPPFLAGS += -DSTART_16=$(CONFIG_SYS_X86_START16)
|
||||
LDPPFLAGS += -DRESET_BASE="CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE)"
|
||||
15
u-boot/arch/x86/cpu/coreboot/Kconfig
Normal file
15
u-boot/arch/x86/cpu/coreboot/Kconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
if TARGET_COREBOOT
|
||||
|
||||
config SYS_COREBOOT
|
||||
bool
|
||||
default y
|
||||
|
||||
config CBMEM_CONSOLE
|
||||
bool
|
||||
default y
|
||||
|
||||
config VIDEO_COREBOOT
|
||||
bool
|
||||
default y
|
||||
|
||||
endif
|
||||
20
u-boot/arch/x86/cpu/coreboot/Makefile
Normal file
20
u-boot/arch/x86/cpu/coreboot/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Copyright (c) 2011 The Chromium OS Authors.
|
||||
#
|
||||
# (C) Copyright 2008
|
||||
# Graeme Russ, graeme.russ@gmail.com.
|
||||
#
|
||||
# (C) Copyright 2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# (C) Copyright 2002
|
||||
# Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += car.o
|
||||
obj-y += coreboot.o
|
||||
obj-y += tables.o
|
||||
obj-y += sdram.o
|
||||
obj-y += timestamp.o
|
||||
13
u-boot/arch/x86/cpu/coreboot/car.S
Normal file
13
u-boot/arch/x86/cpu/coreboot/car.S
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors.
|
||||
* (C) Copyright 2010-2011
|
||||
* Graeme Russ, <graeme.russ@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
.section .text
|
||||
|
||||
.globl car_init
|
||||
car_init:
|
||||
jmp car_init_ret
|
||||
92
u-boot/arch/x86/cpu/coreboot/coreboot.c
Normal file
92
u-boot/arch/x86/cpu/coreboot/coreboot.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors.
|
||||
* (C) Copyright 2008
|
||||
* Graeme Russ, graeme.russ@gmail.com.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fdtdec.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/arch/sysinfo.h>
|
||||
#include <asm/arch/timestamp.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
int ret = get_coreboot_info(&lib_sysinfo);
|
||||
if (ret != 0) {
|
||||
printf("Failed to parse coreboot tables.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
timestamp_init();
|
||||
|
||||
return x86_cpu_init_f();
|
||||
}
|
||||
|
||||
int board_early_init_f(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
return default_print_cpuinfo();
|
||||
}
|
||||
|
||||
static void board_final_cleanup(void)
|
||||
{
|
||||
/*
|
||||
* Un-cache the ROM so the kernel has one
|
||||
* more MTRR available.
|
||||
*
|
||||
* Coreboot should have assigned this to the
|
||||
* top available variable MTRR.
|
||||
*/
|
||||
u8 top_mtrr = (native_read_msr(MTRR_CAP_MSR) & 0xff) - 1;
|
||||
u8 top_type = native_read_msr(MTRR_PHYS_BASE_MSR(top_mtrr)) & 0xff;
|
||||
|
||||
/* Make sure this MTRR is the correct Write-Protected type */
|
||||
if (top_type == MTRR_TYPE_WRPROT) {
|
||||
struct mtrr_state state;
|
||||
|
||||
mtrr_open(&state);
|
||||
wrmsrl(MTRR_PHYS_BASE_MSR(top_mtrr), 0);
|
||||
wrmsrl(MTRR_PHYS_MASK_MSR(top_mtrr), 0);
|
||||
mtrr_close(&state);
|
||||
}
|
||||
|
||||
if (!fdtdec_get_config_bool(gd->fdt_blob, "u-boot,no-apm-finalize")) {
|
||||
/*
|
||||
* Issue SMI to coreboot to lock down ME and registers
|
||||
* when allowed via device tree
|
||||
*/
|
||||
printf("Finalizing coreboot\n");
|
||||
outb(0xcb, 0xb2);
|
||||
}
|
||||
}
|
||||
|
||||
int last_stage_init(void)
|
||||
{
|
||||
if (gd->flags & GD_FLG_COLD_BOOT)
|
||||
timestamp_add_to_bootstage();
|
||||
|
||||
board_final_cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int misc_init_r(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_misc_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
124
u-boot/arch/x86/cpu/coreboot/sdram.c
Normal file
124
u-boot/arch/x86/cpu/coreboot/sdram.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors.
|
||||
* (C) Copyright 2010,2011
|
||||
* Graeme Russ, <graeme.russ@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/e820.h>
|
||||
#include <asm/arch/sysinfo.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
unsigned install_e820_map(unsigned max_entries, struct e820entry *entries)
|
||||
{
|
||||
unsigned num_entries;
|
||||
int i;
|
||||
|
||||
num_entries = min((unsigned)lib_sysinfo.n_memranges, max_entries);
|
||||
if (num_entries < lib_sysinfo.n_memranges) {
|
||||
printf("Warning: Limiting e820 map to %d entries.\n",
|
||||
num_entries);
|
||||
}
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
struct memrange *memrange = &lib_sysinfo.memrange[i];
|
||||
|
||||
entries[i].addr = memrange->base;
|
||||
entries[i].size = memrange->size;
|
||||
|
||||
/*
|
||||
* coreboot has some extensions (type 6 & 16) to the E820 types.
|
||||
* When we detect this, mark it as E820_RESERVED.
|
||||
*/
|
||||
if (memrange->type == CB_MEM_VENDOR_RSVD ||
|
||||
memrange->type == CB_MEM_TABLE)
|
||||
entries[i].type = E820_RESERVED;
|
||||
else
|
||||
entries[i].type = memrange->type;
|
||||
}
|
||||
|
||||
return num_entries;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function looks for the highest region of memory lower than 4GB which
|
||||
* has enough space for U-Boot where U-Boot is aligned on a page boundary. It
|
||||
* overrides the default implementation found elsewhere which simply picks the
|
||||
* end of ram, wherever that may be. The location of the stack, the relocation
|
||||
* address, and how far U-Boot is moved by relocation are set in the global
|
||||
* data structure.
|
||||
*/
|
||||
ulong board_get_usable_ram_top(ulong total_size)
|
||||
{
|
||||
uintptr_t dest_addr = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lib_sysinfo.n_memranges; i++) {
|
||||
struct memrange *memrange = &lib_sysinfo.memrange[i];
|
||||
/* Force U-Boot to relocate to a page aligned address. */
|
||||
uint64_t start = roundup(memrange->base, 1 << 12);
|
||||
uint64_t end = memrange->base + memrange->size;
|
||||
|
||||
/* Ignore non-memory regions. */
|
||||
if (memrange->type != CB_MEM_RAM)
|
||||
continue;
|
||||
|
||||
/* Filter memory over 4GB. */
|
||||
if (end > 0xffffffffULL)
|
||||
end = 0x100000000ULL;
|
||||
/* Skip this region if it's too small. */
|
||||
if (end - start < total_size)
|
||||
continue;
|
||||
|
||||
/* Use this address if it's the largest so far. */
|
||||
if (end > dest_addr)
|
||||
dest_addr = end;
|
||||
}
|
||||
|
||||
/* If no suitable area was found, return an error. */
|
||||
if (!dest_addr)
|
||||
panic("No available memory found for relocation");
|
||||
|
||||
return (ulong)dest_addr;
|
||||
}
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
int i;
|
||||
phys_size_t ram_size = 0;
|
||||
|
||||
for (i = 0; i < lib_sysinfo.n_memranges; i++) {
|
||||
struct memrange *memrange = &lib_sysinfo.memrange[i];
|
||||
unsigned long long end = memrange->base + memrange->size;
|
||||
|
||||
if (memrange->type == CB_MEM_RAM && end > ram_size)
|
||||
ram_size += memrange->size;
|
||||
}
|
||||
|
||||
gd->ram_size = ram_size;
|
||||
if (ram_size == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dram_init_banksize(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (CONFIG_NR_DRAM_BANKS) {
|
||||
for (i = 0, j = 0; i < lib_sysinfo.n_memranges; i++) {
|
||||
struct memrange *memrange = &lib_sysinfo.memrange[i];
|
||||
|
||||
if (memrange->type == CB_MEM_RAM) {
|
||||
gd->bd->bi_dram[j].start = memrange->base;
|
||||
gd->bd->bi_dram[j].size = memrange->size;
|
||||
j++;
|
||||
if (j >= CONFIG_NR_DRAM_BANKS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
234
u-boot/arch/x86/cpu/coreboot/tables.c
Normal file
234
u-boot/arch/x86/cpu/coreboot/tables.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2008 Advanced Micro Devices, Inc.
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <net.h>
|
||||
#include <asm/arch/sysinfo.h>
|
||||
|
||||
/*
|
||||
* This needs to be in the .data section so that it's copied over during
|
||||
* relocation. By default it's put in the .bss section which is simply filled
|
||||
* with zeroes when transitioning from "ROM", which is really RAM, to other
|
||||
* RAM.
|
||||
*/
|
||||
struct sysinfo_t lib_sysinfo __attribute__((section(".data")));
|
||||
|
||||
/*
|
||||
* Some of this is x86 specific, and the rest of it is generic. Right now,
|
||||
* since we only support x86, we'll avoid trying to make lots of infrastructure
|
||||
* we don't need. If in the future, we want to use coreboot on some other
|
||||
* architecture, then take out the generic parsing code and move it elsewhere.
|
||||
*/
|
||||
|
||||
/* === Parsing code === */
|
||||
/* This is the generic parsing code. */
|
||||
|
||||
static void cb_parse_memory(unsigned char *ptr, struct sysinfo_t *info)
|
||||
{
|
||||
struct cb_memory *mem = (struct cb_memory *)ptr;
|
||||
int count = MEM_RANGE_COUNT(mem);
|
||||
int i;
|
||||
|
||||
if (count > SYSINFO_MAX_MEM_RANGES)
|
||||
count = SYSINFO_MAX_MEM_RANGES;
|
||||
|
||||
info->n_memranges = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
struct cb_memory_range *range =
|
||||
(struct cb_memory_range *)MEM_RANGE_PTR(mem, i);
|
||||
|
||||
info->memrange[info->n_memranges].base =
|
||||
UNPACK_CB64(range->start);
|
||||
|
||||
info->memrange[info->n_memranges].size =
|
||||
UNPACK_CB64(range->size);
|
||||
|
||||
info->memrange[info->n_memranges].type = range->type;
|
||||
|
||||
info->n_memranges++;
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_parse_serial(unsigned char *ptr, struct sysinfo_t *info)
|
||||
{
|
||||
struct cb_serial *ser = (struct cb_serial *)ptr;
|
||||
info->serial = ser;
|
||||
}
|
||||
|
||||
static void cb_parse_vbnv(unsigned char *ptr, struct sysinfo_t *info)
|
||||
{
|
||||
struct cb_vbnv *vbnv = (struct cb_vbnv *)ptr;
|
||||
|
||||
info->vbnv_start = vbnv->vbnv_start;
|
||||
info->vbnv_size = vbnv->vbnv_size;
|
||||
}
|
||||
|
||||
static void cb_parse_gpios(unsigned char *ptr, struct sysinfo_t *info)
|
||||
{
|
||||
int i;
|
||||
struct cb_gpios *gpios = (struct cb_gpios *)ptr;
|
||||
|
||||
info->num_gpios = (gpios->count < SYSINFO_MAX_GPIOS) ?
|
||||
(gpios->count) : SYSINFO_MAX_GPIOS;
|
||||
|
||||
for (i = 0; i < info->num_gpios; i++)
|
||||
info->gpios[i] = gpios->gpios[i];
|
||||
}
|
||||
|
||||
static void cb_parse_vdat(unsigned char *ptr, struct sysinfo_t *info)
|
||||
{
|
||||
struct cb_vdat *vdat = (struct cb_vdat *) ptr;
|
||||
|
||||
info->vdat_addr = vdat->vdat_addr;
|
||||
info->vdat_size = vdat->vdat_size;
|
||||
}
|
||||
|
||||
static void cb_parse_tstamp(unsigned char *ptr, struct sysinfo_t *info)
|
||||
{
|
||||
info->tstamp_table = ((struct cb_cbmem_tab *)ptr)->cbmem_tab;
|
||||
}
|
||||
|
||||
static void cb_parse_cbmem_cons(unsigned char *ptr, struct sysinfo_t *info)
|
||||
{
|
||||
info->cbmem_cons = ((struct cb_cbmem_tab *)ptr)->cbmem_tab;
|
||||
}
|
||||
|
||||
static void cb_parse_framebuffer(unsigned char *ptr, struct sysinfo_t *info)
|
||||
{
|
||||
info->framebuffer = (struct cb_framebuffer *)ptr;
|
||||
}
|
||||
|
||||
static void cb_parse_string(unsigned char *ptr, char **info)
|
||||
{
|
||||
*info = (char *)((struct cb_string *)ptr)->string;
|
||||
}
|
||||
|
||||
static int cb_parse_header(void *addr, int len, struct sysinfo_t *info)
|
||||
{
|
||||
struct cb_header *header;
|
||||
unsigned char *ptr = (unsigned char *)addr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i += 16, ptr += 16) {
|
||||
header = (struct cb_header *)ptr;
|
||||
if (!strncmp((const char *)header->signature, "LBIO", 4))
|
||||
break;
|
||||
}
|
||||
|
||||
/* We walked the entire space and didn't find anything. */
|
||||
if (i >= len)
|
||||
return -1;
|
||||
|
||||
if (!header->table_bytes)
|
||||
return 0;
|
||||
|
||||
/* Make sure the checksums match. */
|
||||
if (!ip_checksum_ok(header, sizeof(*header)))
|
||||
return -1;
|
||||
|
||||
if (compute_ip_checksum(ptr + sizeof(*header), header->table_bytes) !=
|
||||
header->table_checksum)
|
||||
return -1;
|
||||
|
||||
/* Now, walk the tables. */
|
||||
ptr += header->header_bytes;
|
||||
|
||||
/* Inintialize some fields to sentinel values. */
|
||||
info->vbnv_start = info->vbnv_size = (uint32_t)(-1);
|
||||
|
||||
for (i = 0; i < header->table_entries; i++) {
|
||||
struct cb_record *rec = (struct cb_record *)ptr;
|
||||
|
||||
/* We only care about a few tags here (maybe more later). */
|
||||
switch (rec->tag) {
|
||||
case CB_TAG_FORWARD:
|
||||
return cb_parse_header(
|
||||
(void *)(unsigned long)
|
||||
((struct cb_forward *)rec)->forward,
|
||||
len, info);
|
||||
continue;
|
||||
case CB_TAG_MEMORY:
|
||||
cb_parse_memory(ptr, info);
|
||||
break;
|
||||
case CB_TAG_SERIAL:
|
||||
cb_parse_serial(ptr, info);
|
||||
break;
|
||||
case CB_TAG_VERSION:
|
||||
cb_parse_string(ptr, &info->version);
|
||||
break;
|
||||
case CB_TAG_EXTRA_VERSION:
|
||||
cb_parse_string(ptr, &info->extra_version);
|
||||
break;
|
||||
case CB_TAG_BUILD:
|
||||
cb_parse_string(ptr, &info->build);
|
||||
break;
|
||||
case CB_TAG_COMPILE_TIME:
|
||||
cb_parse_string(ptr, &info->compile_time);
|
||||
break;
|
||||
case CB_TAG_COMPILE_BY:
|
||||
cb_parse_string(ptr, &info->compile_by);
|
||||
break;
|
||||
case CB_TAG_COMPILE_HOST:
|
||||
cb_parse_string(ptr, &info->compile_host);
|
||||
break;
|
||||
case CB_TAG_COMPILE_DOMAIN:
|
||||
cb_parse_string(ptr, &info->compile_domain);
|
||||
break;
|
||||
case CB_TAG_COMPILER:
|
||||
cb_parse_string(ptr, &info->compiler);
|
||||
break;
|
||||
case CB_TAG_LINKER:
|
||||
cb_parse_string(ptr, &info->linker);
|
||||
break;
|
||||
case CB_TAG_ASSEMBLER:
|
||||
cb_parse_string(ptr, &info->assembler);
|
||||
break;
|
||||
/*
|
||||
* FIXME we should warn on serial if coreboot set up a
|
||||
* framebuffer buf the payload does not know about it.
|
||||
*/
|
||||
case CB_TAG_FRAMEBUFFER:
|
||||
cb_parse_framebuffer(ptr, info);
|
||||
break;
|
||||
case CB_TAG_GPIO:
|
||||
cb_parse_gpios(ptr, info);
|
||||
break;
|
||||
case CB_TAG_VDAT:
|
||||
cb_parse_vdat(ptr, info);
|
||||
break;
|
||||
case CB_TAG_TIMESTAMPS:
|
||||
cb_parse_tstamp(ptr, info);
|
||||
break;
|
||||
case CB_TAG_CBMEM_CONSOLE:
|
||||
cb_parse_cbmem_cons(ptr, info);
|
||||
break;
|
||||
case CB_TAG_VBNV:
|
||||
cb_parse_vbnv(ptr, info);
|
||||
break;
|
||||
}
|
||||
|
||||
ptr += rec->size;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* == Architecture specific == */
|
||||
/* This is the x86 specific stuff. */
|
||||
|
||||
int get_coreboot_info(struct sysinfo_t *info)
|
||||
{
|
||||
int ret = cb_parse_header((void *)0x00000000, 0x1000, info);
|
||||
|
||||
if (ret != 1)
|
||||
ret = cb_parse_header((void *)0x000f0000, 0x1000, info);
|
||||
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
86
u-boot/arch/x86/cpu/coreboot/timestamp.c
Normal file
86
u-boot/arch/x86/cpu/coreboot/timestamp.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/timestamp.h>
|
||||
#include <asm/arch/sysinfo.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
struct timestamp_entry {
|
||||
uint32_t entry_id;
|
||||
uint64_t entry_stamp;
|
||||
} __packed;
|
||||
|
||||
struct timestamp_table {
|
||||
uint64_t base_time;
|
||||
uint32_t max_entries;
|
||||
uint32_t num_entries;
|
||||
struct timestamp_entry entries[0]; /* Variable number of entries */
|
||||
} __packed;
|
||||
|
||||
static struct timestamp_table *ts_table __attribute__((section(".data")));
|
||||
|
||||
void timestamp_init(void)
|
||||
{
|
||||
timestamp_add_now(TS_U_BOOT_INITTED);
|
||||
}
|
||||
|
||||
void timestamp_add(enum timestamp_id id, uint64_t ts_time)
|
||||
{
|
||||
struct timestamp_entry *tse;
|
||||
|
||||
if (!ts_table || (ts_table->num_entries == ts_table->max_entries))
|
||||
return;
|
||||
|
||||
tse = &ts_table->entries[ts_table->num_entries++];
|
||||
tse->entry_id = id;
|
||||
tse->entry_stamp = ts_time - ts_table->base_time;
|
||||
}
|
||||
|
||||
void timestamp_add_now(enum timestamp_id id)
|
||||
{
|
||||
timestamp_add(id, rdtsc());
|
||||
}
|
||||
|
||||
int timestamp_add_to_bootstage(void)
|
||||
{
|
||||
uint i;
|
||||
|
||||
if (!ts_table)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < ts_table->num_entries; i++) {
|
||||
struct timestamp_entry *tse = &ts_table->entries[i];
|
||||
const char *name = NULL;
|
||||
|
||||
switch (tse->entry_id) {
|
||||
case TS_START_ROMSTAGE:
|
||||
name = "start-romstage";
|
||||
break;
|
||||
case TS_BEFORE_INITRAM:
|
||||
name = "before-initram";
|
||||
break;
|
||||
case TS_DEVICE_INITIALIZE:
|
||||
name = "device-initialize";
|
||||
break;
|
||||
case TS_DEVICE_DONE:
|
||||
name = "device-done";
|
||||
break;
|
||||
case TS_SELFBOOT_JUMP:
|
||||
name = "selfboot-jump";
|
||||
break;
|
||||
}
|
||||
if (name) {
|
||||
bootstage_add_record(0, name, BOOTSTAGEF_ALLOC,
|
||||
tse->entry_stamp /
|
||||
get_tbclk_mhz());
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
775
u-boot/arch/x86/cpu/cpu.c
Normal file
775
u-boot/arch/x86/cpu/cpu.c
Normal file
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
* (C) Copyright 2008-2011
|
||||
* Graeme Russ, <graeme.russ@gmail.com>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* Part of this file is adapted from coreboot
|
||||
* src/arch/x86/lib/cpu.c
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <syscon.h>
|
||||
#include <asm/control_regs.h>
|
||||
#include <asm/coreboot_tables.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/lapic.h>
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/mp.h>
|
||||
#include <asm/mrccache.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/interrupt.h>
|
||||
#include <asm/tables.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* Constructor for a conventional segment GDT (or LDT) entry
|
||||
* This is a macro so it can be used in initialisers
|
||||
*/
|
||||
#define GDT_ENTRY(flags, base, limit) \
|
||||
((((base) & 0xff000000ULL) << (56-24)) | \
|
||||
(((flags) & 0x0000f0ffULL) << 40) | \
|
||||
(((limit) & 0x000f0000ULL) << (48-16)) | \
|
||||
(((base) & 0x00ffffffULL) << 16) | \
|
||||
(((limit) & 0x0000ffffULL)))
|
||||
|
||||
struct gdt_ptr {
|
||||
u16 len;
|
||||
u32 ptr;
|
||||
} __packed;
|
||||
|
||||
struct cpu_device_id {
|
||||
unsigned vendor;
|
||||
unsigned device;
|
||||
};
|
||||
|
||||
struct cpuinfo_x86 {
|
||||
uint8_t x86; /* CPU family */
|
||||
uint8_t x86_vendor; /* CPU vendor */
|
||||
uint8_t x86_model;
|
||||
uint8_t x86_mask;
|
||||
};
|
||||
|
||||
/*
|
||||
* List of cpu vendor strings along with their normalized
|
||||
* id values.
|
||||
*/
|
||||
static const struct {
|
||||
int vendor;
|
||||
const char *name;
|
||||
} x86_vendors[] = {
|
||||
{ X86_VENDOR_INTEL, "GenuineIntel", },
|
||||
{ X86_VENDOR_CYRIX, "CyrixInstead", },
|
||||
{ X86_VENDOR_AMD, "AuthenticAMD", },
|
||||
{ X86_VENDOR_UMC, "UMC UMC UMC ", },
|
||||
{ X86_VENDOR_NEXGEN, "NexGenDriven", },
|
||||
{ X86_VENDOR_CENTAUR, "CentaurHauls", },
|
||||
{ X86_VENDOR_RISE, "RiseRiseRise", },
|
||||
{ X86_VENDOR_TRANSMETA, "GenuineTMx86", },
|
||||
{ X86_VENDOR_TRANSMETA, "TransmetaCPU", },
|
||||
{ X86_VENDOR_NSC, "Geode by NSC", },
|
||||
{ X86_VENDOR_SIS, "SiS SiS SiS ", },
|
||||
};
|
||||
|
||||
static const char *const x86_vendor_name[] = {
|
||||
[X86_VENDOR_INTEL] = "Intel",
|
||||
[X86_VENDOR_CYRIX] = "Cyrix",
|
||||
[X86_VENDOR_AMD] = "AMD",
|
||||
[X86_VENDOR_UMC] = "UMC",
|
||||
[X86_VENDOR_NEXGEN] = "NexGen",
|
||||
[X86_VENDOR_CENTAUR] = "Centaur",
|
||||
[X86_VENDOR_RISE] = "Rise",
|
||||
[X86_VENDOR_TRANSMETA] = "Transmeta",
|
||||
[X86_VENDOR_NSC] = "NSC",
|
||||
[X86_VENDOR_SIS] = "SiS",
|
||||
};
|
||||
|
||||
static void load_ds(u32 segment)
|
||||
{
|
||||
asm volatile("movl %0, %%ds" : : "r" (segment * X86_GDT_ENTRY_SIZE));
|
||||
}
|
||||
|
||||
static void load_es(u32 segment)
|
||||
{
|
||||
asm volatile("movl %0, %%es" : : "r" (segment * X86_GDT_ENTRY_SIZE));
|
||||
}
|
||||
|
||||
static void load_fs(u32 segment)
|
||||
{
|
||||
asm volatile("movl %0, %%fs" : : "r" (segment * X86_GDT_ENTRY_SIZE));
|
||||
}
|
||||
|
||||
static void load_gs(u32 segment)
|
||||
{
|
||||
asm volatile("movl %0, %%gs" : : "r" (segment * X86_GDT_ENTRY_SIZE));
|
||||
}
|
||||
|
||||
static void load_ss(u32 segment)
|
||||
{
|
||||
asm volatile("movl %0, %%ss" : : "r" (segment * X86_GDT_ENTRY_SIZE));
|
||||
}
|
||||
|
||||
static void load_gdt(const u64 *boot_gdt, u16 num_entries)
|
||||
{
|
||||
struct gdt_ptr gdt;
|
||||
|
||||
gdt.len = (num_entries * X86_GDT_ENTRY_SIZE) - 1;
|
||||
gdt.ptr = (u32)boot_gdt;
|
||||
|
||||
asm volatile("lgdtl %0\n" : : "m" (gdt));
|
||||
}
|
||||
|
||||
void arch_setup_gd(gd_t *new_gd)
|
||||
{
|
||||
u64 *gdt_addr;
|
||||
|
||||
gdt_addr = new_gd->arch.gdt;
|
||||
|
||||
/*
|
||||
* CS: code, read/execute, 4 GB, base 0
|
||||
*
|
||||
* Some OS (like VxWorks) requires GDT entry 1 to be the 32-bit CS
|
||||
*/
|
||||
gdt_addr[X86_GDT_ENTRY_UNUSED] = GDT_ENTRY(0xc09b, 0, 0xfffff);
|
||||
gdt_addr[X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff);
|
||||
|
||||
/* DS: data, read/write, 4 GB, base 0 */
|
||||
gdt_addr[X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff);
|
||||
|
||||
/* FS: data, read/write, 4 GB, base (Global Data Pointer) */
|
||||
new_gd->arch.gd_addr = new_gd;
|
||||
gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0xc093,
|
||||
(ulong)&new_gd->arch.gd_addr, 0xfffff);
|
||||
|
||||
/* 16-bit CS: code, read/execute, 64 kB, base 0 */
|
||||
gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x009b, 0, 0x0ffff);
|
||||
|
||||
/* 16-bit DS: data, read/write, 64 kB, base 0 */
|
||||
gdt_addr[X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x0093, 0, 0x0ffff);
|
||||
|
||||
gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_CS] = GDT_ENTRY(0x809b, 0, 0xfffff);
|
||||
gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_DS] = GDT_ENTRY(0x8093, 0, 0xfffff);
|
||||
|
||||
load_gdt(gdt_addr, X86_GDT_NUM_ENTRIES);
|
||||
load_ds(X86_GDT_ENTRY_32BIT_DS);
|
||||
load_es(X86_GDT_ENTRY_32BIT_DS);
|
||||
load_gs(X86_GDT_ENTRY_32BIT_DS);
|
||||
load_ss(X86_GDT_ENTRY_32BIT_DS);
|
||||
load_fs(X86_GDT_ENTRY_32BIT_FS);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_FSP
|
||||
/*
|
||||
* Setup FSP execution environment GDT
|
||||
*
|
||||
* Per Intel FSP external architecture specification, before calling any FSP
|
||||
* APIs, we need make sure the system is in flat 32-bit mode and both the code
|
||||
* and data selectors should have full 4GB access range. Here we reuse the one
|
||||
* we used in arch/x86/cpu/start16.S, and reload the segement registers.
|
||||
*/
|
||||
void setup_fsp_gdt(void)
|
||||
{
|
||||
load_gdt((const u64 *)(gdt_rom + CONFIG_RESET_SEG_START), 4);
|
||||
load_ds(X86_GDT_ENTRY_32BIT_DS);
|
||||
load_ss(X86_GDT_ENTRY_32BIT_DS);
|
||||
load_es(X86_GDT_ENTRY_32BIT_DS);
|
||||
load_fs(X86_GDT_ENTRY_32BIT_DS);
|
||||
load_gs(X86_GDT_ENTRY_32BIT_DS);
|
||||
}
|
||||
#endif
|
||||
|
||||
int __weak x86_cleanup_before_linux(void)
|
||||
{
|
||||
#ifdef CONFIG_BOOTSTAGE_STASH
|
||||
bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
|
||||
CONFIG_BOOTSTAGE_STASH_SIZE);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
|
||||
* by the fact that they preserve the flags across the division of 5/2.
|
||||
* PII and PPro exhibit this behavior too, but they have cpuid available.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Perform the Cyrix 5/2 test. A Cyrix won't change
|
||||
* the flags, while other 486 chips will.
|
||||
*/
|
||||
static inline int test_cyrix_52div(void)
|
||||
{
|
||||
unsigned int test;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"sahf\n\t" /* clear flags (%eax = 0x0005) */
|
||||
"div %b2\n\t" /* divide 5 by 2 */
|
||||
"lahf" /* store flags into %ah */
|
||||
: "=a" (test)
|
||||
: "0" (5), "q" (2)
|
||||
: "cc");
|
||||
|
||||
/* AH is 0x02 on Cyrix after the divide.. */
|
||||
return (unsigned char) (test >> 8) == 0x02;
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect a NexGen CPU running without BIOS hypercode new enough
|
||||
* to have CPUID. (Thanks to Herbert Oppmann)
|
||||
*/
|
||||
|
||||
static int deep_magic_nexgen_probe(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
" movw $0x5555, %%ax\n"
|
||||
" xorw %%dx,%%dx\n"
|
||||
" movw $2, %%cx\n"
|
||||
" divw %%cx\n"
|
||||
" movl $0, %%eax\n"
|
||||
" jnz 1f\n"
|
||||
" movl $1, %%eax\n"
|
||||
"1:\n"
|
||||
: "=a" (ret) : : "cx", "dx");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool has_cpuid(void)
|
||||
{
|
||||
return flag_is_changeable_p(X86_EFLAGS_ID);
|
||||
}
|
||||
|
||||
static bool has_mtrr(void)
|
||||
{
|
||||
return cpuid_edx(0x00000001) & (1 << 12) ? true : false;
|
||||
}
|
||||
|
||||
static int build_vendor_name(char *vendor_name)
|
||||
{
|
||||
struct cpuid_result result;
|
||||
result = cpuid(0x00000000);
|
||||
unsigned int *name_as_ints = (unsigned int *)vendor_name;
|
||||
|
||||
name_as_ints[0] = result.ebx;
|
||||
name_as_ints[1] = result.edx;
|
||||
name_as_ints[2] = result.ecx;
|
||||
|
||||
return result.eax;
|
||||
}
|
||||
|
||||
static void identify_cpu(struct cpu_device_id *cpu)
|
||||
{
|
||||
char vendor_name[16];
|
||||
int i;
|
||||
|
||||
vendor_name[0] = '\0'; /* Unset */
|
||||
cpu->device = 0; /* fix gcc 4.4.4 warning */
|
||||
|
||||
/* Find the id and vendor_name */
|
||||
if (!has_cpuid()) {
|
||||
/* Its a 486 if we can modify the AC flag */
|
||||
if (flag_is_changeable_p(X86_EFLAGS_AC))
|
||||
cpu->device = 0x00000400; /* 486 */
|
||||
else
|
||||
cpu->device = 0x00000300; /* 386 */
|
||||
if ((cpu->device == 0x00000400) && test_cyrix_52div()) {
|
||||
memcpy(vendor_name, "CyrixInstead", 13);
|
||||
/* If we ever care we can enable cpuid here */
|
||||
}
|
||||
/* Detect NexGen with old hypercode */
|
||||
else if (deep_magic_nexgen_probe())
|
||||
memcpy(vendor_name, "NexGenDriven", 13);
|
||||
}
|
||||
if (has_cpuid()) {
|
||||
int cpuid_level;
|
||||
|
||||
cpuid_level = build_vendor_name(vendor_name);
|
||||
vendor_name[12] = '\0';
|
||||
|
||||
/* Intel-defined flags: level 0x00000001 */
|
||||
if (cpuid_level >= 0x00000001) {
|
||||
cpu->device = cpuid_eax(0x00000001);
|
||||
} else {
|
||||
/* Have CPUID level 0 only unheard of */
|
||||
cpu->device = 0x00000400;
|
||||
}
|
||||
}
|
||||
cpu->vendor = X86_VENDOR_UNKNOWN;
|
||||
for (i = 0; i < ARRAY_SIZE(x86_vendors); i++) {
|
||||
if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) {
|
||||
cpu->vendor = x86_vendors[i].vendor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void get_fms(struct cpuinfo_x86 *c, uint32_t tfms)
|
||||
{
|
||||
c->x86 = (tfms >> 8) & 0xf;
|
||||
c->x86_model = (tfms >> 4) & 0xf;
|
||||
c->x86_mask = tfms & 0xf;
|
||||
if (c->x86 == 0xf)
|
||||
c->x86 += (tfms >> 20) & 0xff;
|
||||
if (c->x86 >= 0x6)
|
||||
c->x86_model += ((tfms >> 16) & 0xF) << 4;
|
||||
}
|
||||
|
||||
u32 cpu_get_family_model(void)
|
||||
{
|
||||
return gd->arch.x86_device & 0x0fff0ff0;
|
||||
}
|
||||
|
||||
u32 cpu_get_stepping(void)
|
||||
{
|
||||
return gd->arch.x86_mask;
|
||||
}
|
||||
|
||||
int x86_cpu_init_f(void)
|
||||
{
|
||||
const u32 em_rst = ~X86_CR0_EM;
|
||||
const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE;
|
||||
|
||||
if (ll_boot_init()) {
|
||||
/* initialize FPU, reset EM, set MP and NE */
|
||||
asm ("fninit\n" \
|
||||
"movl %%cr0, %%eax\n" \
|
||||
"andl %0, %%eax\n" \
|
||||
"orl %1, %%eax\n" \
|
||||
"movl %%eax, %%cr0\n" \
|
||||
: : "i" (em_rst), "i" (mp_ne_set) : "eax");
|
||||
}
|
||||
|
||||
/* identify CPU via cpuid and store the decoded info into gd->arch */
|
||||
if (has_cpuid()) {
|
||||
struct cpu_device_id cpu;
|
||||
struct cpuinfo_x86 c;
|
||||
|
||||
identify_cpu(&cpu);
|
||||
get_fms(&c, cpu.device);
|
||||
gd->arch.x86 = c.x86;
|
||||
gd->arch.x86_vendor = cpu.vendor;
|
||||
gd->arch.x86_model = c.x86_model;
|
||||
gd->arch.x86_mask = c.x86_mask;
|
||||
gd->arch.x86_device = cpu.device;
|
||||
|
||||
gd->arch.has_mtrr = has_mtrr();
|
||||
}
|
||||
/* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */
|
||||
gd->pci_ram_top = 0x80000000U;
|
||||
|
||||
/* Configure fixed range MTRRs for some legacy regions */
|
||||
if (gd->arch.has_mtrr) {
|
||||
u64 mtrr_cap;
|
||||
|
||||
mtrr_cap = native_read_msr(MTRR_CAP_MSR);
|
||||
if (mtrr_cap & MTRR_CAP_FIX) {
|
||||
/* Mark the VGA RAM area as uncacheable */
|
||||
native_write_msr(MTRR_FIX_16K_A0000_MSR,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE),
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE));
|
||||
|
||||
/*
|
||||
* Mark the PCI ROM area as cacheable to improve ROM
|
||||
* execution performance.
|
||||
*/
|
||||
native_write_msr(MTRR_FIX_4K_C0000_MSR,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
|
||||
native_write_msr(MTRR_FIX_4K_C8000_MSR,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
|
||||
native_write_msr(MTRR_FIX_4K_D0000_MSR,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
|
||||
native_write_msr(MTRR_FIX_4K_D8000_MSR,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
|
||||
|
||||
/* Enable the fixed range MTRRs */
|
||||
msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_I8254_TIMER
|
||||
/* Set up the i8254 timer if required */
|
||||
i8254_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void x86_enable_caches(void)
|
||||
{
|
||||
unsigned long cr0;
|
||||
|
||||
cr0 = read_cr0();
|
||||
cr0 &= ~(X86_CR0_NW | X86_CR0_CD);
|
||||
write_cr0(cr0);
|
||||
wbinvd();
|
||||
}
|
||||
void enable_caches(void) __attribute__((weak, alias("x86_enable_caches")));
|
||||
|
||||
void x86_disable_caches(void)
|
||||
{
|
||||
unsigned long cr0;
|
||||
|
||||
cr0 = read_cr0();
|
||||
cr0 |= X86_CR0_NW | X86_CR0_CD;
|
||||
wbinvd();
|
||||
write_cr0(cr0);
|
||||
wbinvd();
|
||||
}
|
||||
void disable_caches(void) __attribute__((weak, alias("x86_disable_caches")));
|
||||
|
||||
int x86_init_cache(void)
|
||||
{
|
||||
enable_caches();
|
||||
|
||||
return 0;
|
||||
}
|
||||
int init_cache(void) __attribute__((weak, alias("x86_init_cache")));
|
||||
|
||||
int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
printf("resetting ...\n");
|
||||
|
||||
/* wait 50 ms */
|
||||
udelay(50000);
|
||||
disable_interrupts();
|
||||
reset_cpu(0);
|
||||
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flush_cache(unsigned long dummy1, unsigned long dummy2)
|
||||
{
|
||||
asm("wbinvd\n");
|
||||
}
|
||||
|
||||
__weak void reset_cpu(ulong addr)
|
||||
{
|
||||
/* Do a hard reset through the chipset's reset control register */
|
||||
outb(SYS_RST | RST_CPU, IO_PORT_RESET);
|
||||
for (;;)
|
||||
cpu_hlt();
|
||||
}
|
||||
|
||||
void x86_full_reset(void)
|
||||
{
|
||||
outb(FULL_RST | SYS_RST | RST_CPU, IO_PORT_RESET);
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return !(read_cr0() & X86_CR0_CD);
|
||||
}
|
||||
|
||||
/* Define these functions to allow ehch-hcd to function */
|
||||
void flush_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
|
||||
void invalidate_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
|
||||
void dcache_enable(void)
|
||||
{
|
||||
enable_caches();
|
||||
}
|
||||
|
||||
void dcache_disable(void)
|
||||
{
|
||||
disable_caches();
|
||||
}
|
||||
|
||||
void icache_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
void icache_disable(void)
|
||||
{
|
||||
}
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cpu_enable_paging_pae(ulong cr3)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
/* Load the page table address */
|
||||
"movl %0, %%cr3\n"
|
||||
/* Enable pae */
|
||||
"movl %%cr4, %%eax\n"
|
||||
"orl $0x00000020, %%eax\n"
|
||||
"movl %%eax, %%cr4\n"
|
||||
/* Enable paging */
|
||||
"movl %%cr0, %%eax\n"
|
||||
"orl $0x80000000, %%eax\n"
|
||||
"movl %%eax, %%cr0\n"
|
||||
:
|
||||
: "r" (cr3)
|
||||
: "eax");
|
||||
}
|
||||
|
||||
void cpu_disable_paging_pae(void)
|
||||
{
|
||||
/* Turn off paging */
|
||||
__asm__ __volatile__ (
|
||||
/* Disable paging */
|
||||
"movl %%cr0, %%eax\n"
|
||||
"andl $0x7fffffff, %%eax\n"
|
||||
"movl %%eax, %%cr0\n"
|
||||
/* Disable pae */
|
||||
"movl %%cr4, %%eax\n"
|
||||
"andl $0xffffffdf, %%eax\n"
|
||||
"movl %%eax, %%cr4\n"
|
||||
:
|
||||
:
|
||||
: "eax");
|
||||
}
|
||||
|
||||
static bool can_detect_long_mode(void)
|
||||
{
|
||||
return cpuid_eax(0x80000000) > 0x80000000UL;
|
||||
}
|
||||
|
||||
static bool has_long_mode(void)
|
||||
{
|
||||
return cpuid_edx(0x80000001) & (1 << 29) ? true : false;
|
||||
}
|
||||
|
||||
int cpu_has_64bit(void)
|
||||
{
|
||||
return has_cpuid() && can_detect_long_mode() &&
|
||||
has_long_mode();
|
||||
}
|
||||
|
||||
const char *cpu_vendor_name(int vendor)
|
||||
{
|
||||
const char *name;
|
||||
name = "<invalid cpu vendor>";
|
||||
if ((vendor < (ARRAY_SIZE(x86_vendor_name))) &&
|
||||
(x86_vendor_name[vendor] != 0))
|
||||
name = x86_vendor_name[vendor];
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
char *cpu_get_name(char *name)
|
||||
{
|
||||
unsigned int *name_as_ints = (unsigned int *)name;
|
||||
struct cpuid_result regs;
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
/* This bit adds up to 48 bytes */
|
||||
for (i = 0; i < 3; i++) {
|
||||
regs = cpuid(0x80000002 + i);
|
||||
name_as_ints[i * 4 + 0] = regs.eax;
|
||||
name_as_ints[i * 4 + 1] = regs.ebx;
|
||||
name_as_ints[i * 4 + 2] = regs.ecx;
|
||||
name_as_ints[i * 4 + 3] = regs.edx;
|
||||
}
|
||||
name[CPU_MAX_NAME_LEN - 1] = '\0';
|
||||
|
||||
/* Skip leading spaces. */
|
||||
ptr = name;
|
||||
while (*ptr == ' ')
|
||||
ptr++;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int default_print_cpuinfo(void)
|
||||
{
|
||||
printf("CPU: %s, vendor %s, device %xh\n",
|
||||
cpu_has_64bit() ? "x86_64" : "x86",
|
||||
cpu_vendor_name(gd->arch.x86_vendor), gd->arch.x86_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PAGETABLE_SIZE (6 * 4096)
|
||||
|
||||
/**
|
||||
* build_pagetable() - build a flat 4GiB page table structure for 64-bti mode
|
||||
*
|
||||
* @pgtable: Pointer to a 24iKB block of memory
|
||||
*/
|
||||
static void build_pagetable(uint32_t *pgtable)
|
||||
{
|
||||
uint i;
|
||||
|
||||
memset(pgtable, '\0', PAGETABLE_SIZE);
|
||||
|
||||
/* Level 4 needs a single entry */
|
||||
pgtable[0] = (uint32_t)&pgtable[1024] + 7;
|
||||
|
||||
/* Level 3 has one 64-bit entry for each GiB of memory */
|
||||
for (i = 0; i < 4; i++) {
|
||||
pgtable[1024 + i * 2] = (uint32_t)&pgtable[2048] +
|
||||
0x1000 * i + 7;
|
||||
}
|
||||
|
||||
/* Level 2 has 2048 64-bit entries, each repesenting 2MiB */
|
||||
for (i = 0; i < 2048; i++)
|
||||
pgtable[2048 + i * 2] = 0x183 + (i << 21UL);
|
||||
}
|
||||
|
||||
int cpu_jump_to_64bit(ulong setup_base, ulong target)
|
||||
{
|
||||
uint32_t *pgtable;
|
||||
|
||||
pgtable = memalign(4096, PAGETABLE_SIZE);
|
||||
if (!pgtable)
|
||||
return -ENOMEM;
|
||||
|
||||
build_pagetable(pgtable);
|
||||
cpu_call64((ulong)pgtable, setup_base, target);
|
||||
free(pgtable);
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
void show_boot_progress(int val)
|
||||
{
|
||||
outb(val, POST_PORT);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SYS_COREBOOT
|
||||
/*
|
||||
* Implement a weak default function for boards that optionally
|
||||
* need to clean up the system before jumping to the kernel.
|
||||
*/
|
||||
__weak void board_final_cleanup(void)
|
||||
{
|
||||
}
|
||||
|
||||
int last_stage_init(void)
|
||||
{
|
||||
write_tables();
|
||||
|
||||
board_final_cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static int enable_smis(struct udevice *cpu, void *unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mp_flight_record mp_steps[] = {
|
||||
MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL),
|
||||
/* Wait for APs to finish initialization before proceeding */
|
||||
MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL),
|
||||
};
|
||||
|
||||
static int x86_mp_init(void)
|
||||
{
|
||||
struct mp_params mp_params;
|
||||
|
||||
mp_params.parallel_microcode_load = 0,
|
||||
mp_params.flight_plan = &mp_steps[0];
|
||||
mp_params.num_records = ARRAY_SIZE(mp_steps);
|
||||
mp_params.microcode_pointer = 0;
|
||||
|
||||
if (mp_init(&mp_params)) {
|
||||
printf("Warning: MP init failure\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int x86_init_cpus(void)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
debug("Init additional CPUs\n");
|
||||
x86_mp_init();
|
||||
#else
|
||||
struct udevice *dev;
|
||||
|
||||
/*
|
||||
* This causes the cpu-x86 driver to be probed.
|
||||
* We don't check return value here as we want to allow boards
|
||||
* which have not been converted to use cpu uclass driver to boot.
|
||||
*/
|
||||
uclass_first_device(UCLASS_CPU, &dev);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_init_r(void)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
if (!ll_boot_init())
|
||||
return 0;
|
||||
|
||||
ret = x86_init_cpus();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set up the northbridge, PCH and LPC if available. Note that these
|
||||
* may have had some limited pre-relocation init if they were probed
|
||||
* before relocation, but this is post relocation.
|
||||
*/
|
||||
uclass_first_device(UCLASS_NORTHBRIDGE, &dev);
|
||||
uclass_first_device(UCLASS_PCH, &dev);
|
||||
uclass_first_device(UCLASS_LPC, &dev);
|
||||
|
||||
/* Set up pin control if available */
|
||||
ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev);
|
||||
debug("%s, pinctrl=%p, ret=%d\n", __func__, dev, ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_EFI_STUB
|
||||
int reserve_arch(void)
|
||||
{
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
mrccache_reserve();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SEABIOS
|
||||
high_table_reserve();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
76
u-boot/arch/x86/cpu/cpu_x86.c
Normal file
76
u-boot/arch/x86/cpu/cpu_x86.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <asm/cpu.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int cpu_x86_bind(struct udevice *dev)
|
||||
{
|
||||
struct cpu_platdata *plat = dev_get_parent_platdata(dev);
|
||||
|
||||
plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
|
||||
"intel,apic-id", -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_x86_get_desc(struct udevice *dev, char *buf, int size)
|
||||
{
|
||||
if (size < CPU_MAX_NAME_LEN)
|
||||
return -ENOSPC;
|
||||
|
||||
cpu_get_name(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpu_x86_get_count(struct udevice *dev)
|
||||
{
|
||||
int node, cpu;
|
||||
int num = 0;
|
||||
|
||||
node = fdt_path_offset(gd->fdt_blob, "/cpus");
|
||||
if (node < 0)
|
||||
return -ENOENT;
|
||||
|
||||
for (cpu = fdt_first_subnode(gd->fdt_blob, node);
|
||||
cpu >= 0;
|
||||
cpu = fdt_next_subnode(gd->fdt_blob, cpu)) {
|
||||
const char *device_type;
|
||||
|
||||
device_type = fdt_getprop(gd->fdt_blob, cpu,
|
||||
"device_type", NULL);
|
||||
if (!device_type)
|
||||
continue;
|
||||
if (strcmp(device_type, "cpu") == 0)
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static const struct cpu_ops cpu_x86_ops = {
|
||||
.get_desc = cpu_x86_get_desc,
|
||||
.get_count = cpu_x86_get_count,
|
||||
};
|
||||
|
||||
static const struct udevice_id cpu_x86_ids[] = {
|
||||
{ .compatible = "cpu-x86" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(cpu_x86_drv) = {
|
||||
.name = "cpu_x86",
|
||||
.id = UCLASS_CPU,
|
||||
.of_match = cpu_x86_ids,
|
||||
.bind = cpu_x86_bind,
|
||||
.ops = &cpu_x86_ops,
|
||||
};
|
||||
8
u-boot/arch/x86/cpu/efi/Makefile
Normal file
8
u-boot/arch/x86/cpu/efi/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (c) 2015 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += efi.o
|
||||
obj-y += sdram.o
|
||||
38
u-boot/arch/x86/cpu/efi/efi.c
Normal file
38
u-boot/arch/x86/cpu/efi/efi.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fdtdec.h>
|
||||
#include <netdev.h>
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int board_early_init_f(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
return default_print_cpuinfo();
|
||||
}
|
||||
|
||||
void board_final_cleanup(void)
|
||||
{
|
||||
}
|
||||
|
||||
int misc_init_r(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_misc_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
94
u-boot/arch/x86/cpu/efi/elf_ia32_efi.lds
Normal file
94
u-boot/arch/x86/cpu/efi/elf_ia32_efi.lds
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* U-Boot EFI linker script
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Modified from usr/lib32/elf_ia32_efi.lds in gnu-efi
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
image_base = .;
|
||||
.hash : { *(.hash) } /* this MUST come first, EFI expects it */
|
||||
. = ALIGN(4096);
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
.sdata :
|
||||
{
|
||||
*(.got.plt)
|
||||
*(.got)
|
||||
*(.srodata)
|
||||
*(.sdata)
|
||||
*(.sbss)
|
||||
*(.scommon)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
.data :
|
||||
{
|
||||
*(.rodata*)
|
||||
*(.data)
|
||||
*(.data1)
|
||||
*(.data.*)
|
||||
*(.sdata)
|
||||
*(.got.plt)
|
||||
*(.got)
|
||||
/*
|
||||
* the EFI loader doesn't seem to like a .bss section, so we
|
||||
* stick it all into .data:
|
||||
*/
|
||||
*(.sbss)
|
||||
*(.scommon)
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
|
||||
/* U-Boot lists and device tree */
|
||||
. = ALIGN(8);
|
||||
*(SORT(.u_boot_list*));
|
||||
. = ALIGN(8);
|
||||
*(.dtb*);
|
||||
}
|
||||
|
||||
. = ALIGN(4096);
|
||||
.dynamic : { *(.dynamic) }
|
||||
. = ALIGN(4096);
|
||||
.rel :
|
||||
{
|
||||
*(.rel.data)
|
||||
*(.rel.data.*)
|
||||
*(.rel.got)
|
||||
*(.rel.stab)
|
||||
*(.data.rel.ro.local)
|
||||
*(.data.rel.local)
|
||||
*(.data.rel.ro)
|
||||
*(.data.rel*)
|
||||
*(.rel.u_boot_list*)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
.reloc : /* This is the PECOFF .reloc section! */
|
||||
{
|
||||
*(.reloc)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
.dynsym : { *(.dynsym) }
|
||||
. = ALIGN(4096);
|
||||
.dynstr : { *(.dynstr) }
|
||||
. = ALIGN(4096);
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.rel.reloc)
|
||||
*(.eh_frame)
|
||||
*(.note.GNU-stack)
|
||||
}
|
||||
.comment 0 : { *(.comment) }
|
||||
}
|
||||
83
u-boot/arch/x86/cpu/efi/elf_x86_64_efi.lds
Normal file
83
u-boot/arch/x86/cpu/efi/elf_x86_64_efi.lds
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* U-Boot EFI linker script
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Modified from usr/lib32/elf_x86_64_efi.lds in gnu-efi
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
|
||||
OUTPUT_ARCH(i386:x86-64)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
image_base = .;
|
||||
.hash : { *(.hash) } /* this MUST come first, EFI expects it */
|
||||
. = ALIGN(4096);
|
||||
.eh_frame : {
|
||||
*(.eh_frame)
|
||||
}
|
||||
|
||||
. = ALIGN(4096);
|
||||
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
}
|
||||
|
||||
. = ALIGN(4096);
|
||||
|
||||
.reloc : {
|
||||
*(.reloc)
|
||||
}
|
||||
|
||||
. = ALIGN(4096);
|
||||
|
||||
.data : {
|
||||
*(.rodata*)
|
||||
*(.got.plt)
|
||||
*(.got)
|
||||
*(.data*)
|
||||
*(.sdata)
|
||||
/* the EFI loader doesn't seem to like a .bss section, so we stick
|
||||
* it all into .data: */
|
||||
*(.sbss)
|
||||
*(.scommon)
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
*(.rel.local)
|
||||
|
||||
/* U-Boot lists and device tree */
|
||||
. = ALIGN(8);
|
||||
*(SORT(.u_boot_list*));
|
||||
. = ALIGN(8);
|
||||
*(.dtb*);
|
||||
}
|
||||
|
||||
. = ALIGN(4096);
|
||||
.dynamic : { *(.dynamic) }
|
||||
. = ALIGN(4096);
|
||||
|
||||
.rela : {
|
||||
*(.rela.data*)
|
||||
*(.rela.got)
|
||||
*(.rela.stab)
|
||||
}
|
||||
|
||||
. = ALIGN(4096);
|
||||
.dynsym : { *(.dynsym) }
|
||||
. = ALIGN(4096);
|
||||
.dynstr : { *(.dynstr) }
|
||||
. = ALIGN(4096);
|
||||
.ignored.reloc : {
|
||||
*(.rela.reloc)
|
||||
*(.eh_frame)
|
||||
*(.note.GNU-stack)
|
||||
}
|
||||
|
||||
.comment 0 : { *(.comment) }
|
||||
}
|
||||
29
u-boot/arch/x86/cpu/efi/sdram.c
Normal file
29
u-boot/arch/x86/cpu/efi/sdram.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <efi.h>
|
||||
#include <asm/u-boot-x86.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
ulong board_get_usable_ram_top(ulong total_size)
|
||||
{
|
||||
return (ulong)efi_get_ram_base() + gd->ram_size;
|
||||
}
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
/* gd->ram_size is set as part of EFI init */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dram_init_banksize(void)
|
||||
{
|
||||
gd->bd->bi_dram[0].start = efi_get_ram_base();
|
||||
gd->bd->bi_dram[0].size = CONFIG_EFI_RAM_SIZE;
|
||||
}
|
||||
16
u-boot/arch/x86/cpu/intel_common/Makefile
Normal file
16
u-boot/arch/x86/cpu/intel_common/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# Copyright (c) 2016 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-$(CONFIG_HAVE_MRC) += car.o
|
||||
obj-y += cpu.o
|
||||
obj-y += lpc.o
|
||||
obj-$(CONFIG_HAVE_MRC) += me_status.o
|
||||
ifndef CONFIG_TARGET_EFI
|
||||
obj-y += microcode.o
|
||||
endif
|
||||
obj-y += pch.o
|
||||
obj-$(CONFIG_HAVE_MRC) += report_platform.o
|
||||
obj-$(CONFIG_HAVE_MRC) += mrc.o
|
||||
243
u-boot/arch/x86/cpu/intel_common/car.S
Normal file
243
u-boot/arch/x86/cpu/intel_common/car.S
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Google, Inc
|
||||
*
|
||||
* From Coreboot file cpu/intel/model_206ax/cache_as_ram.inc
|
||||
*
|
||||
* Copyright (C) 2000,2007 Ronald G. Minnich <rminnich@gmail.com>
|
||||
* Copyright (C) 2005 Tyan (written by Yinghai Lu for Tyan)
|
||||
* Copyright (C) 2007-2008 coresystems GmbH
|
||||
* Copyright (C) 2012 Kyösti Mälkki <kyosti.malkki@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/msr-index.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/processor-flags.h>
|
||||
|
||||
#define MTRR_PHYS_BASE_MSR(reg) (0x200 + 2 * (reg))
|
||||
#define MTRR_PHYS_MASK_MSR(reg) (0x200 + 2 * (reg) + 1)
|
||||
|
||||
#define CACHE_AS_RAM_SIZE CONFIG_DCACHE_RAM_SIZE
|
||||
#define CACHE_AS_RAM_BASE CONFIG_DCACHE_RAM_BASE
|
||||
|
||||
/* Cache 4GB - MRC_SIZE_KB for MRC */
|
||||
#define CACHE_MRC_BYTES ((CONFIG_CACHE_MRC_SIZE_KB << 10) - 1)
|
||||
#define CACHE_MRC_BASE (0xFFFFFFFF - CACHE_MRC_BYTES)
|
||||
#define CACHE_MRC_MASK (~CACHE_MRC_BYTES)
|
||||
|
||||
#define CPU_PHYSMASK_HI (1 << (CONFIG_CPU_ADDR_BITS - 32) - 1)
|
||||
|
||||
#define NOEVICTMOD_MSR 0x2e0
|
||||
|
||||
/*
|
||||
* Note: ebp must not be touched in this code as it holds the BIST
|
||||
* value (built-in self test). We preserve this value until it can
|
||||
* be written to global_data when CAR is ready for use.
|
||||
*/
|
||||
.globl car_init
|
||||
car_init:
|
||||
post_code(POST_CAR_START)
|
||||
|
||||
/* Send INIT IPI to all excluding ourself */
|
||||
movl $0x000C4500, %eax
|
||||
movl $0xFEE00300, %esi
|
||||
movl %eax, (%esi)
|
||||
|
||||
/* TODO: Load microcode later - the 'no eviction' mode breaks this */
|
||||
movl $MSR_IA32_UCODE_WRITE, %ecx
|
||||
xorl %edx, %edx
|
||||
movl $_dt_ucode_base_size, %eax
|
||||
movl (%eax), %eax
|
||||
addl $UCODE_HEADER_LEN, %eax
|
||||
wrmsr
|
||||
|
||||
post_code(POST_CAR_SIPI)
|
||||
/* Zero out all fixed range and variable range MTRRs */
|
||||
movl $mtrr_table, %esi
|
||||
movl $((mtrr_table_end - mtrr_table) / 2), %edi
|
||||
xorl %eax, %eax
|
||||
xorl %edx, %edx
|
||||
clear_mtrrs:
|
||||
movw (%esi), %bx
|
||||
movzx %bx, %ecx
|
||||
wrmsr
|
||||
add $2, %esi
|
||||
dec %edi
|
||||
jnz clear_mtrrs
|
||||
|
||||
post_code(POST_CAR_MTRR)
|
||||
/* Configure the default memory type to uncacheable */
|
||||
movl $MTRR_DEF_TYPE_MSR, %ecx
|
||||
rdmsr
|
||||
andl $(~0x00000cff), %eax
|
||||
wrmsr
|
||||
|
||||
post_code(POST_CAR_UNCACHEABLE)
|
||||
/* Set Cache-as-RAM base address */
|
||||
movl $(MTRR_PHYS_BASE_MSR(0)), %ecx
|
||||
movl $(CACHE_AS_RAM_BASE | MTRR_TYPE_WRBACK), %eax
|
||||
xorl %edx, %edx
|
||||
wrmsr
|
||||
|
||||
post_code(POST_CAR_BASE_ADDRESS)
|
||||
/* Set Cache-as-RAM mask */
|
||||
movl $(MTRR_PHYS_MASK_MSR(0)), %ecx
|
||||
movl $(~(CACHE_AS_RAM_SIZE - 1) | MTRR_PHYS_MASK_VALID), %eax
|
||||
movl $CPU_PHYSMASK_HI, %edx
|
||||
wrmsr
|
||||
|
||||
post_code(POST_CAR_MASK)
|
||||
|
||||
/* Enable MTRR */
|
||||
movl $MTRR_DEF_TYPE_MSR, %ecx
|
||||
rdmsr
|
||||
orl $MTRR_DEF_TYPE_EN, %eax
|
||||
wrmsr
|
||||
|
||||
/* Enable cache (CR0.CD = 0, CR0.NW = 0) */
|
||||
movl %cr0, %eax
|
||||
andl $(~(X86_CR0_CD | X86_CR0_NW)), %eax
|
||||
invd
|
||||
movl %eax, %cr0
|
||||
|
||||
/* enable the 'no eviction' mode */
|
||||
movl $NOEVICTMOD_MSR, %ecx
|
||||
rdmsr
|
||||
orl $1, %eax
|
||||
andl $~2, %eax
|
||||
wrmsr
|
||||
|
||||
/* Clear the cache memory region. This will also fill up the cache */
|
||||
movl $CACHE_AS_RAM_BASE, %esi
|
||||
movl %esi, %edi
|
||||
movl $(CACHE_AS_RAM_SIZE / 4), %ecx
|
||||
xorl %eax, %eax
|
||||
rep stosl
|
||||
|
||||
/* enable the 'no eviction run' state */
|
||||
movl $NOEVICTMOD_MSR, %ecx
|
||||
rdmsr
|
||||
orl $3, %eax
|
||||
wrmsr
|
||||
|
||||
post_code(POST_CAR_FILL)
|
||||
/* Enable Cache-as-RAM mode by disabling cache */
|
||||
movl %cr0, %eax
|
||||
orl $X86_CR0_CD, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Enable cache for our code in Flash because we do XIP here */
|
||||
movl $MTRR_PHYS_BASE_MSR(1), %ecx
|
||||
xorl %edx, %edx
|
||||
movl $car_init_ret, %eax
|
||||
andl $(~(CONFIG_XIP_ROM_SIZE - 1)), %eax
|
||||
orl $MTRR_TYPE_WRPROT, %eax
|
||||
wrmsr
|
||||
|
||||
movl $MTRR_PHYS_MASK_MSR(1), %ecx
|
||||
movl $CPU_PHYSMASK_HI, %edx
|
||||
movl $(~(CONFIG_XIP_ROM_SIZE - 1) | MTRR_PHYS_MASK_VALID), %eax
|
||||
wrmsr
|
||||
|
||||
post_code(POST_CAR_ROM_CACHE)
|
||||
#ifdef CONFIG_CACHE_MRC_BIN
|
||||
/* Enable caching for ram init code to run faster */
|
||||
movl $MTRR_PHYS_BASE_MSR(2), %ecx
|
||||
movl $(CACHE_MRC_BASE | MTRR_TYPE_WRPROT), %eax
|
||||
xorl %edx, %edx
|
||||
wrmsr
|
||||
movl $MTRR_PHYS_MASK_MSR(2), %ecx
|
||||
movl $(CACHE_MRC_MASK | MTRR_PHYS_MASK_VALID), %eax
|
||||
movl $CPU_PHYSMASK_HI, %edx
|
||||
wrmsr
|
||||
#endif
|
||||
|
||||
post_code(POST_CAR_MRC_CACHE)
|
||||
/* Enable cache */
|
||||
movl %cr0, %eax
|
||||
andl $(~(X86_CR0_CD | X86_CR0_NW)), %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
post_code(POST_CAR_CPU_CACHE)
|
||||
|
||||
/* All CPUs need to be in Wait for SIPI state */
|
||||
wait_for_sipi:
|
||||
movl (%esi), %eax
|
||||
bt $12, %eax
|
||||
jc wait_for_sipi
|
||||
|
||||
/* return */
|
||||
jmp car_init_ret
|
||||
|
||||
.globl car_uninit
|
||||
car_uninit:
|
||||
/* Disable cache */
|
||||
movl %cr0, %eax
|
||||
orl $X86_CR0_CD, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Disable MTRRs */
|
||||
movl $MTRR_DEF_TYPE_MSR, %ecx
|
||||
rdmsr
|
||||
andl $(~MTRR_DEF_TYPE_EN), %eax
|
||||
wrmsr
|
||||
|
||||
/* Disable the no-eviction run state */
|
||||
movl $NOEVICTMOD_MSR, %ecx
|
||||
rdmsr
|
||||
andl $~2, %eax
|
||||
wrmsr
|
||||
|
||||
invd
|
||||
|
||||
/* Disable the no-eviction mode */
|
||||
rdmsr
|
||||
andl $~1, %eax
|
||||
wrmsr
|
||||
|
||||
#ifdef CONFIG_CACHE_MRC_BIN
|
||||
/* Clear the MTRR that was used to cache MRC */
|
||||
xorl %eax, %eax
|
||||
xorl %edx, %edx
|
||||
movl $MTRR_PHYS_BASE_MSR(2), %ecx
|
||||
wrmsr
|
||||
movl $MTRR_PHYS_MASK_MSR(2), %ecx
|
||||
wrmsr
|
||||
#endif
|
||||
|
||||
/* Enable MTRRs */
|
||||
movl $MTRR_DEF_TYPE_MSR, %ecx
|
||||
rdmsr
|
||||
orl $MTRR_DEF_TYPE_EN, %eax
|
||||
wrmsr
|
||||
|
||||
invd
|
||||
|
||||
ret
|
||||
|
||||
mtrr_table:
|
||||
/* Fixed MTRRs */
|
||||
.word 0x250, 0x258, 0x259
|
||||
.word 0x268, 0x269, 0x26A
|
||||
.word 0x26B, 0x26C, 0x26D
|
||||
.word 0x26E, 0x26F
|
||||
/* Variable MTRRs */
|
||||
.word 0x200, 0x201, 0x202, 0x203
|
||||
.word 0x204, 0x205, 0x206, 0x207
|
||||
.word 0x208, 0x209, 0x20A, 0x20B
|
||||
.word 0x20C, 0x20D, 0x20E, 0x20F
|
||||
.word 0x210, 0x211, 0x212, 0x213
|
||||
mtrr_table_end:
|
||||
|
||||
.align 4
|
||||
_dt_ucode_base_size:
|
||||
/* These next two fields are filled in by ifdtool */
|
||||
.globl ucode_base
|
||||
ucode_base: /* Declared in microcode.h */
|
||||
.long 0 /* microcode base */
|
||||
.long 0 /* microcode size */
|
||||
111
u-boot/arch/x86/cpu/intel_common/cpu.c
Normal file
111
u-boot/arch/x86/cpu/intel_common/cpu.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <asm/cpu_common.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/lapic.h>
|
||||
#include <asm/lpc_common.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/microcode.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static int report_bist_failure(void)
|
||||
{
|
||||
if (gd->arch.bist != 0) {
|
||||
post_code(POST_BIST_FAILURE);
|
||||
printf("BIST failed: %08x\n", gd->arch.bist);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_common_init(void)
|
||||
{
|
||||
struct udevice *dev, *lpc;
|
||||
int ret;
|
||||
|
||||
/* Halt if there was a built in self test failure */
|
||||
ret = report_bist_failure();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
enable_lapic();
|
||||
|
||||
ret = microcode_update_intel();
|
||||
if (ret && ret != -EEXIST)
|
||||
return ret;
|
||||
|
||||
/* Enable upper 128bytes of CMOS */
|
||||
writel(1 << 2, RCB_REG(RC));
|
||||
|
||||
/* Early chipset init required before RAM init can work */
|
||||
uclass_first_device(UCLASS_NORTHBRIDGE, &dev);
|
||||
|
||||
ret = uclass_first_device(UCLASS_LPC, &lpc);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!lpc)
|
||||
return -ENODEV;
|
||||
|
||||
/* Cause the SATA device to do its early init */
|
||||
uclass_first_device(UCLASS_AHCI, &dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_set_flex_ratio_to_tdp_nominal(void)
|
||||
{
|
||||
msr_t flex_ratio, msr;
|
||||
u8 nominal_ratio;
|
||||
|
||||
/* Check for Flex Ratio support */
|
||||
flex_ratio = msr_read(MSR_FLEX_RATIO);
|
||||
if (!(flex_ratio.lo & FLEX_RATIO_EN))
|
||||
return -EINVAL;
|
||||
|
||||
/* Check for >0 configurable TDPs */
|
||||
msr = msr_read(MSR_PLATFORM_INFO);
|
||||
if (((msr.hi >> 1) & 3) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Use nominal TDP ratio for flex ratio */
|
||||
msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
|
||||
nominal_ratio = msr.lo & 0xff;
|
||||
|
||||
/* See if flex ratio is already set to nominal TDP ratio */
|
||||
if (((flex_ratio.lo >> 8) & 0xff) == nominal_ratio)
|
||||
return 0;
|
||||
|
||||
/* Set flex ratio to nominal TDP ratio */
|
||||
flex_ratio.lo &= ~0xff00;
|
||||
flex_ratio.lo |= nominal_ratio << 8;
|
||||
flex_ratio.lo |= FLEX_RATIO_LOCK;
|
||||
msr_write(MSR_FLEX_RATIO, flex_ratio);
|
||||
|
||||
/* Set flex ratio in soft reset data register bits 11:6 */
|
||||
clrsetbits_le32(RCB_REG(SOFT_RESET_DATA), 0x3f << 6,
|
||||
(nominal_ratio & 0x3f) << 6);
|
||||
|
||||
debug("CPU: Soft reset to set up flex ratio\n");
|
||||
|
||||
/* Set soft reset control to use register value */
|
||||
setbits_le32(RCB_REG(SOFT_RESET_CTRL), 1);
|
||||
|
||||
/* Issue warm reset, will be "CPU only" due to soft reset data */
|
||||
outb(0x0, IO_PORT_RESET);
|
||||
outb(SYS_RST | RST_CPU, IO_PORT_RESET);
|
||||
cpu_hlt();
|
||||
|
||||
/* Not reached */
|
||||
return -EINVAL;
|
||||
}
|
||||
100
u-boot/arch/x86/cpu/intel_common/lpc.c
Normal file
100
u-boot/arch/x86/cpu/intel_common/lpc.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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/intel_regs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/lpc_common.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* Enable Prefetching and Caching */
|
||||
static void enable_spi_prefetch(struct udevice *pch)
|
||||
{
|
||||
u8 reg8;
|
||||
|
||||
dm_pci_read_config8(pch, 0xdc, ®8);
|
||||
reg8 &= ~(3 << 2);
|
||||
reg8 |= (2 << 2); /* Prefetching and Caching Enabled */
|
||||
dm_pci_write_config8(pch, 0xdc, reg8);
|
||||
}
|
||||
|
||||
static void enable_port80_on_lpc(struct udevice *pch)
|
||||
{
|
||||
/* Enable port 80 POST on LPC */
|
||||
dm_pci_write_config32(pch, PCH_RCBA_BASE, RCB_BASE_ADDRESS | 1);
|
||||
clrbits_le32(RCB_REG(GCS), 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* lpc_early_init() - set up LPC serial ports and other early things
|
||||
*
|
||||
* @dev: LPC device
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int lpc_common_early_init(struct udevice *dev)
|
||||
{
|
||||
struct udevice *pch = dev->parent;
|
||||
struct reg_info {
|
||||
u32 base;
|
||||
u32 size;
|
||||
} values[4], *ptr;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
count = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset,
|
||||
"intel,gen-dec", (u32 *)values,
|
||||
sizeof(values) / sizeof(u32));
|
||||
if (count < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Set COM1/COM2 decode range */
|
||||
dm_pci_write_config16(pch, LPC_IO_DEC, 0x0010);
|
||||
|
||||
/* Enable PS/2 Keyboard/Mouse, EC areas and COM1 */
|
||||
dm_pci_write_config16(pch, LPC_EN, KBC_LPC_EN | MC_LPC_EN |
|
||||
GAMEL_LPC_EN | COMA_LPC_EN);
|
||||
|
||||
/* Write all registers but use 0 if we run out of data */
|
||||
count = count * sizeof(u32) / sizeof(values[0]);
|
||||
for (i = 0, ptr = values; i < ARRAY_SIZE(values); i++, ptr++) {
|
||||
u32 reg = 0;
|
||||
|
||||
if (i < count)
|
||||
reg = ptr->base | PCI_COMMAND_IO | (ptr->size << 16);
|
||||
dm_pci_write_config32(pch, LPC_GENX_DEC(i), reg);
|
||||
}
|
||||
|
||||
enable_spi_prefetch(pch);
|
||||
|
||||
/* This is already done in start.S, but let's do it in C */
|
||||
enable_port80_on_lpc(pch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lpc_set_spi_protect(struct udevice *dev, int bios_ctrl, bool protect)
|
||||
{
|
||||
uint8_t bios_cntl;
|
||||
|
||||
/* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */
|
||||
dm_pci_read_config8(dev, bios_ctrl, &bios_cntl);
|
||||
if (protect) {
|
||||
bios_cntl &= ~BIOS_CTRL_BIOSWE;
|
||||
bios_cntl |= BIT(5);
|
||||
} else {
|
||||
bios_cntl |= BIOS_CTRL_BIOSWE;
|
||||
bios_cntl &= ~BIT(5);
|
||||
}
|
||||
dm_pci_write_config8(dev, bios_ctrl, bios_cntl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
213
u-boot/arch/x86/cpu/intel_common/me_status.c
Normal file
213
u-boot/arch/x86/cpu/intel_common/me_status.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* From Coreboot src/southbridge/intel/bd82x6x/me_status.c
|
||||
*
|
||||
* Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/me.h>
|
||||
|
||||
/* HFS1[3:0] Current Working State Values */
|
||||
static const char *const me_cws_values[] = {
|
||||
[ME_HFS_CWS_RESET] = "Reset",
|
||||
[ME_HFS_CWS_INIT] = "Initializing",
|
||||
[ME_HFS_CWS_REC] = "Recovery",
|
||||
[ME_HFS_CWS_NORMAL] = "Normal",
|
||||
[ME_HFS_CWS_WAIT] = "Platform Disable Wait",
|
||||
[ME_HFS_CWS_TRANS] = "OP State Transition",
|
||||
[ME_HFS_CWS_INVALID] = "Invalid CPU Plugged In"
|
||||
};
|
||||
|
||||
/* HFS1[8:6] Current Operation State Values */
|
||||
static const char *const me_opstate_values[] = {
|
||||
[ME_HFS_STATE_PREBOOT] = "Preboot",
|
||||
[ME_HFS_STATE_M0_UMA] = "M0 with UMA",
|
||||
[ME_HFS_STATE_M3] = "M3 without UMA",
|
||||
[ME_HFS_STATE_M0] = "M0 without UMA",
|
||||
[ME_HFS_STATE_BRINGUP] = "Bring up",
|
||||
[ME_HFS_STATE_ERROR] = "M0 without UMA but with error"
|
||||
};
|
||||
|
||||
/* HFS[19:16] Current Operation Mode Values */
|
||||
static const char *const me_opmode_values[] = {
|
||||
[ME_HFS_MODE_NORMAL] = "Normal",
|
||||
[ME_HFS_MODE_DEBUG] = "Debug",
|
||||
[ME_HFS_MODE_DIS] = "Soft Temporary Disable",
|
||||
[ME_HFS_MODE_OVER_JMPR] = "Security Override via Jumper",
|
||||
[ME_HFS_MODE_OVER_MEI] = "Security Override via MEI Message"
|
||||
};
|
||||
|
||||
/* HFS[15:12] Error Code Values */
|
||||
static const char *const me_error_values[] = {
|
||||
[ME_HFS_ERROR_NONE] = "No Error",
|
||||
[ME_HFS_ERROR_UNCAT] = "Uncategorized Failure",
|
||||
[ME_HFS_ERROR_IMAGE] = "Image Failure",
|
||||
[ME_HFS_ERROR_DEBUG] = "Debug Failure"
|
||||
};
|
||||
|
||||
/* GMES[31:28] ME Progress Code */
|
||||
static const char *const me_progress_values[] = {
|
||||
[ME_GMES_PHASE_ROM] = "ROM Phase",
|
||||
[ME_GMES_PHASE_BUP] = "BUP Phase",
|
||||
[ME_GMES_PHASE_UKERNEL] = "uKernel Phase",
|
||||
[ME_GMES_PHASE_POLICY] = "Policy Module",
|
||||
[ME_GMES_PHASE_MODULE] = "Module Loading",
|
||||
[ME_GMES_PHASE_UNKNOWN] = "Unknown",
|
||||
[ME_GMES_PHASE_HOST] = "Host Communication"
|
||||
};
|
||||
|
||||
/* GMES[27:24] Power Management Event */
|
||||
static const char *const me_pmevent_values[] = {
|
||||
[0x00] = "Clean Moff->Mx wake",
|
||||
[0x01] = "Moff->Mx wake after an error",
|
||||
[0x02] = "Clean global reset",
|
||||
[0x03] = "Global reset after an error",
|
||||
[0x04] = "Clean Intel ME reset",
|
||||
[0x05] = "Intel ME reset due to exception",
|
||||
[0x06] = "Pseudo-global reset",
|
||||
[0x07] = "S0/M0->Sx/M3",
|
||||
[0x08] = "Sx/M3->S0/M0",
|
||||
[0x09] = "Non-power cycle reset",
|
||||
[0x0a] = "Power cycle reset through M3",
|
||||
[0x0b] = "Power cycle reset through Moff",
|
||||
[0x0c] = "Sx/Mx->Sx/Moff"
|
||||
};
|
||||
|
||||
/* Progress Code 0 states */
|
||||
static const char *const me_progress_rom_values[] = {
|
||||
[0x00] = "BEGIN",
|
||||
[0x06] = "DISABLE"
|
||||
};
|
||||
|
||||
/* Progress Code 1 states */
|
||||
static const char *const me_progress_bup_values[] = {
|
||||
[0x00] = "Initialization starts",
|
||||
[0x01] = "Disable the host wake event",
|
||||
[0x04] = "Flow determination start process",
|
||||
[0x08] = "Error reading/matching the VSCC table in the descriptor",
|
||||
[0x0a] = "Check to see if straps say ME DISABLED",
|
||||
[0x0b] = "Timeout waiting for PWROK",
|
||||
[0x0d] = "Possibly handle BUP manufacturing override strap",
|
||||
[0x11] = "Bringup in M3",
|
||||
[0x12] = "Bringup in M0",
|
||||
[0x13] = "Flow detection error",
|
||||
[0x15] = "M3 clock switching error",
|
||||
[0x18] = "M3 kernel load",
|
||||
[0x1c] = "T34 missing - cannot program ICC",
|
||||
[0x1f] = "Waiting for DID BIOS message",
|
||||
[0x20] = "Waiting for DID BIOS message failure",
|
||||
[0x21] = "DID reported an error",
|
||||
[0x22] = "Enabling UMA",
|
||||
[0x23] = "Enabling UMA error",
|
||||
[0x24] = "Sending DID Ack to BIOS",
|
||||
[0x25] = "Sending DID Ack to BIOS error",
|
||||
[0x26] = "Switching clocks in M0",
|
||||
[0x27] = "Switching clocks in M0 error",
|
||||
[0x28] = "ME in temp disable",
|
||||
[0x32] = "M0 kernel load",
|
||||
};
|
||||
|
||||
/* Progress Code 3 states */
|
||||
static const char *const me_progress_policy_values[] = {
|
||||
[0x00] = "Entery into Policy Module",
|
||||
[0x03] = "Received S3 entry",
|
||||
[0x04] = "Received S4 entry",
|
||||
[0x05] = "Received S5 entry",
|
||||
[0x06] = "Received UPD entry",
|
||||
[0x07] = "Received PCR entry",
|
||||
[0x08] = "Received NPCR entry",
|
||||
[0x09] = "Received host wake",
|
||||
[0x0a] = "Received AC<>DC switch",
|
||||
[0x0b] = "Received DRAM Init Done",
|
||||
[0x0c] = "VSCC Data not found for flash device",
|
||||
[0x0d] = "VSCC Table is not valid",
|
||||
[0x0e] = "Flash Partition Boundary is outside address space",
|
||||
[0x0f] = "ME cannot access the chipset descriptor region",
|
||||
[0x10] = "Required VSCC values for flash parts do not match",
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* _intel_me_status() - Check Intel Management Engine status
|
||||
*
|
||||
* struct hfs: Firmware status
|
||||
* struct gmes: Management engine status
|
||||
*/
|
||||
static void _intel_me_status(struct me_hfs *hfs, struct me_gmes *gmes)
|
||||
{
|
||||
/* Check Current States */
|
||||
debug("ME: FW Partition Table : %s\n",
|
||||
hfs->fpt_bad ? "BAD" : "OK");
|
||||
debug("ME: Bringup Loader Failure : %s\n",
|
||||
hfs->ft_bup_ld_flr ? "YES" : "NO");
|
||||
debug("ME: Firmware Init Complete : %s\n",
|
||||
hfs->fw_init_complete ? "YES" : "NO");
|
||||
debug("ME: Manufacturing Mode : %s\n",
|
||||
hfs->mfg_mode ? "YES" : "NO");
|
||||
debug("ME: Boot Options Present : %s\n",
|
||||
hfs->boot_options_present ? "YES" : "NO");
|
||||
debug("ME: Update In Progress : %s\n",
|
||||
hfs->update_in_progress ? "YES" : "NO");
|
||||
debug("ME: Current Working State : %s\n",
|
||||
me_cws_values[hfs->working_state]);
|
||||
debug("ME: Current Operation State : %s\n",
|
||||
me_opstate_values[hfs->operation_state]);
|
||||
debug("ME: Current Operation Mode : %s\n",
|
||||
me_opmode_values[hfs->operation_mode]);
|
||||
debug("ME: Error Code : %s\n",
|
||||
me_error_values[hfs->error_code]);
|
||||
debug("ME: Progress Phase : %s\n",
|
||||
me_progress_values[gmes->progress_code]);
|
||||
debug("ME: Power Management Event : %s\n",
|
||||
me_pmevent_values[gmes->current_pmevent]);
|
||||
|
||||
debug("ME: Progress Phase State : ");
|
||||
switch (gmes->progress_code) {
|
||||
case ME_GMES_PHASE_ROM: /* ROM Phase */
|
||||
debug("%s", me_progress_rom_values[gmes->current_state]);
|
||||
break;
|
||||
|
||||
case ME_GMES_PHASE_BUP: /* Bringup Phase */
|
||||
if (gmes->current_state < ARRAY_SIZE(me_progress_bup_values) &&
|
||||
me_progress_bup_values[gmes->current_state])
|
||||
debug("%s",
|
||||
me_progress_bup_values[gmes->current_state]);
|
||||
else
|
||||
debug("0x%02x", gmes->current_state);
|
||||
break;
|
||||
|
||||
case ME_GMES_PHASE_POLICY: /* Policy Module Phase */
|
||||
if (gmes->current_state <
|
||||
ARRAY_SIZE(me_progress_policy_values) &&
|
||||
me_progress_policy_values[gmes->current_state])
|
||||
debug("%s",
|
||||
me_progress_policy_values[gmes->current_state]);
|
||||
else
|
||||
debug("0x%02x", gmes->current_state);
|
||||
break;
|
||||
|
||||
case ME_GMES_PHASE_HOST: /* Host Communication Phase */
|
||||
if (!gmes->current_state)
|
||||
debug("Host communication established");
|
||||
else
|
||||
debug("0x%02x", gmes->current_state);
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("Unknown 0x%02x", gmes->current_state);
|
||||
}
|
||||
debug("\n");
|
||||
}
|
||||
|
||||
void intel_me_status(struct udevice *me_dev)
|
||||
{
|
||||
struct me_hfs hfs;
|
||||
struct me_gmes gmes;
|
||||
|
||||
pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS);
|
||||
pci_read_dword_ptr(me_dev, &gmes, PCI_ME_GMES);
|
||||
|
||||
_intel_me_status(&hfs, &gmes);
|
||||
}
|
||||
173
u-boot/arch/x86/cpu/intel_common/microcode.c
Normal file
173
u-boot/arch/x86/cpu/intel_common/microcode.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Google, Inc
|
||||
* Copyright (C) 2000 Ronald G. Minnich
|
||||
*
|
||||
* Microcode update for Intel PIII and later CPUs
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <libfdt.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/msr-index.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/**
|
||||
* struct microcode_update - standard microcode header from Intel
|
||||
*
|
||||
* We read this information out of the device tree and use it to determine
|
||||
* whether the update is applicable or not. We also use the same structure
|
||||
* to read information from the CPU.
|
||||
*/
|
||||
struct microcode_update {
|
||||
uint header_version;
|
||||
uint update_revision;
|
||||
uint date_code;
|
||||
uint processor_signature;
|
||||
uint checksum;
|
||||
uint loader_revision;
|
||||
uint processor_flags;
|
||||
const void *data;
|
||||
int size;
|
||||
};
|
||||
|
||||
static int microcode_decode_node(const void *blob, int node,
|
||||
struct microcode_update *update)
|
||||
{
|
||||
update->data = fdt_getprop(blob, node, "data", &update->size);
|
||||
if (!update->data)
|
||||
return -EINVAL;
|
||||
update->data += UCODE_HEADER_LEN;
|
||||
update->size -= UCODE_HEADER_LEN;
|
||||
|
||||
update->header_version = fdtdec_get_int(blob, node,
|
||||
"intel,header-version", 0);
|
||||
update->update_revision = fdtdec_get_int(blob, node,
|
||||
"intel,update-revision", 0);
|
||||
update->date_code = fdtdec_get_int(blob, node,
|
||||
"intel,date-code", 0);
|
||||
update->processor_signature = fdtdec_get_int(blob, node,
|
||||
"intel,processor-signature", 0);
|
||||
update->checksum = fdtdec_get_int(blob, node, "intel,checksum", 0);
|
||||
update->loader_revision = fdtdec_get_int(blob, node,
|
||||
"intel,loader-revision", 0);
|
||||
update->processor_flags = fdtdec_get_int(blob, node,
|
||||
"intel,processor-flags", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int microcode_read_rev(void)
|
||||
{
|
||||
/* Quark does not have microcode MSRs */
|
||||
#ifdef CONFIG_INTEL_QUARK
|
||||
return 0;
|
||||
#else
|
||||
/*
|
||||
* Some Intel CPUs can be very finicky about the CPUID sequence used.
|
||||
* So this is implemented in assembly so that it works reliably.
|
||||
*/
|
||||
uint32_t low, high;
|
||||
|
||||
asm volatile (
|
||||
"xorl %%eax, %%eax\n"
|
||||
"xorl %%edx, %%edx\n"
|
||||
"movl %2, %%ecx\n"
|
||||
"wrmsr\n"
|
||||
"movl $0x01, %%eax\n"
|
||||
"cpuid\n"
|
||||
"movl %2, %%ecx\n"
|
||||
"rdmsr\n"
|
||||
: /* outputs */
|
||||
"=a" (low), "=d" (high)
|
||||
: /* inputs */
|
||||
"i" (MSR_IA32_UCODE_REV)
|
||||
: /* clobbers */
|
||||
"ebx", "ecx"
|
||||
);
|
||||
|
||||
return high;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void microcode_read_cpu(struct microcode_update *cpu)
|
||||
{
|
||||
/* CPUID sets MSR 0x8B iff a microcode update has been loaded. */
|
||||
unsigned int x86_model, x86_family;
|
||||
struct cpuid_result result;
|
||||
uint32_t low, high;
|
||||
|
||||
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
|
||||
result = cpuid(1);
|
||||
rdmsr(MSR_IA32_UCODE_REV, low, cpu->update_revision);
|
||||
x86_model = (result.eax >> 4) & 0x0f;
|
||||
x86_family = (result.eax >> 8) & 0x0f;
|
||||
cpu->processor_signature = result.eax;
|
||||
|
||||
cpu->processor_flags = 0;
|
||||
if ((x86_model >= 5) || (x86_family > 6)) {
|
||||
rdmsr(0x17, low, high);
|
||||
cpu->processor_flags = 1 << ((high >> 18) & 7);
|
||||
}
|
||||
debug("microcode: sig=%#x pf=%#x revision=%#x\n",
|
||||
cpu->processor_signature, cpu->processor_flags,
|
||||
cpu->update_revision);
|
||||
}
|
||||
|
||||
/* Get a microcode update from the device tree and apply it */
|
||||
int microcode_update_intel(void)
|
||||
{
|
||||
struct microcode_update cpu, update;
|
||||
const void *blob = gd->fdt_blob;
|
||||
int skipped;
|
||||
int count;
|
||||
int node;
|
||||
int ret;
|
||||
int rev;
|
||||
|
||||
microcode_read_cpu(&cpu);
|
||||
node = 0;
|
||||
count = 0;
|
||||
skipped = 0;
|
||||
do {
|
||||
node = fdtdec_next_compatible(blob, node,
|
||||
COMPAT_INTEL_MICROCODE);
|
||||
if (node < 0) {
|
||||
debug("%s: Found %d updates\n", __func__, count);
|
||||
return count ? 0 : skipped ? -EEXIST : -ENOENT;
|
||||
}
|
||||
|
||||
ret = microcode_decode_node(blob, node, &update);
|
||||
if (ret) {
|
||||
debug("%s: Unable to decode update: %d\n", __func__,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (!(update.processor_signature == cpu.processor_signature &&
|
||||
(update.processor_flags & cpu.processor_flags))) {
|
||||
debug("%s: Skipping non-matching update, sig=%x, pf=%x\n",
|
||||
__func__, update.processor_signature,
|
||||
update.processor_flags);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
wrmsr(MSR_IA32_UCODE_WRITE, (ulong)update.data, 0);
|
||||
rev = microcode_read_rev();
|
||||
debug("microcode: updated to revision 0x%x date=%04x-%02x-%02x\n",
|
||||
rev, update.date_code & 0xffff,
|
||||
(update.date_code >> 24) & 0xff,
|
||||
(update.date_code >> 16) & 0xff);
|
||||
if (update.update_revision != rev) {
|
||||
printf("Microcode update failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
count++;
|
||||
} while (1);
|
||||
}
|
||||
271
u-boot/arch/x86/cpu/intel_common/mrc.c
Normal file
271
u-boot/arch/x86/cpu/intel_common/mrc.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <syscon.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/mrc_common.h>
|
||||
#include <asm/pch_common.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/arch/me.h>
|
||||
#include <asm/report_platform.h>
|
||||
|
||||
static const char *const ecc_decoder[] = {
|
||||
"inactive",
|
||||
"active on IO",
|
||||
"disabled on IO",
|
||||
"active"
|
||||
};
|
||||
|
||||
ulong mrc_common_board_get_usable_ram_top(ulong total_size)
|
||||
{
|
||||
struct memory_info *info = &gd->arch.meminfo;
|
||||
uintptr_t dest_addr = 0;
|
||||
struct memory_area *largest = NULL;
|
||||
int i;
|
||||
|
||||
/* Find largest area of memory below 4GB */
|
||||
|
||||
for (i = 0; i < info->num_areas; i++) {
|
||||
struct memory_area *area = &info->area[i];
|
||||
|
||||
if (area->start >= 1ULL << 32)
|
||||
continue;
|
||||
if (!largest || area->size > largest->size)
|
||||
largest = area;
|
||||
}
|
||||
|
||||
/* If no suitable area was found, return an error. */
|
||||
assert(largest);
|
||||
if (!largest || largest->size < (2 << 20))
|
||||
panic("No available memory found for relocation");
|
||||
|
||||
dest_addr = largest->start + largest->size;
|
||||
|
||||
return (ulong)dest_addr;
|
||||
}
|
||||
|
||||
void mrc_common_dram_init_banksize(void)
|
||||
{
|
||||
struct memory_info *info = &gd->arch.meminfo;
|
||||
int num_banks;
|
||||
int i;
|
||||
|
||||
for (i = 0, num_banks = 0; i < info->num_areas; i++) {
|
||||
struct memory_area *area = &info->area[i];
|
||||
|
||||
if (area->start >= 1ULL << 32)
|
||||
continue;
|
||||
gd->bd->bi_dram[num_banks].start = area->start;
|
||||
gd->bd->bi_dram[num_banks].size = area->size;
|
||||
num_banks++;
|
||||
}
|
||||
}
|
||||
|
||||
int mrc_add_memory_area(struct memory_info *info, uint64_t start,
|
||||
uint64_t end)
|
||||
{
|
||||
struct memory_area *ptr;
|
||||
|
||||
if (info->num_areas == CONFIG_NR_DRAM_BANKS)
|
||||
return -ENOSPC;
|
||||
|
||||
ptr = &info->area[info->num_areas];
|
||||
ptr->start = start;
|
||||
ptr->size = end - start;
|
||||
info->total_memory += ptr->size;
|
||||
if (ptr->start < (1ULL << 32))
|
||||
info->total_32bit_memory += ptr->size;
|
||||
debug("%d: memory %llx size %llx, total now %llx / %llx\n",
|
||||
info->num_areas, ptr->start, ptr->size,
|
||||
info->total_32bit_memory, info->total_memory);
|
||||
info->num_areas++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump in the log memory controller configuration as read from the memory
|
||||
* controller registers.
|
||||
*/
|
||||
void report_memory_config(void)
|
||||
{
|
||||
u32 addr_decoder_common, addr_decode_ch[2];
|
||||
int i;
|
||||
|
||||
addr_decoder_common = readl(MCHBAR_REG(0x5000));
|
||||
addr_decode_ch[0] = readl(MCHBAR_REG(0x5004));
|
||||
addr_decode_ch[1] = readl(MCHBAR_REG(0x5008));
|
||||
|
||||
debug("memcfg DDR3 clock %d MHz\n",
|
||||
(readl(MCHBAR_REG(0x5e04)) * 13333 * 2 + 50) / 100);
|
||||
debug("memcfg channel assignment: A: %d, B % d, C % d\n",
|
||||
addr_decoder_common & 3,
|
||||
(addr_decoder_common >> 2) & 3,
|
||||
(addr_decoder_common >> 4) & 3);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(addr_decode_ch); i++) {
|
||||
u32 ch_conf = addr_decode_ch[i];
|
||||
debug("memcfg channel[%d] config (%8.8x):\n", i, ch_conf);
|
||||
debug(" ECC %s\n", ecc_decoder[(ch_conf >> 24) & 3]);
|
||||
debug(" enhanced interleave mode %s\n",
|
||||
((ch_conf >> 22) & 1) ? "on" : "off");
|
||||
debug(" rank interleave %s\n",
|
||||
((ch_conf >> 21) & 1) ? "on" : "off");
|
||||
debug(" DIMMA %d MB width x%d %s rank%s\n",
|
||||
((ch_conf >> 0) & 0xff) * 256,
|
||||
((ch_conf >> 19) & 1) ? 16 : 8,
|
||||
((ch_conf >> 17) & 1) ? "dual" : "single",
|
||||
((ch_conf >> 16) & 1) ? "" : ", selected");
|
||||
debug(" DIMMB %d MB width x%d %s rank%s\n",
|
||||
((ch_conf >> 8) & 0xff) * 256,
|
||||
((ch_conf >> 20) & 1) ? 16 : 8,
|
||||
((ch_conf >> 18) & 1) ? "dual" : "single",
|
||||
((ch_conf >> 16) & 1) ? ", selected" : "");
|
||||
}
|
||||
}
|
||||
|
||||
int mrc_locate_spd(struct udevice *dev, int size, const void **spd_datap)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
int spd_index;
|
||||
struct gpio_desc desc[4];
|
||||
int spd_node;
|
||||
int node;
|
||||
int ret;
|
||||
|
||||
ret = gpio_request_list_by_name(dev, "board-id-gpios", desc,
|
||||
ARRAY_SIZE(desc), GPIOD_IS_IN);
|
||||
if (ret < 0) {
|
||||
debug("%s: gpio ret=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
spd_index = dm_gpio_get_values_as_int(desc, ret);
|
||||
debug("spd index %d\n", spd_index);
|
||||
|
||||
node = fdt_first_subnode(blob, dev->of_offset);
|
||||
if (node < 0)
|
||||
return -EINVAL;
|
||||
for (spd_node = fdt_first_subnode(blob, node);
|
||||
spd_node > 0;
|
||||
spd_node = fdt_next_subnode(blob, spd_node)) {
|
||||
int len;
|
||||
|
||||
if (fdtdec_get_int(blob, spd_node, "reg", -1) != spd_index)
|
||||
continue;
|
||||
*spd_datap = fdt_getprop(blob, spd_node, "data", &len);
|
||||
if (len < size) {
|
||||
printf("Missing SPD data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debug("Using SDRAM SPD data for '%s'\n",
|
||||
fdt_get_name(blob, spd_node, NULL));
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("No SPD data found for index %d\n", spd_index);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
asmlinkage void sdram_console_tx_byte(unsigned char byte)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
putc(byte);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the PEI executable in the ROM and execute it.
|
||||
*
|
||||
* @me_dev: Management Engine device
|
||||
* @pei_data: configuration data for UEFI PEI reference code
|
||||
*/
|
||||
static int sdram_initialise(struct udevice *dev, struct udevice *me_dev,
|
||||
void *pei_data, bool use_asm_linkage)
|
||||
{
|
||||
unsigned version;
|
||||
const char *data;
|
||||
|
||||
report_platform_info(dev);
|
||||
debug("Starting UEFI PEI System Agent\n");
|
||||
|
||||
debug("PEI data at %p:\n", pei_data);
|
||||
|
||||
data = (char *)CONFIG_X86_MRC_ADDR;
|
||||
if (data) {
|
||||
int rv;
|
||||
ulong start;
|
||||
|
||||
debug("Calling MRC at %p\n", data);
|
||||
post_code(POST_PRE_MRC);
|
||||
start = get_timer(0);
|
||||
if (use_asm_linkage) {
|
||||
asmlinkage int (*func)(void *);
|
||||
|
||||
func = (asmlinkage int (*)(void *))data;
|
||||
rv = func(pei_data);
|
||||
} else {
|
||||
int (*func)(void *);
|
||||
|
||||
func = (int (*)(void *))data;
|
||||
rv = func(pei_data);
|
||||
}
|
||||
post_code(POST_MRC);
|
||||
if (rv) {
|
||||
switch (rv) {
|
||||
case -1:
|
||||
printf("PEI version mismatch.\n");
|
||||
break;
|
||||
case -2:
|
||||
printf("Invalid memory frequency.\n");
|
||||
break;
|
||||
default:
|
||||
printf("MRC returned %x.\n", rv);
|
||||
}
|
||||
printf("Nonzero MRC return value.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
debug("MRC execution time %lu ms\n", get_timer(start));
|
||||
} else {
|
||||
printf("UEFI PEI System Agent not found.\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
version = readl(MCHBAR_REG(MCHBAR_PEI_VERSION));
|
||||
debug("System Agent Version %d.%d.%d Build %d\n",
|
||||
version >> 24 , (version >> 16) & 0xff,
|
||||
(version >> 8) & 0xff, version & 0xff);
|
||||
|
||||
#if CONFIG_USBDEBUG
|
||||
/* mrc.bin reconfigures USB, so reinit it to have debug */
|
||||
early_usbdebug_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mrc_common_init(struct udevice *dev, void *pei_data, bool use_asm_linkage)
|
||||
{
|
||||
struct udevice *me_dev;
|
||||
int ret;
|
||||
|
||||
ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sdram_initialise(dev, me_dev, pei_data, use_asm_linkage);
|
||||
if (ret)
|
||||
return ret;
|
||||
quick_ram_check();
|
||||
post_code(POST_DRAM);
|
||||
report_memory_config();
|
||||
|
||||
return 0;
|
||||
}
|
||||
25
u-boot/arch/x86/cpu/intel_common/pch.c
Normal file
25
u-boot/arch/x86/cpu/intel_common/pch.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/pch_common.h>
|
||||
|
||||
u32 pch_common_sir_read(struct udevice *dev, int idx)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
dm_pci_write_config32(dev, SATA_SIRI, idx);
|
||||
dm_pci_read_config32(dev, SATA_SIRD, &data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void pch_common_sir_write(struct udevice *dev, int idx, u32 value)
|
||||
{
|
||||
dm_pci_write_config32(dev, SATA_SIRI, idx);
|
||||
dm_pci_write_config32(dev, SATA_SIRD, value);
|
||||
}
|
||||
90
u-boot/arch/x86/cpu/intel_common/report_platform.c
Normal file
90
u-boot/arch/x86/cpu/intel_common/report_platform.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* From Coreboot src/northbridge/intel/sandybridge/report_platform.c
|
||||
*
|
||||
* Copyright (C) 2012 Google Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/report_platform.h>
|
||||
#include <asm/arch/pch.h>
|
||||
|
||||
static void report_cpu_info(void)
|
||||
{
|
||||
char cpu_string[CPU_MAX_NAME_LEN], *cpu_name;
|
||||
const char *mode[] = {"NOT ", ""};
|
||||
struct cpuid_result cpuidr;
|
||||
int vt, txt, aes;
|
||||
u32 index;
|
||||
|
||||
index = 0x80000000;
|
||||
cpuidr = cpuid(index);
|
||||
if (cpuidr.eax < 0x80000004) {
|
||||
strcpy(cpu_string, "Platform info not available");
|
||||
cpu_name = cpu_string;
|
||||
} else {
|
||||
cpu_name = cpu_get_name(cpu_string);
|
||||
}
|
||||
|
||||
cpuidr = cpuid(1);
|
||||
debug("CPU id(%x): %s\n", cpuidr.eax, cpu_name);
|
||||
aes = (cpuidr.ecx & (1 << 25)) ? 1 : 0;
|
||||
txt = (cpuidr.ecx & (1 << 6)) ? 1 : 0;
|
||||
vt = (cpuidr.ecx & (1 << 5)) ? 1 : 0;
|
||||
debug("AES %ssupported, TXT %ssupported, VT %ssupported\n",
|
||||
mode[aes], mode[txt], mode[vt]);
|
||||
}
|
||||
|
||||
/* The PCI id name match comes from Intel document 472178 */
|
||||
static struct {
|
||||
u16 dev_id;
|
||||
const char *dev_name;
|
||||
} pch_table[] = {
|
||||
{0x1E41, "Desktop Sample"},
|
||||
{0x1E42, "Mobile Sample"},
|
||||
{0x1E43, "SFF Sample"},
|
||||
{0x1E44, "Z77"},
|
||||
{0x1E45, "H71"},
|
||||
{0x1E46, "Z75"},
|
||||
{0x1E47, "Q77"},
|
||||
{0x1E48, "Q75"},
|
||||
{0x1E49, "B75"},
|
||||
{0x1E4A, "H77"},
|
||||
{0x1E53, "C216"},
|
||||
{0x1E55, "QM77"},
|
||||
{0x1E56, "QS77"},
|
||||
{0x1E58, "UM77"},
|
||||
{0x1E57, "HM77"},
|
||||
{0x1E59, "HM76"},
|
||||
{0x1E5D, "HM75"},
|
||||
{0x1E5E, "HM70"},
|
||||
{0x1E5F, "NM70"},
|
||||
};
|
||||
|
||||
static void report_pch_info(struct udevice *dev)
|
||||
{
|
||||
const char *pch_type = "Unknown";
|
||||
int i;
|
||||
u16 dev_id;
|
||||
uint8_t rev_id;
|
||||
|
||||
dm_pci_read_config16(dev, 2, &dev_id);
|
||||
for (i = 0; i < ARRAY_SIZE(pch_table); i++) {
|
||||
if (pch_table[i].dev_id == dev_id) {
|
||||
pch_type = pch_table[i].dev_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dm_pci_read_config8(dev, 8, &rev_id);
|
||||
debug("PCH type: %s, device id: %x, rev id %x\n", pch_type, dev_id,
|
||||
rev_id);
|
||||
}
|
||||
|
||||
void report_platform_info(struct udevice *dev)
|
||||
{
|
||||
report_cpu_info();
|
||||
report_pch_info(dev);
|
||||
}
|
||||
616
u-boot/arch/x86/cpu/interrupts.c
Normal file
616
u-boot/arch/x86/cpu/interrupts.c
Normal file
@@ -0,0 +1,616 @@
|
||||
/*
|
||||
* (C) Copyright 2008-2011
|
||||
* Graeme Russ, <graeme.russ@gmail.com>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
|
||||
*
|
||||
* Portions of this file are derived from the Linux kernel source
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/control_regs.h>
|
||||
#include <asm/i8259.h>
|
||||
#include <asm/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/lapic.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/u-boot-x86.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define DECLARE_INTERRUPT(x) \
|
||||
".globl irq_"#x"\n" \
|
||||
".hidden irq_"#x"\n" \
|
||||
".type irq_"#x", @function\n" \
|
||||
"irq_"#x":\n" \
|
||||
"pushl $"#x"\n" \
|
||||
"jmp irq_common_entry\n"
|
||||
|
||||
static char *exceptions[] = {
|
||||
"Divide Error",
|
||||
"Debug",
|
||||
"NMI Interrupt",
|
||||
"Breakpoint",
|
||||
"Overflow",
|
||||
"BOUND Range Exceeded",
|
||||
"Invalid Opcode (Undefined Opcode)",
|
||||
"Device Not Avaiable (No Math Coprocessor)",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Invalid TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Segment Fault",
|
||||
"General Protection",
|
||||
"Page Fault",
|
||||
"Reserved",
|
||||
"x87 FPU Floating-Point Error",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"SIMD Floating-Point Exception",
|
||||
"Virtualization Exception",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
static void dump_regs(struct irq_regs *regs)
|
||||
{
|
||||
unsigned long cs, eip, eflags;
|
||||
unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
|
||||
unsigned long d0, d1, d2, d3, d6, d7;
|
||||
unsigned long sp;
|
||||
|
||||
/*
|
||||
* Some exceptions cause an error code to be saved on the current stack
|
||||
* after the EIP value. We should extract CS/EIP/EFLAGS from different
|
||||
* position on the stack based on the exception number.
|
||||
*/
|
||||
switch (regs->irq_id) {
|
||||
case EXC_DF:
|
||||
case EXC_TS:
|
||||
case EXC_NP:
|
||||
case EXC_SS:
|
||||
case EXC_GP:
|
||||
case EXC_PF:
|
||||
case EXC_AC:
|
||||
cs = regs->context.ctx2.xcs;
|
||||
eip = regs->context.ctx2.eip;
|
||||
eflags = regs->context.ctx2.eflags;
|
||||
/* We should fix up the ESP due to error code */
|
||||
regs->esp += 4;
|
||||
break;
|
||||
default:
|
||||
cs = regs->context.ctx1.xcs;
|
||||
eip = regs->context.ctx1.eip;
|
||||
eflags = regs->context.ctx1.eflags;
|
||||
break;
|
||||
}
|
||||
|
||||
printf("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n",
|
||||
(u16)cs, eip, eflags);
|
||||
if (gd->flags & GD_FLG_RELOC)
|
||||
printf("Original EIP :[<%08lx>]\n", eip - gd->reloc_off);
|
||||
|
||||
printf("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
|
||||
regs->eax, regs->ebx, regs->ecx, regs->edx);
|
||||
printf("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n",
|
||||
regs->esi, regs->edi, regs->ebp, regs->esp);
|
||||
printf(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n",
|
||||
(u16)regs->xds, (u16)regs->xes, (u16)regs->xfs,
|
||||
(u16)regs->xgs, (u16)regs->xss);
|
||||
|
||||
cr0 = read_cr0();
|
||||
cr2 = read_cr2();
|
||||
cr3 = read_cr3();
|
||||
cr4 = read_cr4();
|
||||
|
||||
printf("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n",
|
||||
cr0, cr2, cr3, cr4);
|
||||
|
||||
d0 = get_debugreg(0);
|
||||
d1 = get_debugreg(1);
|
||||
d2 = get_debugreg(2);
|
||||
d3 = get_debugreg(3);
|
||||
|
||||
printf("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
|
||||
d0, d1, d2, d3);
|
||||
|
||||
d6 = get_debugreg(6);
|
||||
d7 = get_debugreg(7);
|
||||
printf("DR6: %08lx DR7: %08lx\n",
|
||||
d6, d7);
|
||||
|
||||
printf("Stack:\n");
|
||||
sp = regs->esp;
|
||||
|
||||
sp += 64;
|
||||
|
||||
while (sp > (regs->esp - 16)) {
|
||||
if (sp == regs->esp)
|
||||
printf("--->");
|
||||
else
|
||||
printf(" ");
|
||||
printf("0x%8.8lx : 0x%8.8lx\n", sp, (ulong)readl(sp));
|
||||
sp -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_exception(struct irq_regs *regs)
|
||||
{
|
||||
printf("%s\n", exceptions[regs->irq_id]);
|
||||
dump_regs(regs);
|
||||
hang();
|
||||
}
|
||||
|
||||
struct idt_entry {
|
||||
u16 base_low;
|
||||
u16 selector;
|
||||
u8 res;
|
||||
u8 access;
|
||||
u16 base_high;
|
||||
} __packed;
|
||||
|
||||
struct desc_ptr {
|
||||
unsigned short size;
|
||||
unsigned long address;
|
||||
} __packed;
|
||||
|
||||
struct idt_entry idt[256] __aligned(16);
|
||||
|
||||
struct desc_ptr idt_ptr;
|
||||
|
||||
static inline void load_idt(const struct desc_ptr *dtr)
|
||||
{
|
||||
asm volatile("cs lidt %0" : : "m" (*dtr));
|
||||
}
|
||||
|
||||
void set_vector(u8 intnum, void *routine)
|
||||
{
|
||||
idt[intnum].base_high = (u16)((u32)(routine) >> 16);
|
||||
idt[intnum].base_low = (u16)((u32)(routine) & 0xffff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally these would be defined static to avoid a checkpatch warning, but
|
||||
* the compiler cannot see them in the inline asm and complains that they
|
||||
* aren't defined
|
||||
*/
|
||||
void irq_0(void);
|
||||
void irq_1(void);
|
||||
|
||||
int cpu_init_interrupts(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
int irq_entry_size = irq_1 - irq_0;
|
||||
void *irq_entry = (void *)irq_0;
|
||||
|
||||
/* Setup the IDT */
|
||||
for (i = 0; i < 256; i++) {
|
||||
idt[i].access = 0x8e;
|
||||
idt[i].res = 0;
|
||||
idt[i].selector = X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE;
|
||||
set_vector(i, irq_entry);
|
||||
irq_entry += irq_entry_size;
|
||||
}
|
||||
|
||||
idt_ptr.size = 256 * 8 - 1;
|
||||
idt_ptr.address = (unsigned long) idt;
|
||||
|
||||
load_idt(&idt_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *x86_get_idt(void)
|
||||
{
|
||||
return &idt_ptr;
|
||||
}
|
||||
|
||||
void __do_irq(int irq)
|
||||
{
|
||||
printf("Unhandled IRQ : %d\n", irq);
|
||||
}
|
||||
void do_irq(int irq) __attribute__((weak, alias("__do_irq")));
|
||||
|
||||
void enable_interrupts(void)
|
||||
{
|
||||
asm("sti\n");
|
||||
}
|
||||
|
||||
int disable_interrupts(void)
|
||||
{
|
||||
long flags;
|
||||
|
||||
asm volatile ("pushfl ; popl %0 ; cli\n" : "=g" (flags) : );
|
||||
|
||||
return flags & X86_EFLAGS_IF;
|
||||
}
|
||||
|
||||
int interrupt_init(void)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
/* Try to set up the interrupt router, but don't require one */
|
||||
ret = uclass_first_device_err(UCLASS_IRQ, &dev);
|
||||
if (ret && ret != -ENODEV)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* When running as an EFI application we are not in control of
|
||||
* interrupts and should leave them alone.
|
||||
*/
|
||||
#ifndef CONFIG_EFI_APP
|
||||
/* Just in case... */
|
||||
disable_interrupts();
|
||||
|
||||
#ifdef CONFIG_I8259_PIC
|
||||
/* Initialize the master/slave i8259 pic */
|
||||
i8259_init();
|
||||
#endif
|
||||
|
||||
lapic_setup();
|
||||
|
||||
/* Initialize core interrupt and exception functionality of CPU */
|
||||
cpu_init_interrupts();
|
||||
|
||||
/*
|
||||
* It is now safe to enable interrupts.
|
||||
*
|
||||
* TODO(sjg@chromium.org): But we don't handle these correctly when
|
||||
* booted from EFI.
|
||||
*/
|
||||
if (ll_boot_init())
|
||||
enable_interrupts();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* IRQ Low-Level Service Routine */
|
||||
void irq_llsr(struct irq_regs *regs)
|
||||
{
|
||||
/*
|
||||
* For detailed description of each exception, refer to:
|
||||
* Intel® 64 and IA-32 Architectures Software Developer's Manual
|
||||
* Volume 1: Basic Architecture
|
||||
* Order Number: 253665-029US, November 2008
|
||||
* Table 6-1. Exceptions and Interrupts
|
||||
*/
|
||||
if (regs->irq_id < 32) {
|
||||
/* Architecture defined exception */
|
||||
do_exception(regs);
|
||||
} else {
|
||||
/* Hardware or User IRQ */
|
||||
do_irq(regs->irq_id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OK - This looks really horrible, but it serves a purpose - It helps create
|
||||
* fully relocatable code.
|
||||
* - The call to irq_llsr will be a relative jump
|
||||
* - The IRQ entries will be guaranteed to be in order
|
||||
* Interrupt entries are now very small (a push and a jump) but they are
|
||||
* now slower (all registers pushed on stack which provides complete
|
||||
* crash dumps in the low level handlers
|
||||
*
|
||||
* Interrupt Entry Point:
|
||||
* - Interrupt has caused eflags, CS and EIP to be pushed
|
||||
* - Interrupt Vector Handler has pushed orig_eax
|
||||
* - pt_regs.esp needs to be adjusted by 40 bytes:
|
||||
* 12 bytes pushed by CPU (EFLAGSF, CS, EIP)
|
||||
* 4 bytes pushed by vector handler (irq_id)
|
||||
* 24 bytes pushed before SP (SS, GS, FS, ES, DS, EAX)
|
||||
* NOTE: Only longs are pushed on/popped off the stack!
|
||||
*/
|
||||
asm(".globl irq_common_entry\n" \
|
||||
".hidden irq_common_entry\n" \
|
||||
".type irq_common_entry, @function\n" \
|
||||
"irq_common_entry:\n" \
|
||||
"cld\n" \
|
||||
"pushl %ss\n" \
|
||||
"pushl %gs\n" \
|
||||
"pushl %fs\n" \
|
||||
"pushl %es\n" \
|
||||
"pushl %ds\n" \
|
||||
"pushl %eax\n" \
|
||||
"movl %esp, %eax\n" \
|
||||
"addl $40, %eax\n" \
|
||||
"pushl %eax\n" \
|
||||
"pushl %ebp\n" \
|
||||
"pushl %edi\n" \
|
||||
"pushl %esi\n" \
|
||||
"pushl %edx\n" \
|
||||
"pushl %ecx\n" \
|
||||
"pushl %ebx\n" \
|
||||
"mov %esp, %eax\n" \
|
||||
"call irq_llsr\n" \
|
||||
"popl %ebx\n" \
|
||||
"popl %ecx\n" \
|
||||
"popl %edx\n" \
|
||||
"popl %esi\n" \
|
||||
"popl %edi\n" \
|
||||
"popl %ebp\n" \
|
||||
"popl %eax\n" \
|
||||
"popl %eax\n" \
|
||||
"popl %ds\n" \
|
||||
"popl %es\n" \
|
||||
"popl %fs\n" \
|
||||
"popl %gs\n" \
|
||||
"popl %ss\n" \
|
||||
"add $4, %esp\n" \
|
||||
"iret\n" \
|
||||
DECLARE_INTERRUPT(0) \
|
||||
DECLARE_INTERRUPT(1) \
|
||||
DECLARE_INTERRUPT(2) \
|
||||
DECLARE_INTERRUPT(3) \
|
||||
DECLARE_INTERRUPT(4) \
|
||||
DECLARE_INTERRUPT(5) \
|
||||
DECLARE_INTERRUPT(6) \
|
||||
DECLARE_INTERRUPT(7) \
|
||||
DECLARE_INTERRUPT(8) \
|
||||
DECLARE_INTERRUPT(9) \
|
||||
DECLARE_INTERRUPT(10) \
|
||||
DECLARE_INTERRUPT(11) \
|
||||
DECLARE_INTERRUPT(12) \
|
||||
DECLARE_INTERRUPT(13) \
|
||||
DECLARE_INTERRUPT(14) \
|
||||
DECLARE_INTERRUPT(15) \
|
||||
DECLARE_INTERRUPT(16) \
|
||||
DECLARE_INTERRUPT(17) \
|
||||
DECLARE_INTERRUPT(18) \
|
||||
DECLARE_INTERRUPT(19) \
|
||||
DECLARE_INTERRUPT(20) \
|
||||
DECLARE_INTERRUPT(21) \
|
||||
DECLARE_INTERRUPT(22) \
|
||||
DECLARE_INTERRUPT(23) \
|
||||
DECLARE_INTERRUPT(24) \
|
||||
DECLARE_INTERRUPT(25) \
|
||||
DECLARE_INTERRUPT(26) \
|
||||
DECLARE_INTERRUPT(27) \
|
||||
DECLARE_INTERRUPT(28) \
|
||||
DECLARE_INTERRUPT(29) \
|
||||
DECLARE_INTERRUPT(30) \
|
||||
DECLARE_INTERRUPT(31) \
|
||||
DECLARE_INTERRUPT(32) \
|
||||
DECLARE_INTERRUPT(33) \
|
||||
DECLARE_INTERRUPT(34) \
|
||||
DECLARE_INTERRUPT(35) \
|
||||
DECLARE_INTERRUPT(36) \
|
||||
DECLARE_INTERRUPT(37) \
|
||||
DECLARE_INTERRUPT(38) \
|
||||
DECLARE_INTERRUPT(39) \
|
||||
DECLARE_INTERRUPT(40) \
|
||||
DECLARE_INTERRUPT(41) \
|
||||
DECLARE_INTERRUPT(42) \
|
||||
DECLARE_INTERRUPT(43) \
|
||||
DECLARE_INTERRUPT(44) \
|
||||
DECLARE_INTERRUPT(45) \
|
||||
DECLARE_INTERRUPT(46) \
|
||||
DECLARE_INTERRUPT(47) \
|
||||
DECLARE_INTERRUPT(48) \
|
||||
DECLARE_INTERRUPT(49) \
|
||||
DECLARE_INTERRUPT(50) \
|
||||
DECLARE_INTERRUPT(51) \
|
||||
DECLARE_INTERRUPT(52) \
|
||||
DECLARE_INTERRUPT(53) \
|
||||
DECLARE_INTERRUPT(54) \
|
||||
DECLARE_INTERRUPT(55) \
|
||||
DECLARE_INTERRUPT(56) \
|
||||
DECLARE_INTERRUPT(57) \
|
||||
DECLARE_INTERRUPT(58) \
|
||||
DECLARE_INTERRUPT(59) \
|
||||
DECLARE_INTERRUPT(60) \
|
||||
DECLARE_INTERRUPT(61) \
|
||||
DECLARE_INTERRUPT(62) \
|
||||
DECLARE_INTERRUPT(63) \
|
||||
DECLARE_INTERRUPT(64) \
|
||||
DECLARE_INTERRUPT(65) \
|
||||
DECLARE_INTERRUPT(66) \
|
||||
DECLARE_INTERRUPT(67) \
|
||||
DECLARE_INTERRUPT(68) \
|
||||
DECLARE_INTERRUPT(69) \
|
||||
DECLARE_INTERRUPT(70) \
|
||||
DECLARE_INTERRUPT(71) \
|
||||
DECLARE_INTERRUPT(72) \
|
||||
DECLARE_INTERRUPT(73) \
|
||||
DECLARE_INTERRUPT(74) \
|
||||
DECLARE_INTERRUPT(75) \
|
||||
DECLARE_INTERRUPT(76) \
|
||||
DECLARE_INTERRUPT(77) \
|
||||
DECLARE_INTERRUPT(78) \
|
||||
DECLARE_INTERRUPT(79) \
|
||||
DECLARE_INTERRUPT(80) \
|
||||
DECLARE_INTERRUPT(81) \
|
||||
DECLARE_INTERRUPT(82) \
|
||||
DECLARE_INTERRUPT(83) \
|
||||
DECLARE_INTERRUPT(84) \
|
||||
DECLARE_INTERRUPT(85) \
|
||||
DECLARE_INTERRUPT(86) \
|
||||
DECLARE_INTERRUPT(87) \
|
||||
DECLARE_INTERRUPT(88) \
|
||||
DECLARE_INTERRUPT(89) \
|
||||
DECLARE_INTERRUPT(90) \
|
||||
DECLARE_INTERRUPT(91) \
|
||||
DECLARE_INTERRUPT(92) \
|
||||
DECLARE_INTERRUPT(93) \
|
||||
DECLARE_INTERRUPT(94) \
|
||||
DECLARE_INTERRUPT(95) \
|
||||
DECLARE_INTERRUPT(97) \
|
||||
DECLARE_INTERRUPT(96) \
|
||||
DECLARE_INTERRUPT(98) \
|
||||
DECLARE_INTERRUPT(99) \
|
||||
DECLARE_INTERRUPT(100) \
|
||||
DECLARE_INTERRUPT(101) \
|
||||
DECLARE_INTERRUPT(102) \
|
||||
DECLARE_INTERRUPT(103) \
|
||||
DECLARE_INTERRUPT(104) \
|
||||
DECLARE_INTERRUPT(105) \
|
||||
DECLARE_INTERRUPT(106) \
|
||||
DECLARE_INTERRUPT(107) \
|
||||
DECLARE_INTERRUPT(108) \
|
||||
DECLARE_INTERRUPT(109) \
|
||||
DECLARE_INTERRUPT(110) \
|
||||
DECLARE_INTERRUPT(111) \
|
||||
DECLARE_INTERRUPT(112) \
|
||||
DECLARE_INTERRUPT(113) \
|
||||
DECLARE_INTERRUPT(114) \
|
||||
DECLARE_INTERRUPT(115) \
|
||||
DECLARE_INTERRUPT(116) \
|
||||
DECLARE_INTERRUPT(117) \
|
||||
DECLARE_INTERRUPT(118) \
|
||||
DECLARE_INTERRUPT(119) \
|
||||
DECLARE_INTERRUPT(120) \
|
||||
DECLARE_INTERRUPT(121) \
|
||||
DECLARE_INTERRUPT(122) \
|
||||
DECLARE_INTERRUPT(123) \
|
||||
DECLARE_INTERRUPT(124) \
|
||||
DECLARE_INTERRUPT(125) \
|
||||
DECLARE_INTERRUPT(126) \
|
||||
DECLARE_INTERRUPT(127) \
|
||||
DECLARE_INTERRUPT(128) \
|
||||
DECLARE_INTERRUPT(129) \
|
||||
DECLARE_INTERRUPT(130) \
|
||||
DECLARE_INTERRUPT(131) \
|
||||
DECLARE_INTERRUPT(132) \
|
||||
DECLARE_INTERRUPT(133) \
|
||||
DECLARE_INTERRUPT(134) \
|
||||
DECLARE_INTERRUPT(135) \
|
||||
DECLARE_INTERRUPT(136) \
|
||||
DECLARE_INTERRUPT(137) \
|
||||
DECLARE_INTERRUPT(138) \
|
||||
DECLARE_INTERRUPT(139) \
|
||||
DECLARE_INTERRUPT(140) \
|
||||
DECLARE_INTERRUPT(141) \
|
||||
DECLARE_INTERRUPT(142) \
|
||||
DECLARE_INTERRUPT(143) \
|
||||
DECLARE_INTERRUPT(144) \
|
||||
DECLARE_INTERRUPT(145) \
|
||||
DECLARE_INTERRUPT(146) \
|
||||
DECLARE_INTERRUPT(147) \
|
||||
DECLARE_INTERRUPT(148) \
|
||||
DECLARE_INTERRUPT(149) \
|
||||
DECLARE_INTERRUPT(150) \
|
||||
DECLARE_INTERRUPT(151) \
|
||||
DECLARE_INTERRUPT(152) \
|
||||
DECLARE_INTERRUPT(153) \
|
||||
DECLARE_INTERRUPT(154) \
|
||||
DECLARE_INTERRUPT(155) \
|
||||
DECLARE_INTERRUPT(156) \
|
||||
DECLARE_INTERRUPT(157) \
|
||||
DECLARE_INTERRUPT(158) \
|
||||
DECLARE_INTERRUPT(159) \
|
||||
DECLARE_INTERRUPT(160) \
|
||||
DECLARE_INTERRUPT(161) \
|
||||
DECLARE_INTERRUPT(162) \
|
||||
DECLARE_INTERRUPT(163) \
|
||||
DECLARE_INTERRUPT(164) \
|
||||
DECLARE_INTERRUPT(165) \
|
||||
DECLARE_INTERRUPT(166) \
|
||||
DECLARE_INTERRUPT(167) \
|
||||
DECLARE_INTERRUPT(168) \
|
||||
DECLARE_INTERRUPT(169) \
|
||||
DECLARE_INTERRUPT(170) \
|
||||
DECLARE_INTERRUPT(171) \
|
||||
DECLARE_INTERRUPT(172) \
|
||||
DECLARE_INTERRUPT(173) \
|
||||
DECLARE_INTERRUPT(174) \
|
||||
DECLARE_INTERRUPT(175) \
|
||||
DECLARE_INTERRUPT(176) \
|
||||
DECLARE_INTERRUPT(177) \
|
||||
DECLARE_INTERRUPT(178) \
|
||||
DECLARE_INTERRUPT(179) \
|
||||
DECLARE_INTERRUPT(180) \
|
||||
DECLARE_INTERRUPT(181) \
|
||||
DECLARE_INTERRUPT(182) \
|
||||
DECLARE_INTERRUPT(183) \
|
||||
DECLARE_INTERRUPT(184) \
|
||||
DECLARE_INTERRUPT(185) \
|
||||
DECLARE_INTERRUPT(186) \
|
||||
DECLARE_INTERRUPT(187) \
|
||||
DECLARE_INTERRUPT(188) \
|
||||
DECLARE_INTERRUPT(189) \
|
||||
DECLARE_INTERRUPT(190) \
|
||||
DECLARE_INTERRUPT(191) \
|
||||
DECLARE_INTERRUPT(192) \
|
||||
DECLARE_INTERRUPT(193) \
|
||||
DECLARE_INTERRUPT(194) \
|
||||
DECLARE_INTERRUPT(195) \
|
||||
DECLARE_INTERRUPT(196) \
|
||||
DECLARE_INTERRUPT(197) \
|
||||
DECLARE_INTERRUPT(198) \
|
||||
DECLARE_INTERRUPT(199) \
|
||||
DECLARE_INTERRUPT(200) \
|
||||
DECLARE_INTERRUPT(201) \
|
||||
DECLARE_INTERRUPT(202) \
|
||||
DECLARE_INTERRUPT(203) \
|
||||
DECLARE_INTERRUPT(204) \
|
||||
DECLARE_INTERRUPT(205) \
|
||||
DECLARE_INTERRUPT(206) \
|
||||
DECLARE_INTERRUPT(207) \
|
||||
DECLARE_INTERRUPT(208) \
|
||||
DECLARE_INTERRUPT(209) \
|
||||
DECLARE_INTERRUPT(210) \
|
||||
DECLARE_INTERRUPT(211) \
|
||||
DECLARE_INTERRUPT(212) \
|
||||
DECLARE_INTERRUPT(213) \
|
||||
DECLARE_INTERRUPT(214) \
|
||||
DECLARE_INTERRUPT(215) \
|
||||
DECLARE_INTERRUPT(216) \
|
||||
DECLARE_INTERRUPT(217) \
|
||||
DECLARE_INTERRUPT(218) \
|
||||
DECLARE_INTERRUPT(219) \
|
||||
DECLARE_INTERRUPT(220) \
|
||||
DECLARE_INTERRUPT(221) \
|
||||
DECLARE_INTERRUPT(222) \
|
||||
DECLARE_INTERRUPT(223) \
|
||||
DECLARE_INTERRUPT(224) \
|
||||
DECLARE_INTERRUPT(225) \
|
||||
DECLARE_INTERRUPT(226) \
|
||||
DECLARE_INTERRUPT(227) \
|
||||
DECLARE_INTERRUPT(228) \
|
||||
DECLARE_INTERRUPT(229) \
|
||||
DECLARE_INTERRUPT(230) \
|
||||
DECLARE_INTERRUPT(231) \
|
||||
DECLARE_INTERRUPT(232) \
|
||||
DECLARE_INTERRUPT(233) \
|
||||
DECLARE_INTERRUPT(234) \
|
||||
DECLARE_INTERRUPT(235) \
|
||||
DECLARE_INTERRUPT(236) \
|
||||
DECLARE_INTERRUPT(237) \
|
||||
DECLARE_INTERRUPT(238) \
|
||||
DECLARE_INTERRUPT(239) \
|
||||
DECLARE_INTERRUPT(240) \
|
||||
DECLARE_INTERRUPT(241) \
|
||||
DECLARE_INTERRUPT(242) \
|
||||
DECLARE_INTERRUPT(243) \
|
||||
DECLARE_INTERRUPT(244) \
|
||||
DECLARE_INTERRUPT(245) \
|
||||
DECLARE_INTERRUPT(246) \
|
||||
DECLARE_INTERRUPT(247) \
|
||||
DECLARE_INTERRUPT(248) \
|
||||
DECLARE_INTERRUPT(249) \
|
||||
DECLARE_INTERRUPT(250) \
|
||||
DECLARE_INTERRUPT(251) \
|
||||
DECLARE_INTERRUPT(252) \
|
||||
DECLARE_INTERRUPT(253) \
|
||||
DECLARE_INTERRUPT(254) \
|
||||
DECLARE_INTERRUPT(255));
|
||||
37
u-boot/arch/x86/cpu/ioapic.c
Normal file
37
u-boot/arch/x86/cpu/ioapic.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/ioapic.h>
|
||||
#include <asm/lapic.h>
|
||||
|
||||
u32 io_apic_read(u32 reg)
|
||||
{
|
||||
writel(reg, IO_APIC_INDEX);
|
||||
return readl(IO_APIC_DATA);
|
||||
}
|
||||
|
||||
void io_apic_write(u32 reg, u32 val)
|
||||
{
|
||||
writel(reg, IO_APIC_INDEX);
|
||||
writel(val, IO_APIC_DATA);
|
||||
}
|
||||
|
||||
void io_apic_set_id(int ioapic_id)
|
||||
{
|
||||
int bsp_lapicid = lapicid();
|
||||
|
||||
debug("IOAPIC: Initialising IOAPIC at %08x\n", IO_APIC_ADDR);
|
||||
debug("IOAPIC: Bootstrap Processor Local APIC = %#02x\n", bsp_lapicid);
|
||||
|
||||
if (ioapic_id) {
|
||||
debug("IOAPIC: ID = 0x%02x\n", ioapic_id);
|
||||
/* Set IOAPIC ID if it has been specified */
|
||||
io_apic_write(0x00, (io_apic_read(0x00) & 0xf0ffffff) |
|
||||
(ioapic_id << 24));
|
||||
}
|
||||
}
|
||||
290
u-boot/arch/x86/cpu/irq.c
Normal file
290
u-boot/arch/x86/cpu/irq.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/pirq_routing.h>
|
||||
#include <asm/tables.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct irq_routing_table *pirq_routing_table;
|
||||
|
||||
bool pirq_check_irq_routed(struct udevice *dev, int link, u8 irq)
|
||||
{
|
||||
struct irq_router *priv = dev_get_priv(dev);
|
||||
u8 pirq;
|
||||
int base = priv->link_base;
|
||||
|
||||
if (priv->config == PIRQ_VIA_PCI)
|
||||
dm_pci_read_config8(dev->parent, LINK_N2V(link, base), &pirq);
|
||||
else
|
||||
pirq = readb(priv->ibase + LINK_N2V(link, base));
|
||||
|
||||
pirq &= 0xf;
|
||||
|
||||
/* IRQ# 0/1/2/8/13 are reserved */
|
||||
if (pirq < 3 || pirq == 8 || pirq == 13)
|
||||
return false;
|
||||
|
||||
return pirq == irq ? true : false;
|
||||
}
|
||||
|
||||
int pirq_translate_link(struct udevice *dev, int link)
|
||||
{
|
||||
struct irq_router *priv = dev_get_priv(dev);
|
||||
|
||||
return LINK_V2N(link, priv->link_base);
|
||||
}
|
||||
|
||||
void pirq_assign_irq(struct udevice *dev, int link, u8 irq)
|
||||
{
|
||||
struct irq_router *priv = dev_get_priv(dev);
|
||||
int base = priv->link_base;
|
||||
|
||||
/* IRQ# 0/1/2/8/13 are reserved */
|
||||
if (irq < 3 || irq == 8 || irq == 13)
|
||||
return;
|
||||
|
||||
if (priv->config == PIRQ_VIA_PCI)
|
||||
dm_pci_write_config8(dev->parent, LINK_N2V(link, base), irq);
|
||||
else
|
||||
writeb(irq, priv->ibase + LINK_N2V(link, base));
|
||||
}
|
||||
|
||||
static struct irq_info *check_dup_entry(struct irq_info *slot_base,
|
||||
int entry_num, int bus, int device)
|
||||
{
|
||||
struct irq_info *slot = slot_base;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < entry_num; i++) {
|
||||
if (slot->bus == bus && slot->devfn == (device << 3))
|
||||
break;
|
||||
slot++;
|
||||
}
|
||||
|
||||
return (i == entry_num) ? NULL : slot;
|
||||
}
|
||||
|
||||
static inline void fill_irq_info(struct irq_router *priv, struct irq_info *slot,
|
||||
int bus, int device, int pin, int pirq)
|
||||
{
|
||||
slot->bus = bus;
|
||||
slot->devfn = (device << 3) | 0;
|
||||
slot->irq[pin - 1].link = LINK_N2V(pirq, priv->link_base);
|
||||
slot->irq[pin - 1].bitmap = priv->irq_mask;
|
||||
}
|
||||
|
||||
static int create_pirq_routing_table(struct udevice *dev)
|
||||
{
|
||||
struct irq_router *priv = dev_get_priv(dev);
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node;
|
||||
int len, count;
|
||||
const u32 *cell;
|
||||
struct irq_routing_table *rt;
|
||||
struct irq_info *slot, *slot_base;
|
||||
int irq_entries = 0;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
node = dev->of_offset;
|
||||
|
||||
/* extract the bdf from fdt_pci_addr */
|
||||
priv->bdf = dm_pci_get_bdf(dev->parent);
|
||||
|
||||
ret = fdt_find_string(blob, node, "intel,pirq-config", "pci");
|
||||
if (!ret) {
|
||||
priv->config = PIRQ_VIA_PCI;
|
||||
} else {
|
||||
ret = fdt_find_string(blob, node, "intel,pirq-config", "ibase");
|
||||
if (!ret)
|
||||
priv->config = PIRQ_VIA_IBASE;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = fdtdec_get_int(blob, node, "intel,pirq-link", -1);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
priv->link_base = ret;
|
||||
|
||||
priv->irq_mask = fdtdec_get_int(blob, node,
|
||||
"intel,pirq-mask", PIRQ_BITMAP);
|
||||
|
||||
if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE)) {
|
||||
/* Reserve IRQ9 for SCI */
|
||||
priv->irq_mask &= ~(1 << 9);
|
||||
}
|
||||
|
||||
if (priv->config == PIRQ_VIA_IBASE) {
|
||||
int ibase_off;
|
||||
|
||||
ibase_off = fdtdec_get_int(blob, node, "intel,ibase-offset", 0);
|
||||
if (!ibase_off)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Here we assume that the IBASE register has already been
|
||||
* properly configured by U-Boot before.
|
||||
*
|
||||
* By 'valid' we mean:
|
||||
* 1) a valid memory space carved within system memory space
|
||||
* assigned to IBASE register block.
|
||||
* 2) memory range decoding is enabled.
|
||||
* Hence we don't do any santify test here.
|
||||
*/
|
||||
dm_pci_read_config32(dev->parent, ibase_off, &priv->ibase);
|
||||
priv->ibase &= ~0xf;
|
||||
}
|
||||
|
||||
priv->actl_8bit = fdtdec_get_bool(blob, node, "intel,actl-8bit");
|
||||
priv->actl_addr = fdtdec_get_int(blob, node, "intel,actl-addr", 0);
|
||||
|
||||
cell = fdt_getprop(blob, node, "intel,pirq-routing", &len);
|
||||
if (!cell || len % sizeof(struct pirq_routing))
|
||||
return -EINVAL;
|
||||
count = len / sizeof(struct pirq_routing);
|
||||
|
||||
rt = calloc(1, sizeof(struct irq_routing_table));
|
||||
if (!rt)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Populate the PIRQ table fields */
|
||||
rt->signature = PIRQ_SIGNATURE;
|
||||
rt->version = PIRQ_VERSION;
|
||||
rt->rtr_bus = PCI_BUS(priv->bdf);
|
||||
rt->rtr_devfn = (PCI_DEV(priv->bdf) << 3) | PCI_FUNC(priv->bdf);
|
||||
rt->rtr_vendor = PCI_VENDOR_ID_INTEL;
|
||||
rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31;
|
||||
|
||||
slot_base = rt->slots;
|
||||
|
||||
/* Now fill in the irq_info entries in the PIRQ table */
|
||||
for (i = 0; i < count;
|
||||
i++, cell += sizeof(struct pirq_routing) / sizeof(u32)) {
|
||||
struct pirq_routing pr;
|
||||
|
||||
pr.bdf = fdt_addr_to_cpu(cell[0]);
|
||||
pr.pin = fdt_addr_to_cpu(cell[1]);
|
||||
pr.pirq = fdt_addr_to_cpu(cell[2]);
|
||||
|
||||
debug("irq_info %d: b.d.f %x.%x.%x INT%c PIRQ%c\n",
|
||||
i, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
|
||||
PCI_FUNC(pr.bdf), 'A' + pr.pin - 1,
|
||||
'A' + pr.pirq);
|
||||
|
||||
slot = check_dup_entry(slot_base, irq_entries,
|
||||
PCI_BUS(pr.bdf), PCI_DEV(pr.bdf));
|
||||
if (slot) {
|
||||
debug("found entry for bus %d device %d, ",
|
||||
PCI_BUS(pr.bdf), PCI_DEV(pr.bdf));
|
||||
|
||||
if (slot->irq[pr.pin - 1].link) {
|
||||
debug("skipping\n");
|
||||
|
||||
/*
|
||||
* Sanity test on the routed PIRQ pin
|
||||
*
|
||||
* If they don't match, show a warning to tell
|
||||
* there might be something wrong with the PIRQ
|
||||
* routing information in the device tree.
|
||||
*/
|
||||
if (slot->irq[pr.pin - 1].link !=
|
||||
LINK_N2V(pr.pirq, priv->link_base))
|
||||
debug("WARNING: Inconsistent PIRQ routing information\n");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
slot = slot_base + irq_entries++;
|
||||
}
|
||||
debug("writing INT%c\n", 'A' + pr.pin - 1);
|
||||
fill_irq_info(priv, slot, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
|
||||
pr.pin, pr.pirq);
|
||||
}
|
||||
|
||||
rt->size = irq_entries * sizeof(struct irq_info) + 32;
|
||||
|
||||
/* Fix up the table checksum */
|
||||
rt->checksum = table_compute_checksum(rt, rt->size);
|
||||
|
||||
pirq_routing_table = rt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void irq_enable_sci(struct udevice *dev)
|
||||
{
|
||||
struct irq_router *priv = dev_get_priv(dev);
|
||||
|
||||
if (priv->actl_8bit) {
|
||||
/* Bit7 must be turned on to enable ACPI */
|
||||
dm_pci_write_config8(dev->parent, priv->actl_addr, 0x80);
|
||||
} else {
|
||||
/* Write 0 to enable SCI on IRQ9 */
|
||||
if (priv->config == PIRQ_VIA_PCI)
|
||||
dm_pci_write_config32(dev->parent, priv->actl_addr, 0);
|
||||
else
|
||||
writel(0, priv->ibase + priv->actl_addr);
|
||||
}
|
||||
}
|
||||
|
||||
int irq_router_common_init(struct udevice *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = create_pirq_routing_table(dev);
|
||||
if (ret) {
|
||||
debug("Failed to create pirq routing table\n");
|
||||
return ret;
|
||||
}
|
||||
/* Route PIRQ */
|
||||
pirq_route_irqs(dev, pirq_routing_table->slots,
|
||||
get_irq_slot_count(pirq_routing_table));
|
||||
|
||||
if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE))
|
||||
irq_enable_sci(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int irq_router_probe(struct udevice *dev)
|
||||
{
|
||||
return irq_router_common_init(dev);
|
||||
}
|
||||
|
||||
u32 write_pirq_routing_table(u32 addr)
|
||||
{
|
||||
if (!pirq_routing_table)
|
||||
return addr;
|
||||
|
||||
return copy_pirq_routing_table(addr, pirq_routing_table);
|
||||
}
|
||||
|
||||
static const struct udevice_id irq_router_ids[] = {
|
||||
{ .compatible = "intel,irq-router" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(irq_router_drv) = {
|
||||
.name = "intel_irq",
|
||||
.id = UCLASS_IRQ,
|
||||
.of_match = irq_router_ids,
|
||||
.probe = irq_router_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct irq_router),
|
||||
};
|
||||
|
||||
UCLASS_DRIVER(irq) = {
|
||||
.id = UCLASS_IRQ,
|
||||
.name = "irq",
|
||||
};
|
||||
61
u-boot/arch/x86/cpu/ivybridge/Kconfig
Normal file
61
u-boot/arch/x86/cpu/ivybridge/Kconfig
Normal file
@@ -0,0 +1,61 @@
|
||||
#
|
||||
# From Coreboot src/northbridge/intel/sandybridge/Kconfig
|
||||
#
|
||||
# Copyright (C) 2010 Google Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config NORTHBRIDGE_INTEL_IVYBRIDGE
|
||||
bool
|
||||
select CACHE_MRC_BIN if HAVE_MRC
|
||||
|
||||
if NORTHBRIDGE_INTEL_IVYBRIDGE
|
||||
|
||||
config DCACHE_RAM_BASE
|
||||
default 0xff7e0000
|
||||
|
||||
config DCACHE_RAM_SIZE
|
||||
default 0x20000
|
||||
|
||||
config DCACHE_RAM_MRC_VAR_SIZE
|
||||
default 0x4000
|
||||
|
||||
config CPU_SPECIFIC_OPTIONS
|
||||
def_bool y
|
||||
select SMM_TSEG
|
||||
select X86_RAMTEST
|
||||
|
||||
config SMM_TSEG_SIZE
|
||||
hex
|
||||
default 0x800000
|
||||
|
||||
config ENABLE_VMX
|
||||
bool "Enable VMX for virtualization"
|
||||
default n
|
||||
help
|
||||
Virtual Machine Extensions are provided in many x86 CPUs. These
|
||||
provide various facilities for allowing a host OS to provide an
|
||||
environment where potentially several guest OSes have only
|
||||
limited access to the underlying hardware. This is achieved
|
||||
without resorting to software trapping and/or instruction set
|
||||
emulation (which would be very slow).
|
||||
|
||||
Intel's implementation of this is called VT-x. This option enables
|
||||
VT-x this so that the OS that is booted by U-Boot can make use of
|
||||
these facilities. If this option is not enabled, then the host OS
|
||||
will be unable to support virtualisation, or it will run very
|
||||
slowly.
|
||||
|
||||
config FSP_ADDR
|
||||
hex
|
||||
default 0xfff80000
|
||||
|
||||
config FSP_USE_UPD
|
||||
bool
|
||||
default n
|
||||
|
||||
config FSP_BROKEN_HOB
|
||||
bool
|
||||
default y
|
||||
|
||||
endif
|
||||
19
u-boot/arch/x86/cpu/ivybridge/Makefile
Normal file
19
u-boot/arch/x86/cpu/ivybridge/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2014 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
ifdef CONFIG_HAVE_FSP
|
||||
obj-y += fsp_configs.o ivybridge.o
|
||||
else
|
||||
obj-y += cpu.o
|
||||
obj-y += early_me.o
|
||||
obj-y += gma.o
|
||||
obj-y += lpc.o
|
||||
obj-y += model_206ax.o
|
||||
obj-y += northbridge.o
|
||||
obj-y += sata.o
|
||||
obj-y += sdram.o
|
||||
endif
|
||||
obj-y += bd82x6x.o
|
||||
245
u-boot/arch/x86/cpu/ivybridge/bd82x6x.c
Normal file
245
u-boot/arch/x86/cpu/ivybridge/bd82x6x.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <pch.h>
|
||||
#include <syscon.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/lapic.h>
|
||||
#include <asm/lpc_common.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/arch/bd82x6x.h>
|
||||
#include <asm/arch/model_206ax.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/sandybridge.h>
|
||||
|
||||
#define GPIO_BASE 0x48
|
||||
#define BIOS_CTRL 0xdc
|
||||
|
||||
#ifndef CONFIG_HAVE_FSP
|
||||
static int pch_revision_id = -1;
|
||||
static int pch_type = -1;
|
||||
|
||||
/**
|
||||
* pch_silicon_revision() - Read silicon revision ID from the PCH
|
||||
*
|
||||
* @dev: PCH device
|
||||
* @return silicon revision ID
|
||||
*/
|
||||
static int pch_silicon_revision(struct udevice *dev)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
if (pch_revision_id < 0) {
|
||||
dm_pci_read_config8(dev, PCI_REVISION_ID, &val);
|
||||
pch_revision_id = val;
|
||||
}
|
||||
|
||||
return pch_revision_id;
|
||||
}
|
||||
|
||||
int pch_silicon_type(struct udevice *dev)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
if (pch_type < 0) {
|
||||
dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val);
|
||||
pch_type = val;
|
||||
}
|
||||
|
||||
return pch_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* pch_silicon_supported() - Check if a certain revision is supported
|
||||
*
|
||||
* @dev: PCH device
|
||||
* @type: PCH type
|
||||
* @rev: Minimum required resion
|
||||
* @return 0 if not supported, 1 if supported
|
||||
*/
|
||||
static int pch_silicon_supported(struct udevice *dev, int type, int rev)
|
||||
{
|
||||
int cur_type = pch_silicon_type(dev);
|
||||
int cur_rev = pch_silicon_revision(dev);
|
||||
|
||||
switch (type) {
|
||||
case PCH_TYPE_CPT:
|
||||
/* CougarPoint minimum revision */
|
||||
if (cur_type == PCH_TYPE_CPT && cur_rev >= rev)
|
||||
return 1;
|
||||
/* PantherPoint any revision */
|
||||
if (cur_type == PCH_TYPE_PPT)
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case PCH_TYPE_PPT:
|
||||
/* PantherPoint minimum revision */
|
||||
if (cur_type == PCH_TYPE_PPT && cur_rev >= rev)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define IOBP_RETRY 1000
|
||||
static inline int iobp_poll(void)
|
||||
{
|
||||
unsigned try = IOBP_RETRY;
|
||||
u32 data;
|
||||
|
||||
while (try--) {
|
||||
data = readl(RCB_REG(IOBPS));
|
||||
if ((data & 1) == 0)
|
||||
return 1;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
printf("IOBP timeout\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue,
|
||||
u32 orvalue)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
/* Set the address */
|
||||
writel(address, RCB_REG(IOBPIRI));
|
||||
|
||||
/* READ OPCODE */
|
||||
if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
|
||||
writel(IOBPS_RW_BX, RCB_REG(IOBPS));
|
||||
else
|
||||
writel(IOBPS_READ_AX, RCB_REG(IOBPS));
|
||||
if (!iobp_poll())
|
||||
return;
|
||||
|
||||
/* Read IOBP data */
|
||||
data = readl(RCB_REG(IOBPD));
|
||||
if (!iobp_poll())
|
||||
return;
|
||||
|
||||
/* Check for successful transaction */
|
||||
if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) {
|
||||
printf("IOBP read 0x%08x failed\n", address);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update the data */
|
||||
data &= andvalue;
|
||||
data |= orvalue;
|
||||
|
||||
/* WRITE OPCODE */
|
||||
if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
|
||||
writel(IOBPS_RW_BX, RCB_REG(IOBPS));
|
||||
else
|
||||
writel(IOBPS_WRITE_AX, RCB_REG(IOBPS));
|
||||
if (!iobp_poll())
|
||||
return;
|
||||
|
||||
/* Write IOBP data */
|
||||
writel(data, RCB_REG(IOBPD));
|
||||
if (!iobp_poll())
|
||||
return;
|
||||
}
|
||||
|
||||
static int bd82x6x_probe(struct udevice *dev)
|
||||
{
|
||||
struct udevice *gma_dev;
|
||||
int ret;
|
||||
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return 0;
|
||||
|
||||
/* Cause the SATA device to do its init */
|
||||
uclass_first_device(UCLASS_AHCI, &dev);
|
||||
|
||||
ret = syscon_get_by_driver_data(X86_SYSCON_GMA, &gma_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = gma_func0_init(gma_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_HAVE_FSP */
|
||||
|
||||
static int bd82x6x_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 bd82x6x_set_spi_protect(struct udevice *dev, bool protect)
|
||||
{
|
||||
return lpc_set_spi_protect(dev, BIOS_CTRL, protect);
|
||||
}
|
||||
|
||||
static int bd82x6x_get_gpio_base(struct udevice *dev, u32 *gbasep)
|
||||
{
|
||||
u32 base;
|
||||
|
||||
/*
|
||||
* GPIO_BASE moved to its current offset with ICH6, but prior to
|
||||
* that it was unused (or undocumented). Check that it looks
|
||||
* okay: not all ones or zeros.
|
||||
*
|
||||
* Note we don't need check bit0 here, because the Tunnel Creek
|
||||
* GPIO base address register bit0 is reserved (read returns 0),
|
||||
* while on the Ivybridge the bit0 is used to indicate it is an
|
||||
* I/O space.
|
||||
*/
|
||||
dm_pci_read_config32(dev, GPIO_BASE, &base);
|
||||
if (base == 0x00000000 || base == 0xffffffff) {
|
||||
debug("%s: unexpected BASE value\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Okay, I guess we're looking at the right device. The actual
|
||||
* GPIO registers are in the PCI device's I/O space, starting
|
||||
* at the offset that we just read. Bit 0 indicates that it's
|
||||
* an I/O address, not a memory address, so mask that off.
|
||||
*/
|
||||
*gbasep = base & 1 ? base & ~3 : base & ~15;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pch_ops bd82x6x_pch_ops = {
|
||||
.get_spi_base = bd82x6x_pch_get_spi_base,
|
||||
.set_spi_protect = bd82x6x_set_spi_protect,
|
||||
.get_gpio_base = bd82x6x_get_gpio_base,
|
||||
};
|
||||
|
||||
static const struct udevice_id bd82x6x_ids[] = {
|
||||
{ .compatible = "intel,bd82x6x" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bd82x6x_drv) = {
|
||||
.name = "bd82x6x",
|
||||
.id = UCLASS_PCH,
|
||||
.of_match = bd82x6x_ids,
|
||||
#ifndef CONFIG_HAVE_FSP
|
||||
.probe = bd82x6x_probe,
|
||||
#endif
|
||||
.ops = &bd82x6x_pch_ops,
|
||||
};
|
||||
195
u-boot/arch/x86/cpu/ivybridge/cpu.c
Normal file
195
u-boot/arch/x86/cpu/ivybridge/cpu.c
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Google, Inc
|
||||
* (C) Copyright 2008
|
||||
* Graeme Russ, graeme.russ@gmail.com.
|
||||
*
|
||||
* Some portions from coreboot src/mainboard/google/link/romstage.c
|
||||
* and src/cpu/intel/model_206ax/bootblock.c
|
||||
* Copyright (C) 2007-2010 coresystems GmbH
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <pch.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu_common.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/lapic.h>
|
||||
#include <asm/lpc_common.h>
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/arch/model_206ax.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/sandybridge.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static int set_flex_ratio_to_tdp_nominal(void)
|
||||
{
|
||||
/* Minimum CPU revision for configurable TDP support */
|
||||
if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
|
||||
return -EINVAL;
|
||||
|
||||
return cpu_set_flex_ratio_to_tdp_nominal();
|
||||
}
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
post_code(POST_CPU_INIT);
|
||||
|
||||
return x86_cpu_init_f();
|
||||
}
|
||||
|
||||
int arch_cpu_init_dm(void)
|
||||
{
|
||||
struct pci_controller *hose;
|
||||
struct udevice *bus, *dev;
|
||||
int ret;
|
||||
|
||||
post_code(0x70);
|
||||
ret = uclass_get_device(UCLASS_PCI, 0, &bus);
|
||||
post_code(0x71);
|
||||
if (ret)
|
||||
return ret;
|
||||
post_code(0x72);
|
||||
hose = dev_get_uclass_priv(bus);
|
||||
|
||||
/* TODO(sjg@chromium.org): Get rid of gd->hose */
|
||||
gd->hose = hose;
|
||||
|
||||
ret = uclass_first_device_err(UCLASS_LPC, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We should do as little as possible before the serial console is
|
||||
* up. Perhaps this should move to later. Our next lot of init
|
||||
* happens in print_cpuinfo() when we have a console
|
||||
*/
|
||||
ret = set_flex_ratio_to_tdp_nominal();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PCH_EHCI0_TEMP_BAR0 0xe8000000
|
||||
#define PCH_EHCI1_TEMP_BAR0 0xe8000400
|
||||
#define PCH_XHCI_TEMP_BAR0 0xe8001000
|
||||
|
||||
/*
|
||||
* Setup USB controller MMIO BAR to prevent the reference code from
|
||||
* resetting the controller.
|
||||
*
|
||||
* The BAR will be re-assigned during device enumeration so these are only
|
||||
* temporary.
|
||||
*
|
||||
* This is used to speed up the resume path.
|
||||
*/
|
||||
static void enable_usb_bar(struct udevice *bus)
|
||||
{
|
||||
pci_dev_t usb0 = PCH_EHCI1_DEV;
|
||||
pci_dev_t usb1 = PCH_EHCI2_DEV;
|
||||
pci_dev_t usb3 = PCH_XHCI_DEV;
|
||||
ulong cmd;
|
||||
|
||||
/* USB Controller 1 */
|
||||
pci_bus_write_config(bus, usb0, PCI_BASE_ADDRESS_0,
|
||||
PCH_EHCI0_TEMP_BAR0, PCI_SIZE_32);
|
||||
pci_bus_read_config(bus, usb0, PCI_COMMAND, &cmd, PCI_SIZE_32);
|
||||
cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
|
||||
pci_bus_write_config(bus, usb0, PCI_COMMAND, cmd, PCI_SIZE_32);
|
||||
|
||||
/* USB Controller 2 */
|
||||
pci_bus_write_config(bus, usb1, PCI_BASE_ADDRESS_0,
|
||||
PCH_EHCI1_TEMP_BAR0, PCI_SIZE_32);
|
||||
pci_bus_read_config(bus, usb1, PCI_COMMAND, &cmd, PCI_SIZE_32);
|
||||
cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
|
||||
pci_bus_write_config(bus, usb1, PCI_COMMAND, cmd, PCI_SIZE_32);
|
||||
|
||||
/* USB3 Controller 1 */
|
||||
pci_bus_write_config(bus, usb3, PCI_BASE_ADDRESS_0,
|
||||
PCH_XHCI_TEMP_BAR0, PCI_SIZE_32);
|
||||
pci_bus_read_config(bus, usb3, PCI_COMMAND, &cmd, PCI_SIZE_32);
|
||||
cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
|
||||
pci_bus_write_config(bus, usb3, PCI_COMMAND, cmd, PCI_SIZE_32);
|
||||
}
|
||||
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
enum pei_boot_mode_t boot_mode = PEI_BOOT_NONE;
|
||||
char processor_name[CPU_MAX_NAME_LEN];
|
||||
struct udevice *dev, *lpc;
|
||||
const char *name;
|
||||
uint32_t pm1_cnt;
|
||||
uint16_t pm1_sts;
|
||||
int ret;
|
||||
|
||||
/* TODO: cmos_post_init() */
|
||||
if (readl(MCHBAR_REG(SSKPD)) == 0xCAFE) {
|
||||
debug("soft reset detected\n");
|
||||
boot_mode = PEI_BOOT_SOFT_RESET;
|
||||
|
||||
/* System is not happy after keyboard reset... */
|
||||
debug("Issuing CF9 warm reset\n");
|
||||
reset_cpu(0);
|
||||
}
|
||||
|
||||
ret = cpu_common_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Check PM1_STS[15] to see if we are waking from Sx */
|
||||
pm1_sts = inw(DEFAULT_PMBASE + PM1_STS);
|
||||
|
||||
/* Read PM1_CNT[12:10] to determine which Sx state */
|
||||
pm1_cnt = inl(DEFAULT_PMBASE + PM1_CNT);
|
||||
|
||||
if ((pm1_sts & WAK_STS) && ((pm1_cnt >> 10) & 7) == 5) {
|
||||
debug("Resume from S3 detected, but disabled.\n");
|
||||
} else {
|
||||
/*
|
||||
* TODO: An indication of life might be possible here (e.g.
|
||||
* keyboard light)
|
||||
*/
|
||||
}
|
||||
post_code(POST_EARLY_INIT);
|
||||
|
||||
/* Enable SPD ROMs and DDR-III DRAM */
|
||||
ret = uclass_first_device_err(UCLASS_I2C, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Prepare USB controller early in S3 resume */
|
||||
if (boot_mode == PEI_BOOT_RESUME) {
|
||||
uclass_first_device(UCLASS_LPC, &lpc);
|
||||
enable_usb_bar(pci_get_controller(lpc->parent));
|
||||
}
|
||||
|
||||
gd->arch.pei_boot_mode = boot_mode;
|
||||
|
||||
/* Print processor name */
|
||||
name = cpu_get_name(processor_name);
|
||||
printf("CPU: %s\n", name);
|
||||
|
||||
post_code(POST_CPU_INFO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void board_debug_uart_init(void)
|
||||
{
|
||||
/* This enables the debug UART */
|
||||
pci_x86_write_config(NULL, PCH_LPC_DEV, LPC_EN, COMA_LPC_EN,
|
||||
PCI_SIZE_16);
|
||||
}
|
||||
173
u-boot/arch/x86/cpu/ivybridge/early_me.c
Normal file
173
u-boot/arch/x86/cpu/ivybridge/early_me.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* From Coreboot src/southbridge/intel/bd82x6x/early_me.c
|
||||
*
|
||||
* Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/arch/me.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static const char *const me_ack_values[] = {
|
||||
[ME_HFS_ACK_NO_DID] = "No DID Ack received",
|
||||
[ME_HFS_ACK_RESET] = "Non-power cycle reset",
|
||||
[ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset",
|
||||
[ME_HFS_ACK_S3] = "Go to S3",
|
||||
[ME_HFS_ACK_S4] = "Go to S4",
|
||||
[ME_HFS_ACK_S5] = "Go to S5",
|
||||
[ME_HFS_ACK_GBL_RESET] = "Global Reset",
|
||||
[ME_HFS_ACK_CONTINUE] = "Continue to boot"
|
||||
};
|
||||
|
||||
int intel_early_me_init(struct udevice *me_dev)
|
||||
{
|
||||
int count;
|
||||
struct me_uma uma;
|
||||
struct me_hfs hfs;
|
||||
|
||||
debug("Intel ME early init\n");
|
||||
|
||||
/* Wait for ME UMA SIZE VALID bit to be set */
|
||||
for (count = ME_RETRY; count > 0; --count) {
|
||||
pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA);
|
||||
if (uma.valid)
|
||||
break;
|
||||
udelay(ME_DELAY);
|
||||
}
|
||||
if (!count) {
|
||||
printf("ERROR: ME is not ready!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Check for valid firmware */
|
||||
pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS);
|
||||
if (hfs.fpt_bad) {
|
||||
printf("WARNING: ME has bad firmware\n");
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
debug("Intel ME firmware is ready\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intel_early_me_uma_size(struct udevice *me_dev)
|
||||
{
|
||||
struct me_uma uma;
|
||||
|
||||
pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA);
|
||||
if (uma.valid) {
|
||||
debug("ME: Requested %uMB UMA\n", uma.size);
|
||||
return uma.size;
|
||||
}
|
||||
|
||||
debug("ME: Invalid UMA size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void set_global_reset(struct udevice *dev, int enable)
|
||||
{
|
||||
u32 etr3;
|
||||
|
||||
dm_pci_read_config32(dev, ETR3, &etr3);
|
||||
|
||||
/* Clear CF9 Without Resume Well Reset Enable */
|
||||
etr3 &= ~ETR3_CWORWRE;
|
||||
|
||||
/* CF9GR indicates a Global Reset */
|
||||
if (enable)
|
||||
etr3 |= ETR3_CF9GR;
|
||||
else
|
||||
etr3 &= ~ETR3_CF9GR;
|
||||
|
||||
dm_pci_write_config32(dev, ETR3, etr3);
|
||||
}
|
||||
|
||||
int intel_early_me_init_done(struct udevice *dev, struct udevice *me_dev,
|
||||
uint status)
|
||||
{
|
||||
int count;
|
||||
u32 mebase_l, mebase_h;
|
||||
struct me_hfs hfs;
|
||||
struct me_did did = {
|
||||
.init_done = ME_INIT_DONE,
|
||||
.status = status
|
||||
};
|
||||
|
||||
/* MEBASE from MESEG_BASE[35:20] */
|
||||
dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_L, &mebase_l);
|
||||
dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_H, &mebase_h);
|
||||
mebase_h &= 0xf;
|
||||
did.uma_base = (mebase_l >> 20) | (mebase_h << 12);
|
||||
|
||||
/* Send message to ME */
|
||||
debug("ME: Sending Init Done with status: %d, UMA base: 0x%04x\n",
|
||||
status, did.uma_base);
|
||||
|
||||
pci_write_dword_ptr(me_dev, &did, PCI_ME_H_GS);
|
||||
|
||||
/* Must wait for ME acknowledgement */
|
||||
for (count = ME_RETRY; count > 0; --count) {
|
||||
pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS);
|
||||
if (hfs.bios_msg_ack)
|
||||
break;
|
||||
udelay(ME_DELAY);
|
||||
}
|
||||
if (!count) {
|
||||
printf("ERROR: ME failed to respond\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Return the requested BIOS action */
|
||||
debug("ME: Requested BIOS Action: %s\n", me_ack_values[hfs.ack_data]);
|
||||
|
||||
/* Check status after acknowledgement */
|
||||
intel_me_status(me_dev);
|
||||
|
||||
switch (hfs.ack_data) {
|
||||
case ME_HFS_ACK_CONTINUE:
|
||||
/* Continue to boot */
|
||||
return 0;
|
||||
case ME_HFS_ACK_RESET:
|
||||
/* Non-power cycle reset */
|
||||
set_global_reset(dev, 0);
|
||||
reset_cpu(0);
|
||||
break;
|
||||
case ME_HFS_ACK_PWR_CYCLE:
|
||||
/* Power cycle reset */
|
||||
set_global_reset(dev, 0);
|
||||
x86_full_reset();
|
||||
break;
|
||||
case ME_HFS_ACK_GBL_RESET:
|
||||
/* Global reset */
|
||||
set_global_reset(dev, 1);
|
||||
x86_full_reset();
|
||||
break;
|
||||
case ME_HFS_ACK_S3:
|
||||
case ME_HFS_ACK_S4:
|
||||
case ME_HFS_ACK_S5:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct udevice_id ivybridge_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 = ivybridge_syscon_ids,
|
||||
};
|
||||
45
u-boot/arch/x86/cpu/ivybridge/fsp_configs.c
Normal file
45
u-boot/arch/x86/cpu/ivybridge/fsp_configs.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fdtdec.h>
|
||||
#include <asm/fsp/fsp_support.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void update_fsp_configs(struct fsp_config_data *config,
|
||||
struct fspinit_rtbuf *rt_buf)
|
||||
{
|
||||
struct platform_config *plat_config = &config->plat_config;
|
||||
struct memory_config *mem_config = &config->mem_config;
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node;
|
||||
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IVYBRIDGE_FSP);
|
||||
if (node < 0) {
|
||||
debug("%s: Cannot find FSP node\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
plat_config->enable_ht =
|
||||
fdtdec_get_bool(blob, node, "fsp,enable-ht");
|
||||
plat_config->enable_turbo =
|
||||
fdtdec_get_bool(blob, node, "fsp,enable-turbo");
|
||||
plat_config->enable_memory_down =
|
||||
fdtdec_get_bool(blob, node, "fsp,enable-memory-down");
|
||||
plat_config->enable_fast_boot =
|
||||
fdtdec_get_bool(blob, node, "fsp,enable-fast-boot");
|
||||
|
||||
/* Initialize runtime buffer for fsp_init() */
|
||||
rt_buf->stack_top = config->common.stack_top - 32;
|
||||
rt_buf->boot_mode = config->common.boot_mode;
|
||||
rt_buf->plat_config = plat_config;
|
||||
|
||||
if (plat_config->enable_memory_down)
|
||||
rt_buf->mem_config = mem_config;
|
||||
else
|
||||
rt_buf->mem_config = NULL;
|
||||
}
|
||||
850
u-boot/arch/x86/cpu/ivybridge/gma.c
Normal file
850
u-boot/arch/x86/cpu/ivybridge/gma.c
Normal file
@@ -0,0 +1,850 @@
|
||||
/*
|
||||
* From Coreboot file of the same name
|
||||
*
|
||||
* Copyright (C) 2011 Chromium OS Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <bios_emul.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <pci_rom.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/sandybridge.h>
|
||||
|
||||
struct gt_powermeter {
|
||||
u16 reg;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
static const struct gt_powermeter snb_pm_gt1[] = {
|
||||
{ 0xa200, 0xcc000000 },
|
||||
{ 0xa204, 0x07000040 },
|
||||
{ 0xa208, 0x0000fe00 },
|
||||
{ 0xa20c, 0x00000000 },
|
||||
{ 0xa210, 0x17000000 },
|
||||
{ 0xa214, 0x00000021 },
|
||||
{ 0xa218, 0x0817fe19 },
|
||||
{ 0xa21c, 0x00000000 },
|
||||
{ 0xa220, 0x00000000 },
|
||||
{ 0xa224, 0xcc000000 },
|
||||
{ 0xa228, 0x07000040 },
|
||||
{ 0xa22c, 0x0000fe00 },
|
||||
{ 0xa230, 0x00000000 },
|
||||
{ 0xa234, 0x17000000 },
|
||||
{ 0xa238, 0x00000021 },
|
||||
{ 0xa23c, 0x0817fe19 },
|
||||
{ 0xa240, 0x00000000 },
|
||||
{ 0xa244, 0x00000000 },
|
||||
{ 0xa248, 0x8000421e },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct gt_powermeter snb_pm_gt2[] = {
|
||||
{ 0xa200, 0x330000a6 },
|
||||
{ 0xa204, 0x402d0031 },
|
||||
{ 0xa208, 0x00165f83 },
|
||||
{ 0xa20c, 0xf1000000 },
|
||||
{ 0xa210, 0x00000000 },
|
||||
{ 0xa214, 0x00160016 },
|
||||
{ 0xa218, 0x002a002b },
|
||||
{ 0xa21c, 0x00000000 },
|
||||
{ 0xa220, 0x00000000 },
|
||||
{ 0xa224, 0x330000a6 },
|
||||
{ 0xa228, 0x402d0031 },
|
||||
{ 0xa22c, 0x00165f83 },
|
||||
{ 0xa230, 0xf1000000 },
|
||||
{ 0xa234, 0x00000000 },
|
||||
{ 0xa238, 0x00160016 },
|
||||
{ 0xa23c, 0x002a002b },
|
||||
{ 0xa240, 0x00000000 },
|
||||
{ 0xa244, 0x00000000 },
|
||||
{ 0xa248, 0x8000421e },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct gt_powermeter ivb_pm_gt1[] = {
|
||||
{ 0xa800, 0x00000000 },
|
||||
{ 0xa804, 0x00021c00 },
|
||||
{ 0xa808, 0x00000403 },
|
||||
{ 0xa80c, 0x02001700 },
|
||||
{ 0xa810, 0x05000200 },
|
||||
{ 0xa814, 0x00000000 },
|
||||
{ 0xa818, 0x00690500 },
|
||||
{ 0xa81c, 0x0000007f },
|
||||
{ 0xa820, 0x01002501 },
|
||||
{ 0xa824, 0x00000300 },
|
||||
{ 0xa828, 0x01000331 },
|
||||
{ 0xa82c, 0x0000000c },
|
||||
{ 0xa830, 0x00010016 },
|
||||
{ 0xa834, 0x01100101 },
|
||||
{ 0xa838, 0x00010103 },
|
||||
{ 0xa83c, 0x00041300 },
|
||||
{ 0xa840, 0x00000b30 },
|
||||
{ 0xa844, 0x00000000 },
|
||||
{ 0xa848, 0x7f000000 },
|
||||
{ 0xa84c, 0x05000008 },
|
||||
{ 0xa850, 0x00000001 },
|
||||
{ 0xa854, 0x00000004 },
|
||||
{ 0xa858, 0x00000007 },
|
||||
{ 0xa85c, 0x00000000 },
|
||||
{ 0xa860, 0x00010000 },
|
||||
{ 0xa248, 0x0000221e },
|
||||
{ 0xa900, 0x00000000 },
|
||||
{ 0xa904, 0x00001c00 },
|
||||
{ 0xa908, 0x00000000 },
|
||||
{ 0xa90c, 0x06000000 },
|
||||
{ 0xa910, 0x09000200 },
|
||||
{ 0xa914, 0x00000000 },
|
||||
{ 0xa918, 0x00590000 },
|
||||
{ 0xa91c, 0x00000000 },
|
||||
{ 0xa920, 0x04002501 },
|
||||
{ 0xa924, 0x00000100 },
|
||||
{ 0xa928, 0x03000410 },
|
||||
{ 0xa92c, 0x00000000 },
|
||||
{ 0xa930, 0x00020000 },
|
||||
{ 0xa934, 0x02070106 },
|
||||
{ 0xa938, 0x00010100 },
|
||||
{ 0xa93c, 0x00401c00 },
|
||||
{ 0xa940, 0x00000000 },
|
||||
{ 0xa944, 0x00000000 },
|
||||
{ 0xa948, 0x10000e00 },
|
||||
{ 0xa94c, 0x02000004 },
|
||||
{ 0xa950, 0x00000001 },
|
||||
{ 0xa954, 0x00000004 },
|
||||
{ 0xa960, 0x00060000 },
|
||||
{ 0xaa3c, 0x00001c00 },
|
||||
{ 0xaa54, 0x00000004 },
|
||||
{ 0xaa60, 0x00060000 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct gt_powermeter ivb_pm_gt2[] = {
|
||||
{ 0xa800, 0x10000000 },
|
||||
{ 0xa804, 0x00033800 },
|
||||
{ 0xa808, 0x00000902 },
|
||||
{ 0xa80c, 0x0c002f00 },
|
||||
{ 0xa810, 0x12000400 },
|
||||
{ 0xa814, 0x00000000 },
|
||||
{ 0xa818, 0x00d20800 },
|
||||
{ 0xa81c, 0x00000002 },
|
||||
{ 0xa820, 0x03004b02 },
|
||||
{ 0xa824, 0x00000600 },
|
||||
{ 0xa828, 0x07000773 },
|
||||
{ 0xa82c, 0x00000000 },
|
||||
{ 0xa830, 0x00010032 },
|
||||
{ 0xa834, 0x1520040d },
|
||||
{ 0xa838, 0x00020105 },
|
||||
{ 0xa83c, 0x00083700 },
|
||||
{ 0xa840, 0x0000151d },
|
||||
{ 0xa844, 0x00000000 },
|
||||
{ 0xa848, 0x20001b00 },
|
||||
{ 0xa84c, 0x0a000010 },
|
||||
{ 0xa850, 0x00000000 },
|
||||
{ 0xa854, 0x00000008 },
|
||||
{ 0xa858, 0x00000008 },
|
||||
{ 0xa85c, 0x00000000 },
|
||||
{ 0xa860, 0x00020000 },
|
||||
{ 0xa248, 0x0000221e },
|
||||
{ 0xa900, 0x00000000 },
|
||||
{ 0xa904, 0x00003500 },
|
||||
{ 0xa908, 0x00000000 },
|
||||
{ 0xa90c, 0x0c000000 },
|
||||
{ 0xa910, 0x12000500 },
|
||||
{ 0xa914, 0x00000000 },
|
||||
{ 0xa918, 0x00b20000 },
|
||||
{ 0xa91c, 0x00000000 },
|
||||
{ 0xa920, 0x08004b02 },
|
||||
{ 0xa924, 0x00000200 },
|
||||
{ 0xa928, 0x07000820 },
|
||||
{ 0xa92c, 0x00000000 },
|
||||
{ 0xa930, 0x00030000 },
|
||||
{ 0xa934, 0x050f020d },
|
||||
{ 0xa938, 0x00020300 },
|
||||
{ 0xa93c, 0x00903900 },
|
||||
{ 0xa940, 0x00000000 },
|
||||
{ 0xa944, 0x00000000 },
|
||||
{ 0xa948, 0x20001b00 },
|
||||
{ 0xa94c, 0x0a000010 },
|
||||
{ 0xa950, 0x00000000 },
|
||||
{ 0xa954, 0x00000008 },
|
||||
{ 0xa960, 0x00110000 },
|
||||
{ 0xaa3c, 0x00003900 },
|
||||
{ 0xaa54, 0x00000008 },
|
||||
{ 0xaa60, 0x00110000 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct gt_powermeter ivb_pm_gt2_17w[] = {
|
||||
{ 0xa800, 0x20000000 },
|
||||
{ 0xa804, 0x000e3800 },
|
||||
{ 0xa808, 0x00000806 },
|
||||
{ 0xa80c, 0x0c002f00 },
|
||||
{ 0xa810, 0x0c000800 },
|
||||
{ 0xa814, 0x00000000 },
|
||||
{ 0xa818, 0x00d20d00 },
|
||||
{ 0xa81c, 0x000000ff },
|
||||
{ 0xa820, 0x03004b02 },
|
||||
{ 0xa824, 0x00000600 },
|
||||
{ 0xa828, 0x07000773 },
|
||||
{ 0xa82c, 0x00000000 },
|
||||
{ 0xa830, 0x00020032 },
|
||||
{ 0xa834, 0x1520040d },
|
||||
{ 0xa838, 0x00020105 },
|
||||
{ 0xa83c, 0x00083700 },
|
||||
{ 0xa840, 0x000016ff },
|
||||
{ 0xa844, 0x00000000 },
|
||||
{ 0xa848, 0xff000000 },
|
||||
{ 0xa84c, 0x0a000010 },
|
||||
{ 0xa850, 0x00000002 },
|
||||
{ 0xa854, 0x00000008 },
|
||||
{ 0xa858, 0x0000000f },
|
||||
{ 0xa85c, 0x00000000 },
|
||||
{ 0xa860, 0x00020000 },
|
||||
{ 0xa248, 0x0000221e },
|
||||
{ 0xa900, 0x00000000 },
|
||||
{ 0xa904, 0x00003800 },
|
||||
{ 0xa908, 0x00000000 },
|
||||
{ 0xa90c, 0x0c000000 },
|
||||
{ 0xa910, 0x12000800 },
|
||||
{ 0xa914, 0x00000000 },
|
||||
{ 0xa918, 0x00b20000 },
|
||||
{ 0xa91c, 0x00000000 },
|
||||
{ 0xa920, 0x08004b02 },
|
||||
{ 0xa924, 0x00000300 },
|
||||
{ 0xa928, 0x01000820 },
|
||||
{ 0xa92c, 0x00000000 },
|
||||
{ 0xa930, 0x00030000 },
|
||||
{ 0xa934, 0x15150406 },
|
||||
{ 0xa938, 0x00020300 },
|
||||
{ 0xa93c, 0x00903900 },
|
||||
{ 0xa940, 0x00000000 },
|
||||
{ 0xa944, 0x00000000 },
|
||||
{ 0xa948, 0x20001b00 },
|
||||
{ 0xa94c, 0x0a000010 },
|
||||
{ 0xa950, 0x00000000 },
|
||||
{ 0xa954, 0x00000008 },
|
||||
{ 0xa960, 0x00110000 },
|
||||
{ 0xaa3c, 0x00003900 },
|
||||
{ 0xaa54, 0x00000008 },
|
||||
{ 0xaa60, 0x00110000 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct gt_powermeter ivb_pm_gt2_35w[] = {
|
||||
{ 0xa800, 0x00000000 },
|
||||
{ 0xa804, 0x00030400 },
|
||||
{ 0xa808, 0x00000806 },
|
||||
{ 0xa80c, 0x0c002f00 },
|
||||
{ 0xa810, 0x0c000300 },
|
||||
{ 0xa814, 0x00000000 },
|
||||
{ 0xa818, 0x00d20d00 },
|
||||
{ 0xa81c, 0x000000ff },
|
||||
{ 0xa820, 0x03004b02 },
|
||||
{ 0xa824, 0x00000600 },
|
||||
{ 0xa828, 0x07000773 },
|
||||
{ 0xa82c, 0x00000000 },
|
||||
{ 0xa830, 0x00020032 },
|
||||
{ 0xa834, 0x1520040d },
|
||||
{ 0xa838, 0x00020105 },
|
||||
{ 0xa83c, 0x00083700 },
|
||||
{ 0xa840, 0x000016ff },
|
||||
{ 0xa844, 0x00000000 },
|
||||
{ 0xa848, 0xff000000 },
|
||||
{ 0xa84c, 0x0a000010 },
|
||||
{ 0xa850, 0x00000001 },
|
||||
{ 0xa854, 0x00000008 },
|
||||
{ 0xa858, 0x00000008 },
|
||||
{ 0xa85c, 0x00000000 },
|
||||
{ 0xa860, 0x00020000 },
|
||||
{ 0xa248, 0x0000221e },
|
||||
{ 0xa900, 0x00000000 },
|
||||
{ 0xa904, 0x00003800 },
|
||||
{ 0xa908, 0x00000000 },
|
||||
{ 0xa90c, 0x0c000000 },
|
||||
{ 0xa910, 0x12000800 },
|
||||
{ 0xa914, 0x00000000 },
|
||||
{ 0xa918, 0x00b20000 },
|
||||
{ 0xa91c, 0x00000000 },
|
||||
{ 0xa920, 0x08004b02 },
|
||||
{ 0xa924, 0x00000300 },
|
||||
{ 0xa928, 0x01000820 },
|
||||
{ 0xa92c, 0x00000000 },
|
||||
{ 0xa930, 0x00030000 },
|
||||
{ 0xa934, 0x15150406 },
|
||||
{ 0xa938, 0x00020300 },
|
||||
{ 0xa93c, 0x00903900 },
|
||||
{ 0xa940, 0x00000000 },
|
||||
{ 0xa944, 0x00000000 },
|
||||
{ 0xa948, 0x20001b00 },
|
||||
{ 0xa94c, 0x0a000010 },
|
||||
{ 0xa950, 0x00000000 },
|
||||
{ 0xa954, 0x00000008 },
|
||||
{ 0xa960, 0x00110000 },
|
||||
{ 0xaa3c, 0x00003900 },
|
||||
{ 0xaa54, 0x00000008 },
|
||||
{ 0xaa60, 0x00110000 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Some vga option roms are used for several chipsets but they only have one
|
||||
* PCI ID in their header. If we encounter such an option rom, we need to do
|
||||
* the mapping ourselves.
|
||||
*/
|
||||
|
||||
u32 map_oprom_vendev(u32 vendev)
|
||||
{
|
||||
u32 new_vendev = vendev;
|
||||
|
||||
switch (vendev) {
|
||||
case 0x80860102: /* GT1 Desktop */
|
||||
case 0x8086010a: /* GT1 Server */
|
||||
case 0x80860112: /* GT2 Desktop */
|
||||
case 0x80860116: /* GT2 Mobile */
|
||||
case 0x80860122: /* GT2 Desktop >=1.3GHz */
|
||||
case 0x80860126: /* GT2 Mobile >=1.3GHz */
|
||||
case 0x80860156: /* IVB */
|
||||
case 0x80860166: /* IVB */
|
||||
/* Set to GT1 Mobile */
|
||||
new_vendev = 0x80860106;
|
||||
break;
|
||||
}
|
||||
|
||||
return new_vendev;
|
||||
}
|
||||
|
||||
static inline u32 gtt_read(void *bar, u32 reg)
|
||||
{
|
||||
return readl(bar + reg);
|
||||
}
|
||||
|
||||
static inline void gtt_write(void *bar, u32 reg, u32 data)
|
||||
{
|
||||
writel(data, bar + reg);
|
||||
}
|
||||
|
||||
static void gtt_write_powermeter(void *bar, const struct gt_powermeter *pm)
|
||||
{
|
||||
for (; pm && pm->reg; pm++)
|
||||
gtt_write(bar, pm->reg, pm->value);
|
||||
}
|
||||
|
||||
#define GTT_RETRY 1000
|
||||
static int gtt_poll(void *bar, u32 reg, u32 mask, u32 value)
|
||||
{
|
||||
unsigned try = GTT_RETRY;
|
||||
u32 data;
|
||||
|
||||
while (try--) {
|
||||
data = gtt_read(bar, reg);
|
||||
if ((data & mask) == value)
|
||||
return 1;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
printf("GT init timeout\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gma_pm_init_pre_vbios(void *gtt_bar, int rev)
|
||||
{
|
||||
u32 reg32;
|
||||
|
||||
debug("GT Power Management Init, silicon = %#x\n", rev);
|
||||
|
||||
if (rev < IVB_STEP_C0) {
|
||||
/* 1: Enable force wake */
|
||||
gtt_write(gtt_bar, 0xa18c, 0x00000001);
|
||||
gtt_poll(gtt_bar, 0x130090, (1 << 0), (1 << 0));
|
||||
} else {
|
||||
gtt_write(gtt_bar, 0xa180, 1 << 5);
|
||||
gtt_write(gtt_bar, 0xa188, 0xffff0001);
|
||||
gtt_poll(gtt_bar, 0x130040, (1 << 0), (1 << 0));
|
||||
}
|
||||
|
||||
if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
|
||||
/* 1d: Set GTT+0x42004 [15:14]=11 (SnB C1+) */
|
||||
reg32 = gtt_read(gtt_bar, 0x42004);
|
||||
reg32 |= (1 << 14) | (1 << 15);
|
||||
gtt_write(gtt_bar, 0x42004, reg32);
|
||||
}
|
||||
|
||||
if (rev >= IVB_STEP_A0) {
|
||||
/* Display Reset Acknowledge Settings */
|
||||
reg32 = gtt_read(gtt_bar, 0x45010);
|
||||
reg32 |= (1 << 1) | (1 << 0);
|
||||
gtt_write(gtt_bar, 0x45010, reg32);
|
||||
}
|
||||
|
||||
/* 2: Get GT SKU from GTT+0x911c[13] */
|
||||
reg32 = gtt_read(gtt_bar, 0x911c);
|
||||
if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
|
||||
if (reg32 & (1 << 13)) {
|
||||
debug("SNB GT1 Power Meter Weights\n");
|
||||
gtt_write_powermeter(gtt_bar, snb_pm_gt1);
|
||||
} else {
|
||||
debug("SNB GT2 Power Meter Weights\n");
|
||||
gtt_write_powermeter(gtt_bar, snb_pm_gt2);
|
||||
}
|
||||
} else {
|
||||
u32 unit = readl(MCHBAR_REG(0x5938)) & 0xf;
|
||||
|
||||
if (reg32 & (1 << 13)) {
|
||||
/* GT1 SKU */
|
||||
debug("IVB GT1 Power Meter Weights\n");
|
||||
gtt_write_powermeter(gtt_bar, ivb_pm_gt1);
|
||||
} else {
|
||||
/* GT2 SKU */
|
||||
u32 tdp = readl(MCHBAR_REG(0x5930)) & 0x7fff;
|
||||
tdp /= (1 << unit);
|
||||
|
||||
if (tdp <= 17) {
|
||||
/* <=17W ULV */
|
||||
debug("IVB GT2 17W Power Meter Weights\n");
|
||||
gtt_write_powermeter(gtt_bar, ivb_pm_gt2_17w);
|
||||
} else if ((tdp >= 25) && (tdp <= 35)) {
|
||||
/* 25W-35W */
|
||||
debug("IVB GT2 25W-35W Power Meter Weights\n");
|
||||
gtt_write_powermeter(gtt_bar, ivb_pm_gt2_35w);
|
||||
} else {
|
||||
/* All others */
|
||||
debug("IVB GT2 35W Power Meter Weights\n");
|
||||
gtt_write_powermeter(gtt_bar, ivb_pm_gt2_35w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 3: Gear ratio map */
|
||||
gtt_write(gtt_bar, 0xa004, 0x00000010);
|
||||
|
||||
/* 4: GFXPAUSE */
|
||||
gtt_write(gtt_bar, 0xa000, 0x00070020);
|
||||
|
||||
/* 5: Dynamic EU trip control */
|
||||
gtt_write(gtt_bar, 0xa080, 0x00000004);
|
||||
|
||||
/* 6: ECO bits */
|
||||
reg32 = gtt_read(gtt_bar, 0xa180);
|
||||
reg32 |= (1 << 26) | (1 << 31);
|
||||
/* (bit 20=1 for SNB step D1+ / IVB A0+) */
|
||||
if (rev >= SNB_STEP_D1)
|
||||
reg32 |= (1 << 20);
|
||||
gtt_write(gtt_bar, 0xa180, reg32);
|
||||
|
||||
/* 6a: for SnB step D2+ only */
|
||||
if (((rev & BASE_REV_MASK) == BASE_REV_SNB) &&
|
||||
(rev >= SNB_STEP_D2)) {
|
||||
reg32 = gtt_read(gtt_bar, 0x9400);
|
||||
reg32 |= (1 << 7);
|
||||
gtt_write(gtt_bar, 0x9400, reg32);
|
||||
|
||||
reg32 = gtt_read(gtt_bar, 0x941c);
|
||||
reg32 &= 0xf;
|
||||
reg32 |= (1 << 1);
|
||||
gtt_write(gtt_bar, 0x941c, reg32);
|
||||
gtt_poll(gtt_bar, 0x941c, (1 << 1), (0 << 1));
|
||||
}
|
||||
|
||||
if ((rev & BASE_REV_MASK) == BASE_REV_IVB) {
|
||||
reg32 = gtt_read(gtt_bar, 0x907c);
|
||||
reg32 |= (1 << 16);
|
||||
gtt_write(gtt_bar, 0x907c, reg32);
|
||||
|
||||
/* 6b: Clocking reset controls */
|
||||
gtt_write(gtt_bar, 0x9424, 0x00000001);
|
||||
} else {
|
||||
/* 6b: Clocking reset controls */
|
||||
gtt_write(gtt_bar, 0x9424, 0x00000000);
|
||||
}
|
||||
|
||||
/* 7 */
|
||||
if (gtt_poll(gtt_bar, 0x138124, (1 << 31), (0 << 31))) {
|
||||
gtt_write(gtt_bar, 0x138128, 0x00000029); /* Mailbox Data */
|
||||
/* Mailbox Cmd for RC6 VID */
|
||||
gtt_write(gtt_bar, 0x138124, 0x80000004);
|
||||
if (gtt_poll(gtt_bar, 0x138124, (1 << 31), (0 << 31)))
|
||||
gtt_write(gtt_bar, 0x138124, 0x8000000a);
|
||||
gtt_poll(gtt_bar, 0x138124, (1 << 31), (0 << 31));
|
||||
}
|
||||
|
||||
/* 8 */
|
||||
gtt_write(gtt_bar, 0xa090, 0x00000000); /* RC Control */
|
||||
gtt_write(gtt_bar, 0xa098, 0x03e80000); /* RC1e Wake Rate Limit */
|
||||
gtt_write(gtt_bar, 0xa09c, 0x0028001e); /* RC6/6p Wake Rate Limit */
|
||||
gtt_write(gtt_bar, 0xa0a0, 0x0000001e); /* RC6pp Wake Rate Limit */
|
||||
gtt_write(gtt_bar, 0xa0a8, 0x0001e848); /* RC Evaluation Interval */
|
||||
gtt_write(gtt_bar, 0xa0ac, 0x00000019); /* RC Idle Hysteresis */
|
||||
|
||||
/* 9 */
|
||||
gtt_write(gtt_bar, 0x2054, 0x0000000a); /* Render Idle Max Count */
|
||||
gtt_write(gtt_bar, 0x12054, 0x0000000a); /* Video Idle Max Count */
|
||||
gtt_write(gtt_bar, 0x22054, 0x0000000a); /* Blitter Idle Max Count */
|
||||
|
||||
/* 10 */
|
||||
gtt_write(gtt_bar, 0xa0b0, 0x00000000); /* Unblock Ack to Busy */
|
||||
gtt_write(gtt_bar, 0xa0b4, 0x000003e8); /* RC1e Threshold */
|
||||
gtt_write(gtt_bar, 0xa0b8, 0x0000c350); /* RC6 Threshold */
|
||||
gtt_write(gtt_bar, 0xa0bc, 0x000186a0); /* RC6p Threshold */
|
||||
gtt_write(gtt_bar, 0xa0c0, 0x0000fa00); /* RC6pp Threshold */
|
||||
|
||||
/* 11 */
|
||||
gtt_write(gtt_bar, 0xa010, 0x000f4240); /* RP Down Timeout */
|
||||
gtt_write(gtt_bar, 0xa014, 0x12060000); /* RP Interrupt Limits */
|
||||
gtt_write(gtt_bar, 0xa02c, 0x00015f90); /* RP Up Threshold */
|
||||
gtt_write(gtt_bar, 0xa030, 0x000186a0); /* RP Down Threshold */
|
||||
gtt_write(gtt_bar, 0xa068, 0x000186a0); /* RP Up EI */
|
||||
gtt_write(gtt_bar, 0xa06c, 0x000493e0); /* RP Down EI */
|
||||
gtt_write(gtt_bar, 0xa070, 0x0000000a); /* RP Idle Hysteresis */
|
||||
|
||||
/* 11a: Enable Render Standby (RC6) */
|
||||
if ((rev & BASE_REV_MASK) == BASE_REV_IVB) {
|
||||
/*
|
||||
* IvyBridge should also support DeepRenderStandby.
|
||||
*
|
||||
* Unfortunately it does not work reliably on all SKUs so
|
||||
* disable it here and it can be enabled by the kernel.
|
||||
*/
|
||||
gtt_write(gtt_bar, 0xa090, 0x88040000); /* HW RC Control */
|
||||
} else {
|
||||
gtt_write(gtt_bar, 0xa090, 0x88040000); /* HW RC Control */
|
||||
}
|
||||
|
||||
/* 12: Normal Frequency Request */
|
||||
/* RPNFREQ_VAL comes from MCHBAR 0x5998 23:16 (8 bits!? use 7) */
|
||||
reg32 = readl(MCHBAR_REG(0x5998));
|
||||
reg32 >>= 16;
|
||||
reg32 &= 0xef;
|
||||
reg32 <<= 25;
|
||||
gtt_write(gtt_bar, 0xa008, reg32);
|
||||
|
||||
/* 13: RP Control */
|
||||
gtt_write(gtt_bar, 0xa024, 0x00000592);
|
||||
|
||||
/* 14: Enable PM Interrupts */
|
||||
gtt_write(gtt_bar, 0x4402c, 0x03000076);
|
||||
|
||||
/* Clear 0x6c024 [8:6] */
|
||||
reg32 = gtt_read(gtt_bar, 0x6c024);
|
||||
reg32 &= ~0x000001c0;
|
||||
gtt_write(gtt_bar, 0x6c024, reg32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gma_pm_init_post_vbios(struct udevice *dev, int rev, void *gtt_bar)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
u32 reg32, cycle_delay;
|
||||
|
||||
debug("GT Power Management Init (post VBIOS)\n");
|
||||
|
||||
/* 15: Deassert Force Wake */
|
||||
if (rev < IVB_STEP_C0) {
|
||||
gtt_write(gtt_bar, 0xa18c, gtt_read(gtt_bar, 0xa18c) & ~1);
|
||||
gtt_poll(gtt_bar, 0x130090, (1 << 0), (0 << 0));
|
||||
} else {
|
||||
gtt_write(gtt_bar, 0xa188, 0x1fffe);
|
||||
if (gtt_poll(gtt_bar, 0x130040, (1 << 0), (0 << 0))) {
|
||||
gtt_write(gtt_bar, 0xa188,
|
||||
gtt_read(gtt_bar, 0xa188) | 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 16: SW RC Control */
|
||||
gtt_write(gtt_bar, 0xa094, 0x00060000);
|
||||
|
||||
/* Setup Digital Port Hotplug */
|
||||
reg32 = gtt_read(gtt_bar, 0xc4030);
|
||||
if (!reg32) {
|
||||
u32 dp_hotplug[3];
|
||||
|
||||
if (fdtdec_get_int_array(blob, node, "intel,dp_hotplug",
|
||||
dp_hotplug, ARRAY_SIZE(dp_hotplug)))
|
||||
return -EINVAL;
|
||||
|
||||
reg32 = (dp_hotplug[0] & 0x7) << 2;
|
||||
reg32 |= (dp_hotplug[0] & 0x7) << 10;
|
||||
reg32 |= (dp_hotplug[0] & 0x7) << 18;
|
||||
gtt_write(gtt_bar, 0xc4030, reg32);
|
||||
}
|
||||
|
||||
/* Setup Panel Power On Delays */
|
||||
reg32 = gtt_read(gtt_bar, 0xc7208);
|
||||
if (!reg32) {
|
||||
reg32 = (unsigned)fdtdec_get_int(blob, node,
|
||||
"panel-port-select", 0) << 30;
|
||||
reg32 |= fdtdec_get_int(blob, node, "panel-power-up-delay", 0)
|
||||
<< 16;
|
||||
reg32 |= fdtdec_get_int(blob, node,
|
||||
"panel-power-backlight-on-delay", 0);
|
||||
gtt_write(gtt_bar, 0xc7208, reg32);
|
||||
}
|
||||
|
||||
/* Setup Panel Power Off Delays */
|
||||
reg32 = gtt_read(gtt_bar, 0xc720c);
|
||||
if (!reg32) {
|
||||
reg32 = fdtdec_get_int(blob, node, "panel-power-down-delay", 0)
|
||||
<< 16;
|
||||
reg32 |= fdtdec_get_int(blob, node,
|
||||
"panel-power-backlight-off-delay", 0);
|
||||
gtt_write(gtt_bar, 0xc720c, reg32);
|
||||
}
|
||||
|
||||
/* Setup Panel Power Cycle Delay */
|
||||
cycle_delay = fdtdec_get_int(blob, node,
|
||||
"intel,panel-power-cycle-delay", 0);
|
||||
if (cycle_delay) {
|
||||
reg32 = gtt_read(gtt_bar, 0xc7210);
|
||||
reg32 &= ~0xff;
|
||||
reg32 |= cycle_delay;
|
||||
gtt_write(gtt_bar, 0xc7210, reg32);
|
||||
}
|
||||
|
||||
/* Enable Backlight if needed */
|
||||
reg32 = fdtdec_get_int(blob, node, "intel,cpu-backlight", 0);
|
||||
if (reg32) {
|
||||
gtt_write(gtt_bar, 0x48250, (1 << 31));
|
||||
gtt_write(gtt_bar, 0x48254, reg32);
|
||||
}
|
||||
reg32 = fdtdec_get_int(blob, node, "intel,pch-backlight", 0);
|
||||
if (reg32) {
|
||||
gtt_write(gtt_bar, 0xc8250, (1 << 31));
|
||||
gtt_write(gtt_bar, 0xc8254, reg32);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some vga option roms are used for several chipsets but they only have one
|
||||
* PCI ID in their header. If we encounter such an option rom, we need to do
|
||||
* the mapping ourselves.
|
||||
*/
|
||||
|
||||
uint32_t board_map_oprom_vendev(uint32_t vendev)
|
||||
{
|
||||
switch (vendev) {
|
||||
case 0x80860102: /* GT1 Desktop */
|
||||
case 0x8086010a: /* GT1 Server */
|
||||
case 0x80860112: /* GT2 Desktop */
|
||||
case 0x80860116: /* GT2 Mobile */
|
||||
case 0x80860122: /* GT2 Desktop >=1.3GHz */
|
||||
case 0x80860126: /* GT2 Mobile >=1.3GHz */
|
||||
case 0x80860156: /* IVB */
|
||||
case 0x80860166: /* IVB */
|
||||
return 0x80860106; /* GT1 Mobile */
|
||||
}
|
||||
|
||||
return vendev;
|
||||
}
|
||||
|
||||
static int int15_handler(void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
debug("%s: INT15 function %04x!\n", __func__, M.x86.R_AX);
|
||||
|
||||
switch (M.x86.R_AX) {
|
||||
case 0x5f34:
|
||||
/*
|
||||
* Set Panel Fitting Hook:
|
||||
* bit 2 = Graphics Stretching
|
||||
* bit 1 = Text Stretching
|
||||
* bit 0 = Centering (do not set with bit1 or bit2)
|
||||
* 0 = video bios default
|
||||
*/
|
||||
M.x86.R_AX = 0x005f;
|
||||
M.x86.R_CL = 0x00; /* Use video bios default */
|
||||
res = 1;
|
||||
break;
|
||||
case 0x5f35:
|
||||
/*
|
||||
* Boot Display Device Hook:
|
||||
* bit 0 = CRT
|
||||
* bit 1 = TV (eDP)
|
||||
* bit 2 = EFP
|
||||
* bit 3 = LFP
|
||||
* bit 4 = CRT2
|
||||
* bit 5 = TV2 (eDP)
|
||||
* bit 6 = EFP2
|
||||
* bit 7 = LFP2
|
||||
*/
|
||||
M.x86.R_AX = 0x005f;
|
||||
M.x86.R_CX = 0x0000; /* Use video bios default */
|
||||
res = 1;
|
||||
break;
|
||||
case 0x5f51:
|
||||
/*
|
||||
* Hook to select active LFP configuration:
|
||||
* 00h = No LVDS, VBIOS does not enable LVDS
|
||||
* 01h = Int-LVDS, LFP driven by integrated LVDS decoder
|
||||
* 02h = SVDO-LVDS, LFP driven by SVDO decoder
|
||||
* 03h = eDP, LFP Driven by Int-DisplayPort encoder
|
||||
*/
|
||||
M.x86.R_AX = 0x005f;
|
||||
M.x86.R_CX = 0x0003; /* eDP */
|
||||
res = 1;
|
||||
break;
|
||||
case 0x5f70:
|
||||
switch (M.x86.R_CH) {
|
||||
case 0:
|
||||
/* Get Mux */
|
||||
M.x86.R_AX = 0x005f;
|
||||
M.x86.R_CX = 0x0000;
|
||||
res = 1;
|
||||
break;
|
||||
case 1:
|
||||
/* Set Mux */
|
||||
M.x86.R_AX = 0x005f;
|
||||
M.x86.R_CX = 0x0000;
|
||||
res = 1;
|
||||
break;
|
||||
case 2:
|
||||
/* Get SG/Non-SG mode */
|
||||
M.x86.R_AX = 0x005f;
|
||||
M.x86.R_CX = 0x0000;
|
||||
res = 1;
|
||||
break;
|
||||
default:
|
||||
/* Interrupt was not handled */
|
||||
debug("Unknown INT15 5f70 function: 0x%02x\n",
|
||||
M.x86.R_CH);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x5fac:
|
||||
res = 1;
|
||||
break;
|
||||
default:
|
||||
debug("Unknown INT15 function %04x!\n", M.x86.R_AX);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void sandybridge_setup_graphics(struct udevice *dev, struct udevice *video_dev)
|
||||
{
|
||||
u32 reg32;
|
||||
u16 reg16;
|
||||
u8 reg8;
|
||||
|
||||
dm_pci_read_config16(video_dev, PCI_DEVICE_ID, ®16);
|
||||
switch (reg16) {
|
||||
case 0x0102: /* GT1 Desktop */
|
||||
case 0x0106: /* GT1 Mobile */
|
||||
case 0x010a: /* GT1 Server */
|
||||
case 0x0112: /* GT2 Desktop */
|
||||
case 0x0116: /* GT2 Mobile */
|
||||
case 0x0122: /* GT2 Desktop >=1.3GHz */
|
||||
case 0x0126: /* GT2 Mobile >=1.3GHz */
|
||||
case 0x0156: /* IvyBridge */
|
||||
case 0x0166: /* IvyBridge */
|
||||
break;
|
||||
default:
|
||||
debug("Graphics not supported by this CPU/chipset\n");
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Initialising Graphics\n");
|
||||
|
||||
/* Setup IGD memory by setting GGC[7:3] = 1 for 32MB */
|
||||
dm_pci_read_config16(dev, GGC, ®16);
|
||||
reg16 &= ~0x00f8;
|
||||
reg16 |= 1 << 3;
|
||||
/* Program GTT memory by setting GGC[9:8] = 2MB */
|
||||
reg16 &= ~0x0300;
|
||||
reg16 |= 2 << 8;
|
||||
/* Enable VGA decode */
|
||||
reg16 &= ~0x0002;
|
||||
dm_pci_write_config16(dev, GGC, reg16);
|
||||
|
||||
/* Enable 256MB aperture */
|
||||
dm_pci_read_config8(video_dev, MSAC, ®8);
|
||||
reg8 &= ~0x06;
|
||||
reg8 |= 0x02;
|
||||
dm_pci_write_config8(video_dev, MSAC, reg8);
|
||||
|
||||
/* Erratum workarounds */
|
||||
reg32 = readl(MCHBAR_REG(0x5f00));
|
||||
reg32 |= (1 << 9) | (1 << 10);
|
||||
writel(reg32, MCHBAR_REG(0x5f00));
|
||||
|
||||
/* Enable SA Clock Gating */
|
||||
reg32 = readl(MCHBAR_REG(0x5f00));
|
||||
writel(reg32 | 1, MCHBAR_REG(0x5f00));
|
||||
|
||||
/* GPU RC6 workaround for sighting 366252 */
|
||||
reg32 = readl(MCHBAR_REG(0x5d14));
|
||||
reg32 |= (1 << 31);
|
||||
writel(reg32, MCHBAR_REG(0x5d14));
|
||||
|
||||
/* VLW */
|
||||
reg32 = readl(MCHBAR_REG(0x6120));
|
||||
reg32 &= ~(1 << 0);
|
||||
writel(reg32, MCHBAR_REG(0x6120));
|
||||
|
||||
reg32 = readl(MCHBAR_REG(0x5418));
|
||||
reg32 |= (1 << 4) | (1 << 5);
|
||||
writel(reg32, MCHBAR_REG(0x5418));
|
||||
}
|
||||
|
||||
int gma_func0_init(struct udevice *dev)
|
||||
{
|
||||
#ifdef CONFIG_VIDEO
|
||||
ulong start;
|
||||
#endif
|
||||
struct udevice *nbridge;
|
||||
void *gtt_bar;
|
||||
ulong base;
|
||||
u32 reg32;
|
||||
int ret;
|
||||
int rev;
|
||||
|
||||
/* Enable PCH Display Port */
|
||||
writew(0x0010, RCB_REG(DISPBDF));
|
||||
setbits_le32(RCB_REG(FD2), PCH_ENABLE_DBDF);
|
||||
|
||||
ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &nbridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
rev = bridge_silicon_revision(nbridge);
|
||||
sandybridge_setup_graphics(nbridge, dev);
|
||||
|
||||
/* IGD needs to be Bus Master */
|
||||
dm_pci_read_config32(dev, PCI_COMMAND, ®32);
|
||||
reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
|
||||
dm_pci_write_config32(dev, PCI_COMMAND, reg32);
|
||||
|
||||
/* Use write-combining for the graphics memory, 256MB */
|
||||
base = dm_pci_read_bar32(dev, 2);
|
||||
mtrr_add_request(MTRR_TYPE_WRCOMB, base, 256 << 20);
|
||||
mtrr_commit(true);
|
||||
|
||||
gtt_bar = (void *)dm_pci_read_bar32(dev, 0);
|
||||
debug("GT bar %p\n", gtt_bar);
|
||||
ret = gma_pm_init_pre_vbios(gtt_bar, rev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_VIDEO
|
||||
start = get_timer(0);
|
||||
ret = dm_pci_run_vga_bios(dev, int15_handler,
|
||||
PCI_ROM_USE_NATIVE | PCI_ROM_ALLOW_FALLBACK);
|
||||
debug("BIOS ran in %lums\n", get_timer(start));
|
||||
#endif
|
||||
/* Post VBIOS init */
|
||||
ret = gma_pm_init_post_vbios(dev, rev, gtt_bar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
156
u-boot/arch/x86/cpu/ivybridge/gma.h
Normal file
156
u-boot/arch/x86/cpu/ivybridge/gma.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* From Coreboot file of the same name
|
||||
*
|
||||
* Copyright (C) 2012 Chromium OS Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
/* mailbox 0: header */
|
||||
__packed struct opregion_header {
|
||||
u8 signature[16];
|
||||
u32 size;
|
||||
u32 version;
|
||||
u8 sbios_version[32];
|
||||
u8 vbios_version[16];
|
||||
u8 driver_version[16];
|
||||
u32 mailboxes;
|
||||
u8 reserved[164];
|
||||
};
|
||||
|
||||
#define IGD_OPREGION_SIGNATURE "IntelGraphicsMem"
|
||||
#define IGD_OPREGION_VERSION 2
|
||||
|
||||
#define IGD_MBOX1 (1 << 0)
|
||||
#define IGD_MBOX2 (1 << 1)
|
||||
#define IGD_MBOX3 (1 << 2)
|
||||
#define IGD_MBOX4 (1 << 3)
|
||||
#define IGD_MBOX5 (1 << 4)
|
||||
|
||||
#define MAILBOXES_MOBILE (IGD_MBOX1 | IGD_MBOX2 | IGD_MBOX3 | \
|
||||
IGD_MBOX4 | IGD_MBOX5)
|
||||
#define MAILBOXES_DESKTOP (IGD_MBOX2 | IGD_MBOX4)
|
||||
|
||||
#define SBIOS_VERSION_SIZE 32
|
||||
|
||||
/* mailbox 1: public acpi methods */
|
||||
__packed struct opregion_mailbox1 {
|
||||
u32 drdy;
|
||||
u32 csts;
|
||||
u32 cevt;
|
||||
u8 reserved1[20];
|
||||
u32 didl[8];
|
||||
u32 cpdl[8];
|
||||
u32 cadl[8];
|
||||
u32 nadl[8];
|
||||
u32 aslp;
|
||||
u32 tidx;
|
||||
u32 chpd;
|
||||
u32 clid;
|
||||
u32 cdck;
|
||||
u32 sxsw;
|
||||
u32 evts;
|
||||
u32 cnot;
|
||||
u32 nrdy;
|
||||
u8 reserved2[60];
|
||||
};
|
||||
|
||||
/* mailbox 2: software sci interface */
|
||||
__packed struct opregion_mailbox2 {
|
||||
u32 scic;
|
||||
u32 parm;
|
||||
u32 dslp;
|
||||
u8 reserved[244];
|
||||
};
|
||||
|
||||
/* mailbox 3: power conservation */
|
||||
__packed struct opregion_mailbox3 {
|
||||
u32 ardy;
|
||||
u32 aslc;
|
||||
u32 tche;
|
||||
u32 alsi;
|
||||
u32 bclp;
|
||||
u32 pfit;
|
||||
u32 cblv;
|
||||
u16 bclm[20];
|
||||
u32 cpfm;
|
||||
u32 epfm;
|
||||
u8 plut[74];
|
||||
u32 pfmb;
|
||||
u32 ccdv;
|
||||
u32 pcft;
|
||||
u8 reserved[94];
|
||||
};
|
||||
|
||||
#define IGD_BACKLIGHT_BRIGHTNESS 0xff
|
||||
#define IGD_INITIAL_BRIGHTNESS 0x64
|
||||
|
||||
#define IGD_FIELD_VALID (1 << 31)
|
||||
#define IGD_WORD_FIELD_VALID (1 << 15)
|
||||
#define IGD_PFIT_STRETCH 6
|
||||
|
||||
/* mailbox 4: vbt */
|
||||
__packed struct {
|
||||
u8 gvd1[7168];
|
||||
} opregion_vbt_t;
|
||||
|
||||
/* IGD OpRegion */
|
||||
__packed struct igd_opregion {
|
||||
opregion_header_t header;
|
||||
opregion_mailbox1_t mailbox1;
|
||||
opregion_mailbox2_t mailbox2;
|
||||
opregion_mailbox3_t mailbox3;
|
||||
opregion_vbt_t vbt;
|
||||
};
|
||||
|
||||
/* Intel Video BIOS (Option ROM) */
|
||||
__packed struct optionrom_header {
|
||||
u16 signature;
|
||||
u8 size;
|
||||
u8 reserved[21];
|
||||
u16 pcir_offset;
|
||||
u16 vbt_offset;
|
||||
};
|
||||
|
||||
#define OPROM_SIGNATURE 0xaa55
|
||||
|
||||
__packed struct optionrom_pcir {
|
||||
u32 signature;
|
||||
u16 vendor;
|
||||
u16 device;
|
||||
u16 reserved1;
|
||||
u16 length;
|
||||
u8 revision;
|
||||
u8 classcode[3];
|
||||
u16 imagelength;
|
||||
u16 coderevision;
|
||||
u8 codetype;
|
||||
u8 indicator;
|
||||
u16 reserved2;
|
||||
};
|
||||
|
||||
__packed struct optionrom_vbt {
|
||||
u8 hdr_signature[20];
|
||||
u16 hdr_version;
|
||||
u16 hdr_size;
|
||||
u16 hdr_vbt_size;
|
||||
u8 hdr_vbt_checksum;
|
||||
u8 hdr_reserved;
|
||||
u32 hdr_vbt_datablock;
|
||||
u32 hdr_aim[4];
|
||||
u8 datahdr_signature[16];
|
||||
u16 datahdr_version;
|
||||
u16 datahdr_size;
|
||||
u16 datahdr_datablocksize;
|
||||
u8 coreblock_id;
|
||||
u16 coreblock_size;
|
||||
u16 coreblock_biossize;
|
||||
u8 coreblock_biostype;
|
||||
u8 coreblock_releasestatus;
|
||||
u8 coreblock_hwsupported;
|
||||
u8 coreblock_integratedhw;
|
||||
u8 coreblock_biosbuild[4];
|
||||
u8 coreblock_biossignon[155];
|
||||
};
|
||||
|
||||
#define VBT_SIGNATURE 0x54425624
|
||||
22
u-boot/arch/x86/cpu/ivybridge/ivybridge.c
Normal file
22
u-boot/arch/x86/cpu/ivybridge/ivybridge.c
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
post_code(POST_CPU_INIT);
|
||||
|
||||
ret = x86_cpu_init_f();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
534
u-boot/arch/x86/cpu/ivybridge/lpc.c
Normal file
534
u-boot/arch/x86/cpu/ivybridge/lpc.c
Normal file
@@ -0,0 +1,534 @@
|
||||
/*
|
||||
* From coreboot southbridge/intel/bd82x6x/lpc.c
|
||||
*
|
||||
* Copyright (C) 2008-2009 coresystems GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <rtc.h>
|
||||
#include <pci.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/ioapic.h>
|
||||
#include <asm/lpc_common.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/arch/pch.h>
|
||||
|
||||
#define NMI_OFF 0
|
||||
|
||||
#define ENABLE_ACPI_MODE_IN_COREBOOT 0
|
||||
#define TEST_SMM_FLASH_LOCKDOWN 0
|
||||
|
||||
static int pch_enable_apic(struct udevice *pch)
|
||||
{
|
||||
u32 reg32;
|
||||
int i;
|
||||
|
||||
/* Enable ACPI I/O and power management. Set SCI IRQ to IRQ9 */
|
||||
dm_pci_write_config8(pch, ACPI_CNTL, 0x80);
|
||||
|
||||
writel(0, IO_APIC_INDEX);
|
||||
writel(1 << 25, IO_APIC_DATA);
|
||||
|
||||
/* affirm full set of redirection table entries ("write once") */
|
||||
writel(1, IO_APIC_INDEX);
|
||||
reg32 = readl(IO_APIC_DATA);
|
||||
writel(1, IO_APIC_INDEX);
|
||||
writel(reg32, IO_APIC_DATA);
|
||||
|
||||
writel(0, IO_APIC_INDEX);
|
||||
reg32 = readl(IO_APIC_DATA);
|
||||
debug("PCH APIC ID = %x\n", (reg32 >> 24) & 0x0f);
|
||||
if (reg32 != (1 << 25)) {
|
||||
printf("APIC Error - cannot write to registers\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
debug("Dumping IOAPIC registers\n");
|
||||
for (i = 0; i < 3; i++) {
|
||||
writel(i, IO_APIC_INDEX);
|
||||
debug(" reg 0x%04x:", i);
|
||||
reg32 = readl(IO_APIC_DATA);
|
||||
debug(" 0x%08x\n", reg32);
|
||||
}
|
||||
|
||||
/* Select Boot Configuration register. */
|
||||
writel(3, IO_APIC_INDEX);
|
||||
|
||||
/* Use Processor System Bus to deliver interrupts. */
|
||||
writel(1, IO_APIC_DATA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pch_enable_serial_irqs(struct udevice *pch)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
/* Set packet length and toggle silent mode bit for one frame. */
|
||||
value = (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0);
|
||||
#ifdef CONFIG_SERIRQ_CONTINUOUS_MODE
|
||||
dm_pci_write_config8(pch, SERIRQ_CNTL, value);
|
||||
#else
|
||||
dm_pci_write_config8(pch, SERIRQ_CNTL, value | (1 << 6));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int pch_pirq_init(struct udevice *pch)
|
||||
{
|
||||
uint8_t route[8], *ptr;
|
||||
|
||||
if (fdtdec_get_byte_array(gd->fdt_blob, pch->of_offset,
|
||||
"intel,pirq-routing", route, sizeof(route)))
|
||||
return -EINVAL;
|
||||
ptr = route;
|
||||
dm_pci_write_config8(pch, PIRQA_ROUT, *ptr++);
|
||||
dm_pci_write_config8(pch, PIRQB_ROUT, *ptr++);
|
||||
dm_pci_write_config8(pch, PIRQC_ROUT, *ptr++);
|
||||
dm_pci_write_config8(pch, PIRQD_ROUT, *ptr++);
|
||||
|
||||
dm_pci_write_config8(pch, PIRQE_ROUT, *ptr++);
|
||||
dm_pci_write_config8(pch, PIRQF_ROUT, *ptr++);
|
||||
dm_pci_write_config8(pch, PIRQG_ROUT, *ptr++);
|
||||
dm_pci_write_config8(pch, PIRQH_ROUT, *ptr++);
|
||||
|
||||
/*
|
||||
* TODO(sjg@chromium.org): U-Boot does not set up the interrupts
|
||||
* here. It's unclear if it is needed
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pch_gpi_routing(struct udevice *pch)
|
||||
{
|
||||
u8 route[16];
|
||||
u32 reg;
|
||||
int gpi;
|
||||
|
||||
if (fdtdec_get_byte_array(gd->fdt_blob, pch->of_offset,
|
||||
"intel,gpi-routing", route, sizeof(route)))
|
||||
return -EINVAL;
|
||||
|
||||
for (reg = 0, gpi = 0; gpi < ARRAY_SIZE(route); gpi++)
|
||||
reg |= route[gpi] << (gpi * 2);
|
||||
|
||||
dm_pci_write_config32(pch, 0xb8, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pch_power_options(struct udevice *pch)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = pch->of_offset;
|
||||
u8 reg8;
|
||||
u16 reg16, pmbase;
|
||||
u32 reg32;
|
||||
const char *state;
|
||||
int pwr_on;
|
||||
int nmi_option;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Which state do we want to goto after g3 (power restored)?
|
||||
* 0 == S0 Full On
|
||||
* 1 == S5 Soft Off
|
||||
*
|
||||
* If the option is not existent (Laptops), use Kconfig setting.
|
||||
* TODO(sjg@chromium.org): Make this configurable
|
||||
*/
|
||||
pwr_on = MAINBOARD_POWER_ON;
|
||||
|
||||
dm_pci_read_config16(pch, GEN_PMCON_3, ®16);
|
||||
reg16 &= 0xfffe;
|
||||
switch (pwr_on) {
|
||||
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";
|
||||
}
|
||||
|
||||
reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
|
||||
reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
|
||||
|
||||
reg16 &= ~(1 << 10);
|
||||
reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
|
||||
|
||||
reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
|
||||
|
||||
dm_pci_write_config16(pch, GEN_PMCON_3, reg16);
|
||||
debug("Set power %s after power failure.\n", state);
|
||||
|
||||
/* Set up NMI on errors. */
|
||||
reg8 = inb(0x61);
|
||||
reg8 &= 0x0f; /* Higher Nibble must be 0 */
|
||||
reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
|
||||
reg8 |= (1 << 2); /* PCI SERR# Disable for now */
|
||||
outb(reg8, 0x61);
|
||||
|
||||
reg8 = inb(0x70);
|
||||
/* TODO(sjg@chromium.org): Make this configurable */
|
||||
nmi_option = NMI_OFF;
|
||||
if (nmi_option) {
|
||||
debug("NMI sources enabled.\n");
|
||||
reg8 &= ~(1 << 7); /* Set NMI. */
|
||||
} else {
|
||||
debug("NMI sources disabled.\n");
|
||||
/* Can't mask NMI from PCI-E and NMI_NOW */
|
||||
reg8 |= (1 << 7);
|
||||
}
|
||||
outb(reg8, 0x70);
|
||||
|
||||
/* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
|
||||
dm_pci_read_config16(pch, GEN_PMCON_1, ®16);
|
||||
reg16 &= ~(3 << 0); /* SMI# rate 1 minute */
|
||||
reg16 &= ~(1 << 10); /* Disable BIOS_PCI_EXP_EN for native PME */
|
||||
#if DEBUG_PERIODIC_SMIS
|
||||
/* Set DEBUG_PERIODIC_SMIS in pch.h to debug using periodic SMIs */
|
||||
reg16 |= (3 << 0); /* Periodic SMI every 8s */
|
||||
#endif
|
||||
dm_pci_write_config16(pch, GEN_PMCON_1, reg16);
|
||||
|
||||
/* Set the board's GPI routing. */
|
||||
ret = pch_gpi_routing(pch);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dm_pci_read_config16(pch, 0x40, &pmbase);
|
||||
pmbase &= 0xfffe;
|
||||
|
||||
writel(pmbase + GPE0_EN, fdtdec_get_int(blob, node,
|
||||
"intel,gpe0-enable", 0));
|
||||
writew(pmbase + ALT_GP_SMI_EN, fdtdec_get_int(blob, node,
|
||||
"intel,alt-gp-smi-enable", 0));
|
||||
|
||||
/* Set up power management block and determine sleep mode */
|
||||
reg32 = inl(pmbase + 0x04); /* PM1_CNT */
|
||||
reg32 &= ~(7 << 10); /* SLP_TYP */
|
||||
reg32 |= (1 << 0); /* SCI_EN */
|
||||
outl(reg32, pmbase + 0x04);
|
||||
|
||||
/* Clear magic status bits to prevent unexpected wake */
|
||||
setbits_le32(RCB_REG(0x3310), (1 << 4) | (1 << 5) | (1 << 0));
|
||||
clrbits_le32(RCB_REG(0x3f02), 0xf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pch_rtc_init(struct udevice *pch)
|
||||
{
|
||||
int rtc_failed;
|
||||
u8 reg8;
|
||||
|
||||
dm_pci_read_config8(pch, GEN_PMCON_3, ®8);
|
||||
rtc_failed = reg8 & RTC_BATTERY_DEAD;
|
||||
if (rtc_failed) {
|
||||
reg8 &= ~RTC_BATTERY_DEAD;
|
||||
dm_pci_write_config8(pch, GEN_PMCON_3, reg8);
|
||||
}
|
||||
debug("rtc_failed = 0x%x\n", rtc_failed);
|
||||
|
||||
/* TODO: Handle power failure */
|
||||
if (rtc_failed)
|
||||
printf("RTC power failed\n");
|
||||
}
|
||||
|
||||
/* CougarPoint PCH Power Management init */
|
||||
static void cpt_pm_init(struct udevice *pch)
|
||||
{
|
||||
debug("CougarPoint PM init\n");
|
||||
dm_pci_write_config8(pch, 0xa9, 0x47);
|
||||
setbits_le32(RCB_REG(0x2238), (1 << 6) | (1 << 0));
|
||||
|
||||
setbits_le32(RCB_REG(0x228c), 1 << 0);
|
||||
setbits_le32(RCB_REG(0x1100), (1 << 13) | (1 << 14));
|
||||
setbits_le32(RCB_REG(0x0900), 1 << 14);
|
||||
writel(0xc0388400, RCB_REG(0x2304));
|
||||
setbits_le32(RCB_REG(0x2314), (1 << 5) | (1 << 18));
|
||||
setbits_le32(RCB_REG(0x2320), (1 << 15) | (1 << 1));
|
||||
clrsetbits_le32(RCB_REG(0x3314), ~0x1f, 0xf);
|
||||
writel(0x050f0000, RCB_REG(0x3318));
|
||||
writel(0x04000000, RCB_REG(0x3324));
|
||||
setbits_le32(RCB_REG(0x3340), 0xfffff);
|
||||
setbits_le32(RCB_REG(0x3344), 1 << 1);
|
||||
|
||||
writel(0x0001c000, RCB_REG(0x3360));
|
||||
writel(0x00061100, RCB_REG(0x3368));
|
||||
writel(0x7f8fdfff, RCB_REG(0x3378));
|
||||
writel(0x000003fc, RCB_REG(0x337c));
|
||||
writel(0x00001000, RCB_REG(0x3388));
|
||||
writel(0x0001c000, RCB_REG(0x3390));
|
||||
writel(0x00000800, RCB_REG(0x33a0));
|
||||
writel(0x00001000, RCB_REG(0x33b0));
|
||||
writel(0x00093900, RCB_REG(0x33c0));
|
||||
writel(0x24653002, RCB_REG(0x33cc));
|
||||
writel(0x062108fe, RCB_REG(0x33d0));
|
||||
clrsetbits_le32(RCB_REG(0x33d4), 0x0fff0fff, 0x00670060);
|
||||
writel(0x01010000, RCB_REG(0x3a28));
|
||||
writel(0x01010404, RCB_REG(0x3a2c));
|
||||
writel(0x01041041, RCB_REG(0x3a80));
|
||||
clrsetbits_le32(RCB_REG(0x3a84), 0x0000ffff, 0x00001001);
|
||||
setbits_le32(RCB_REG(0x3a84), 1 << 24); /* SATA 2/3 disabled */
|
||||
setbits_le32(RCB_REG(0x3a88), 1 << 0); /* SATA 4/5 disabled */
|
||||
writel(0x00000001, RCB_REG(0x3a6c));
|
||||
clrsetbits_le32(RCB_REG(0x2344), ~0x00ffff00, 0xff00000c);
|
||||
clrsetbits_le32(RCB_REG(0x80c), 0xff << 20, 0x11 << 20);
|
||||
writel(0, RCB_REG(0x33c8));
|
||||
setbits_le32(RCB_REG(0x21b0), 0xf);
|
||||
}
|
||||
|
||||
/* PantherPoint PCH Power Management init */
|
||||
static void ppt_pm_init(struct udevice *pch)
|
||||
{
|
||||
debug("PantherPoint PM init\n");
|
||||
dm_pci_write_config8(pch, 0xa9, 0x47);
|
||||
setbits_le32(RCB_REG(0x2238), 1 << 0);
|
||||
setbits_le32(RCB_REG(0x228c), 1 << 0);
|
||||
setbits_le16(RCB_REG(0x1100), (1 << 13) | (1 << 14));
|
||||
setbits_le16(RCB_REG(0x0900), 1 << 14);
|
||||
writel(0xc03b8400, RCB_REG(0x2304));
|
||||
setbits_le32(RCB_REG(0x2314), (1 << 5) | (1 << 18));
|
||||
setbits_le32(RCB_REG(0x2320), (1 << 15) | (1 << 1));
|
||||
clrsetbits_le32(RCB_REG(0x3314), 0x1f, 0xf);
|
||||
writel(0x054f0000, RCB_REG(0x3318));
|
||||
writel(0x04000000, RCB_REG(0x3324));
|
||||
setbits_le32(RCB_REG(0x3340), 0xfffff);
|
||||
setbits_le32(RCB_REG(0x3344), (1 << 1) | (1 << 0));
|
||||
writel(0x0001c000, RCB_REG(0x3360));
|
||||
writel(0x00061100, RCB_REG(0x3368));
|
||||
writel(0x7f8fdfff, RCB_REG(0x3378));
|
||||
writel(0x000003fd, RCB_REG(0x337c));
|
||||
writel(0x00001000, RCB_REG(0x3388));
|
||||
writel(0x0001c000, RCB_REG(0x3390));
|
||||
writel(0x00000800, RCB_REG(0x33a0));
|
||||
writel(0x00001000, RCB_REG(0x33b0));
|
||||
writel(0x00093900, RCB_REG(0x33c0));
|
||||
writel(0x24653002, RCB_REG(0x33cc));
|
||||
writel(0x067388fe, RCB_REG(0x33d0));
|
||||
clrsetbits_le32(RCB_REG(0x33d4), 0x0fff0fff, 0x00670060);
|
||||
writel(0x01010000, RCB_REG(0x3a28));
|
||||
writel(0x01010404, RCB_REG(0x3a2c));
|
||||
writel(0x01040000, RCB_REG(0x3a80));
|
||||
clrsetbits_le32(RCB_REG(0x3a84), 0x0000ffff, 0x00001001);
|
||||
/* SATA 2/3 disabled */
|
||||
setbits_le32(RCB_REG(0x3a84), 1 << 24);
|
||||
/* SATA 4/5 disabled */
|
||||
setbits_le32(RCB_REG(0x3a88), 1 << 0);
|
||||
writel(0x00000001, RCB_REG(0x3a6c));
|
||||
clrsetbits_le32(RCB_REG(0x2344), 0xff0000ff, 0xff00000c);
|
||||
clrsetbits_le32(RCB_REG(0x80c), 0xff << 20, 0x11 << 20);
|
||||
setbits_le32(RCB_REG(0x33a4), (1 << 0));
|
||||
writel(0, RCB_REG(0x33c8));
|
||||
setbits_le32(RCB_REG(0x21b0), 0xf);
|
||||
}
|
||||
|
||||
static void enable_hpet(void)
|
||||
{
|
||||
/* Move HPET to default address 0xfed00000 and enable it */
|
||||
clrsetbits_le32(RCB_REG(HPTC), 3 << 0, 1 << 7);
|
||||
}
|
||||
|
||||
static void enable_clock_gating(struct udevice *pch)
|
||||
{
|
||||
u32 reg32;
|
||||
u16 reg16;
|
||||
|
||||
setbits_le32(RCB_REG(0x2234), 0xf);
|
||||
|
||||
dm_pci_read_config16(pch, GEN_PMCON_1, ®16);
|
||||
reg16 |= (1 << 2) | (1 << 11);
|
||||
dm_pci_write_config16(pch, GEN_PMCON_1, reg16);
|
||||
|
||||
pch_iobp_update(pch, 0xEB007F07, ~0UL, (1 << 31));
|
||||
pch_iobp_update(pch, 0xEB004000, ~0UL, (1 << 7));
|
||||
pch_iobp_update(pch, 0xEC007F07, ~0UL, (1 << 31));
|
||||
pch_iobp_update(pch, 0xEC004000, ~0UL, (1 << 7));
|
||||
|
||||
reg32 = readl(RCB_REG(CG));
|
||||
reg32 |= (1 << 31);
|
||||
reg32 |= (1 << 29) | (1 << 28);
|
||||
reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
|
||||
reg32 |= (1 << 16);
|
||||
reg32 |= (1 << 17);
|
||||
reg32 |= (1 << 18);
|
||||
reg32 |= (1 << 22);
|
||||
reg32 |= (1 << 23);
|
||||
reg32 &= ~(1 << 20);
|
||||
reg32 |= (1 << 19);
|
||||
reg32 |= (1 << 0);
|
||||
reg32 |= (0xf << 1);
|
||||
writel(reg32, RCB_REG(CG));
|
||||
|
||||
setbits_le32(RCB_REG(0x38c0), 0x7);
|
||||
setbits_le32(RCB_REG(0x36d4), 0x6680c004);
|
||||
setbits_le32(RCB_REG(0x3564), 0x3);
|
||||
}
|
||||
|
||||
static void pch_disable_smm_only_flashing(struct udevice *pch)
|
||||
{
|
||||
u8 reg8;
|
||||
|
||||
debug("Enabling BIOS updates outside of SMM... ");
|
||||
dm_pci_read_config8(pch, 0xdc, ®8); /* BIOS_CNTL */
|
||||
reg8 &= ~(1 << 5);
|
||||
dm_pci_write_config8(pch, 0xdc, reg8);
|
||||
}
|
||||
|
||||
static void pch_fixups(struct udevice *pch)
|
||||
{
|
||||
u8 gen_pmcon_2;
|
||||
|
||||
/* Indicate DRAM init done for MRC S3 to know it can resume */
|
||||
dm_pci_read_config8(pch, GEN_PMCON_2, &gen_pmcon_2);
|
||||
gen_pmcon_2 |= (1 << 7);
|
||||
dm_pci_write_config8(pch, GEN_PMCON_2, gen_pmcon_2);
|
||||
|
||||
/* Enable DMI ASPM in the PCH */
|
||||
clrbits_le32(RCB_REG(0x2304), 1 << 10);
|
||||
setbits_le32(RCB_REG(0x21a4), (1 << 11) | (1 << 10));
|
||||
setbits_le32(RCB_REG(0x21a8), 0x3);
|
||||
}
|
||||
|
||||
static void set_spi_speed(void)
|
||||
{
|
||||
u32 fdod;
|
||||
|
||||
/* Observe SPI Descriptor Component Section 0 */
|
||||
writel(0x1000, RCB_REG(SPI_DESC_COMP0));
|
||||
|
||||
/* Extract the1 Write/Erase SPI Frequency from descriptor */
|
||||
fdod = readl(RCB_REG(SPI_FREQ_WR_ERA));
|
||||
fdod >>= 24;
|
||||
fdod &= 7;
|
||||
|
||||
/* Set Software Sequence frequency to match */
|
||||
clrsetbits_8(RCB_REG(SPI_FREQ_SWSEQ), 7, fdod);
|
||||
}
|
||||
|
||||
static int lpc_init_extra(struct udevice *dev)
|
||||
{
|
||||
struct udevice *pch = dev->parent;
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node;
|
||||
|
||||
debug("pch: lpc_init\n");
|
||||
dm_pci_write_bar32(pch, 0, 0);
|
||||
dm_pci_write_bar32(pch, 1, 0xff800000);
|
||||
dm_pci_write_bar32(pch, 2, 0xfec00000);
|
||||
dm_pci_write_bar32(pch, 3, 0x800);
|
||||
dm_pci_write_bar32(pch, 4, 0x900);
|
||||
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_PCH);
|
||||
if (node < 0)
|
||||
return -ENOENT;
|
||||
|
||||
/* Set the value for PCI command register. */
|
||||
dm_pci_write_config16(pch, PCI_COMMAND, 0x000f);
|
||||
|
||||
/* IO APIC initialization. */
|
||||
pch_enable_apic(pch);
|
||||
|
||||
pch_enable_serial_irqs(pch);
|
||||
|
||||
/* Setup the PIRQ. */
|
||||
pch_pirq_init(pch);
|
||||
|
||||
/* Setup power options. */
|
||||
pch_power_options(pch);
|
||||
|
||||
/* Initialize power management */
|
||||
switch (pch_silicon_type(pch)) {
|
||||
case PCH_TYPE_CPT: /* CougarPoint */
|
||||
cpt_pm_init(pch);
|
||||
break;
|
||||
case PCH_TYPE_PPT: /* PantherPoint */
|
||||
ppt_pm_init(pch);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown Chipset: %s\n", pch->name);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* Initialize the real time clock. */
|
||||
pch_rtc_init(pch);
|
||||
|
||||
/* Initialize the High Precision Event Timers, if present. */
|
||||
enable_hpet();
|
||||
|
||||
/* Initialize Clock Gating */
|
||||
enable_clock_gating(pch);
|
||||
|
||||
pch_disable_smm_only_flashing(pch);
|
||||
|
||||
pch_fixups(pch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd82x6x_lpc_early_init(struct udevice *dev)
|
||||
{
|
||||
set_spi_speed();
|
||||
|
||||
/* Setting up Southbridge. In the northbridge code. */
|
||||
debug("Setting up static southbridge registers\n");
|
||||
dm_pci_write_config32(dev->parent, PCH_RCBA_BASE,
|
||||
RCB_BASE_ADDRESS | 1);
|
||||
dm_pci_write_config32(dev->parent, PMBASE, DEFAULT_PMBASE | 1);
|
||||
|
||||
/* Enable ACPI BAR */
|
||||
dm_pci_write_config8(dev->parent, ACPI_CNTL, 0x80);
|
||||
|
||||
debug("Disabling watchdog reboot\n");
|
||||
setbits_le32(RCB_REG(GCS), 1 >> 5); /* No reset */
|
||||
outw(1 << 11, DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */
|
||||
|
||||
dm_pci_write_config32(dev->parent, GPIO_BASE, DEFAULT_GPIOBASE | 1);
|
||||
dm_pci_write_config32(dev->parent, GPIO_CNTL, 0x10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd82x6x_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 bd82x6x_lpc_early_init(dev);
|
||||
}
|
||||
|
||||
return lpc_init_extra(dev);
|
||||
}
|
||||
|
||||
static const struct udevice_id bd82x6x_lpc_ids[] = {
|
||||
{ .compatible = "intel,bd82x6x-lpc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bd82x6x_lpc_drv) = {
|
||||
.name = "lpc",
|
||||
.id = UCLASS_LPC,
|
||||
.of_match = bd82x6x_lpc_ids,
|
||||
.probe = bd82x6x_lpc_probe,
|
||||
};
|
||||
495
u-boot/arch/x86/cpu/ivybridge/model_206ax.c
Normal file
495
u-boot/arch/x86/cpu/ivybridge/model_206ax.c
Normal file
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* From Coreboot file of same name
|
||||
*
|
||||
* Copyright (C) 2007-2009 coresystems GmbH
|
||||
* Copyright (C) 2011 The Chromium Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu_x86.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/msr-index.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/speedstep.h>
|
||||
#include <asm/turbo.h>
|
||||
#include <asm/arch/bd82x6x.h>
|
||||
#include <asm/arch/model_206ax.h>
|
||||
|
||||
static void enable_vmx(void)
|
||||
{
|
||||
struct cpuid_result regs;
|
||||
#ifdef CONFIG_ENABLE_VMX
|
||||
int enable = true;
|
||||
#else
|
||||
int enable = false;
|
||||
#endif
|
||||
msr_t msr;
|
||||
|
||||
regs = cpuid(1);
|
||||
/* Check that the VMX is supported before reading or writing the MSR. */
|
||||
if (!((regs.ecx & CPUID_VMX) || (regs.ecx & CPUID_SMX)))
|
||||
return;
|
||||
|
||||
msr = msr_read(MSR_IA32_FEATURE_CONTROL);
|
||||
|
||||
if (msr.lo & (1 << 0)) {
|
||||
debug("VMX is locked, so %s will do nothing\n", __func__);
|
||||
/* VMX locked. If we set it again we get an illegal
|
||||
* instruction
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* The IA32_FEATURE_CONTROL MSR may initialize with random values.
|
||||
* It must be cleared regardless of VMX config setting.
|
||||
*/
|
||||
msr.hi = 0;
|
||||
msr.lo = 0;
|
||||
|
||||
debug("%s VMX\n", enable ? "Enabling" : "Disabling");
|
||||
|
||||
/*
|
||||
* Even though the Intel manual says you must set the lock bit in
|
||||
* addition to the VMX bit in order for VMX to work, it is incorrect.
|
||||
* Thus we leave it unlocked for the OS to manage things itself.
|
||||
* This is good for a few reasons:
|
||||
* - No need to reflash the bios just to toggle the lock bit.
|
||||
* - The VMX bits really really should match each other across cores,
|
||||
* so hard locking it on one while another has the opposite setting
|
||||
* can easily lead to crashes as code using VMX migrates between
|
||||
* them.
|
||||
* - Vendors that want to "upsell" from a bios that disables+locks to
|
||||
* one that doesn't is sleazy.
|
||||
* By leaving this to the OS (e.g. Linux), people can do exactly what
|
||||
* they want on the fly, and do it correctly (e.g. across multiple
|
||||
* cores).
|
||||
*/
|
||||
if (enable) {
|
||||
msr.lo |= (1 << 2);
|
||||
if (regs.ecx & CPUID_SMX)
|
||||
msr.lo |= (1 << 1);
|
||||
}
|
||||
|
||||
msr_write(MSR_IA32_FEATURE_CONTROL, msr);
|
||||
}
|
||||
|
||||
/* 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 cpu_config_tdp_levels(void)
|
||||
{
|
||||
struct cpuid_result result;
|
||||
msr_t platform_info;
|
||||
|
||||
/* Minimum CPU revision */
|
||||
result = cpuid(1);
|
||||
if (result.eax < IVB_CONFIG_TDP_MIN_CPUID)
|
||||
return 0;
|
||||
|
||||
/* Bits 34:33 indicate how many levels supported */
|
||||
platform_info = msr_read(MSR_PLATFORM_INFO);
|
||||
return (platform_info.hi >> 1) & 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure processor power limits if possible
|
||||
* This must be done AFTER set of BIOS_RESET_CPL
|
||||
*/
|
||||
void set_power_limits(u8 power_limit_1_time)
|
||||
{
|
||||
msr_t msr = msr_read(MSR_PLATFORM_INFO);
|
||||
msr_t limit;
|
||||
unsigned power_unit;
|
||||
unsigned tdp, min_power, max_power, max_time;
|
||||
u8 power_limit_1_val;
|
||||
|
||||
if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr))
|
||||
return;
|
||||
|
||||
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 SNB EP/EX */
|
||||
|
||||
msr_write(MSR_PKG_POWER_LIMIT, limit);
|
||||
|
||||
/* 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 void configure_c_states(void)
|
||||
{
|
||||
struct cpuid_result result;
|
||||
msr_t msr;
|
||||
|
||||
msr = msr_read(MSR_PMG_CST_CONFIG_CTL);
|
||||
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 */
|
||||
msr.lo |= 7; /* No package C-state limit */
|
||||
msr_write(MSR_PMG_CST_CONFIG_CTL, msr);
|
||||
|
||||
msr = msr_read(MSR_PMG_IO_CAPTURE_ADR);
|
||||
msr.lo &= ~0x7ffff;
|
||||
msr.lo |= (PMB0_BASE + 4); /* LVL_2 base address */
|
||||
msr.lo |= (2 << 16); /* CST Range: C7 is max C-state */
|
||||
msr_write(MSR_PMG_IO_CAPTURE_ADR, 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);
|
||||
|
||||
/* C3 Interrupt Response Time Limit */
|
||||
msr.hi = 0;
|
||||
msr.lo = IRTL_VALID | IRTL_1024_NS | 0x50;
|
||||
msr_write(MSR_PKGC3_IRTL, msr);
|
||||
|
||||
/* C6 Interrupt Response Time Limit */
|
||||
msr.hi = 0;
|
||||
msr.lo = IRTL_VALID | IRTL_1024_NS | 0x68;
|
||||
msr_write(MSR_PKGC6_IRTL, msr);
|
||||
|
||||
/* C7 Interrupt Response Time Limit */
|
||||
msr.hi = 0;
|
||||
msr.lo = IRTL_VALID | IRTL_1024_NS | 0x6D;
|
||||
msr_write(MSR_PKGC7_IRTL, msr);
|
||||
|
||||
/* Primary Plane Current Limit */
|
||||
msr = msr_read(MSR_PP0_CURRENT_CONFIG);
|
||||
msr.lo &= ~0x1fff;
|
||||
msr.lo |= PP0_CURRENT_LIMIT;
|
||||
msr_write(MSR_PP0_CURRENT_CONFIG, msr);
|
||||
|
||||
/* Secondary Plane Current Limit */
|
||||
msr = msr_read(MSR_PP1_CURRENT_CONFIG);
|
||||
msr.lo &= ~0x1fff;
|
||||
result = cpuid(1);
|
||||
if (result.eax >= 0x30600)
|
||||
msr.lo |= PP1_CURRENT_LIMIT_IVB;
|
||||
else
|
||||
msr.lo |= PP1_CURRENT_LIMIT_SNB;
|
||||
msr_write(MSR_PP1_CURRENT_CONFIG, msr);
|
||||
}
|
||||
|
||||
static int configure_thermal_target(struct udevice *dev)
|
||||
{
|
||||
int tcc_offset;
|
||||
msr_t msr;
|
||||
|
||||
tcc_offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void configure_misc(void)
|
||||
{
|
||||
msr_t msr;
|
||||
|
||||
msr = msr_read(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(IA32_MISC_ENABLE, msr);
|
||||
|
||||
/* Disable Thermal interrupts */
|
||||
msr.lo = 0;
|
||||
msr.hi = 0;
|
||||
msr_write(IA32_THERM_INTERRUPT, msr);
|
||||
|
||||
/* Enable package critical interrupt only */
|
||||
msr.lo = 1 << 4;
|
||||
msr.hi = 0;
|
||||
msr_write(IA32_PACKAGE_THERM_INTERRUPT, 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_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(IA32_PLATFORM_DCA_CAP);
|
||||
msr.lo |= 1;
|
||||
msr_write(IA32_PLATFORM_DCA_CAP, msr);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_max_ratio(void)
|
||||
{
|
||||
msr_t msr, perf_ctl;
|
||||
|
||||
perf_ctl.hi = 0;
|
||||
|
||||
/* Check for configurable TDP option */
|
||||
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(MSR_IA32_PERF_CTL, perf_ctl);
|
||||
|
||||
debug("model_x06ax: frequency set to %d\n",
|
||||
((perf_ctl.lo >> 8) & 0xff) * SANDYBRIDGE_BCLK);
|
||||
}
|
||||
|
||||
static void set_energy_perf_bias(u8 policy)
|
||||
{
|
||||
msr_t msr;
|
||||
|
||||
/* Energy Policy is bits 3:0 */
|
||||
msr = msr_read(IA32_ENERGY_PERFORMANCE_BIAS);
|
||||
msr.lo &= ~0xf;
|
||||
msr.lo |= policy & 0xf;
|
||||
msr_write(IA32_ENERGY_PERFORMANCE_BIAS, msr);
|
||||
|
||||
debug("model_x06ax: energy policy set to %u\n", policy);
|
||||
}
|
||||
|
||||
static void configure_mca(void)
|
||||
{
|
||||
msr_t msr;
|
||||
int i;
|
||||
|
||||
msr.lo = 0;
|
||||
msr.hi = 0;
|
||||
/* This should only be done on a cold boot */
|
||||
for (i = 0; i < 7; i++)
|
||||
msr_write(IA32_MC0_STATUS + (i * 4), msr);
|
||||
}
|
||||
|
||||
#if CONFIG_USBDEBUG
|
||||
static unsigned ehci_debug_addr;
|
||||
#endif
|
||||
|
||||
static int model_206ax_init(struct udevice *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Clear out pending MCEs */
|
||||
configure_mca();
|
||||
|
||||
#if CONFIG_USBDEBUG
|
||||
/* Is this caution really needed? */
|
||||
if (!ehci_debug_addr)
|
||||
ehci_debug_addr = get_ehci_debug();
|
||||
set_ehci_debug(0);
|
||||
#endif
|
||||
|
||||
#if CONFIG_USBDEBUG
|
||||
set_ehci_debug(ehci_debug_addr);
|
||||
#endif
|
||||
|
||||
/* Enable the local cpu apics */
|
||||
enable_lapic_tpr();
|
||||
|
||||
/* Enable virtualization if enabled in CMOS */
|
||||
enable_vmx();
|
||||
|
||||
/* Configure C States */
|
||||
configure_c_states();
|
||||
|
||||
/* Configure Enhanced SpeedStep and Thermal Sensors */
|
||||
configure_misc();
|
||||
|
||||
/* Thermal throttle activation offset */
|
||||
ret = configure_thermal_target(dev);
|
||||
if (ret) {
|
||||
debug("Cannot set thermal target\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable Direct Cache Access */
|
||||
configure_dca_cap();
|
||||
|
||||
/* Set energy policy */
|
||||
set_energy_perf_bias(ENERGY_POLICY_NORMAL);
|
||||
|
||||
/* Set Max Ratio */
|
||||
set_max_ratio();
|
||||
|
||||
/* Enable Turbo */
|
||||
turbo_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int model_206ax_get_info(struct udevice *dev, struct cpu_info *info)
|
||||
{
|
||||
msr_t msr;
|
||||
|
||||
msr = msr_read(MSR_IA32_PERF_CTL);
|
||||
info->cpu_freq = ((msr.lo >> 8) & 0xff) * SANDYBRIDGE_BCLK * 1000000;
|
||||
info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU |
|
||||
1 << CPU_FEAT_UCODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int model_206ax_get_count(struct udevice *dev)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int cpu_x86_model_206ax_probe(struct udevice *dev)
|
||||
{
|
||||
if (dev->seq == 0)
|
||||
model_206ax_init(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cpu_ops cpu_x86_model_206ax_ops = {
|
||||
.get_desc = cpu_x86_get_desc,
|
||||
.get_info = model_206ax_get_info,
|
||||
.get_count = model_206ax_get_count,
|
||||
};
|
||||
|
||||
static const struct udevice_id cpu_x86_model_206ax_ids[] = {
|
||||
{ .compatible = "intel,core-gen3" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(cpu_x86_model_206ax_drv) = {
|
||||
.name = "cpu_x86_model_206ax",
|
||||
.id = UCLASS_CPU,
|
||||
.of_match = cpu_x86_model_206ax_ids,
|
||||
.bind = cpu_x86_bind,
|
||||
.probe = cpu_x86_model_206ax_probe,
|
||||
.ops = &cpu_x86_model_206ax_ops,
|
||||
};
|
||||
238
u-boot/arch/x86/cpu/ivybridge/northbridge.c
Normal file
238
u-boot/arch/x86/cpu/ivybridge/northbridge.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* From Coreboot northbridge/intel/sandybridge/northbridge.c
|
||||
*
|
||||
* Copyright (C) 2007-2009 coresystems GmbH
|
||||
* Copyright (C) 2011 The Chromium Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/model_206ax.h>
|
||||
#include <asm/arch/sandybridge.h>
|
||||
|
||||
int bridge_silicon_revision(struct udevice *dev)
|
||||
{
|
||||
struct cpuid_result result;
|
||||
u16 bridge_id;
|
||||
u8 stepping;
|
||||
|
||||
result = cpuid(1);
|
||||
stepping = result.eax & 0xf;
|
||||
dm_pci_read_config16(dev, PCI_DEVICE_ID, &bridge_id);
|
||||
bridge_id &= 0xf0;
|
||||
return bridge_id | stepping;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reserve everything between A segment and 1MB:
|
||||
*
|
||||
* 0xa0000 - 0xbffff: legacy VGA
|
||||
* 0xc0000 - 0xcffff: VGA OPROM (needed by kernel)
|
||||
* 0xe0000 - 0xfffff: SeaBIOS, if used, otherwise DMI
|
||||
*/
|
||||
static const int legacy_hole_base_k = 0xa0000 / 1024;
|
||||
static const int legacy_hole_size_k = 384;
|
||||
|
||||
static int get_pcie_bar(struct udevice *dev, u32 *base, u32 *len)
|
||||
{
|
||||
u32 pciexbar_reg;
|
||||
|
||||
*base = 0;
|
||||
*len = 0;
|
||||
|
||||
dm_pci_read_config32(dev, PCIEXBAR, &pciexbar_reg);
|
||||
|
||||
if (!(pciexbar_reg & (1 << 0)))
|
||||
return 0;
|
||||
|
||||
switch ((pciexbar_reg >> 1) & 3) {
|
||||
case 0: /* 256MB */
|
||||
*base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) |
|
||||
(1 << 28));
|
||||
*len = 256 * 1024 * 1024;
|
||||
return 1;
|
||||
case 1: /* 128M */
|
||||
*base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) |
|
||||
(1 << 28) | (1 << 27));
|
||||
*len = 128 * 1024 * 1024;
|
||||
return 1;
|
||||
case 2: /* 64M */
|
||||
*base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) |
|
||||
(1 << 28) | (1 << 27) | (1 << 26));
|
||||
*len = 64 * 1024 * 1024;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_fixed_resources(struct udevice *dev, int index)
|
||||
{
|
||||
u32 pcie_config_base, pcie_config_size;
|
||||
|
||||
if (get_pcie_bar(dev, &pcie_config_base, &pcie_config_size)) {
|
||||
debug("Adding PCIe config bar base=0x%08x size=0x%x\n",
|
||||
pcie_config_base, pcie_config_size);
|
||||
}
|
||||
}
|
||||
|
||||
static void northbridge_dmi_init(struct udevice *dev, int rev)
|
||||
{
|
||||
/* Clear error status bits */
|
||||
writel(0xffffffff, DMIBAR_REG(0x1c4));
|
||||
writel(0xffffffff, DMIBAR_REG(0x1d0));
|
||||
|
||||
/* Steps prior to DMI ASPM */
|
||||
if ((rev & BASE_REV_MASK) == BASE_REV_SNB) {
|
||||
clrsetbits_le32(DMIBAR_REG(0x250), (1 << 22) | (1 << 20),
|
||||
1 << 21);
|
||||
}
|
||||
|
||||
setbits_le32(DMIBAR_REG(0x238), 1 << 29);
|
||||
|
||||
if (rev >= SNB_STEP_D0) {
|
||||
setbits_le32(DMIBAR_REG(0x1f8), 1 << 16);
|
||||
} else if (rev >= SNB_STEP_D1) {
|
||||
clrsetbits_le32(DMIBAR_REG(0x1f8), 1 << 26, 1 << 16);
|
||||
setbits_le32(DMIBAR_REG(0x1fc), (1 << 12) | (1 << 23));
|
||||
}
|
||||
|
||||
/* Enable ASPM on SNB link, should happen before PCH link */
|
||||
if ((rev & BASE_REV_MASK) == BASE_REV_SNB)
|
||||
setbits_le32(DMIBAR_REG(0xd04), 1 << 4);
|
||||
|
||||
setbits_le32(DMIBAR_REG(0x88), (1 << 1) | (1 << 0));
|
||||
}
|
||||
|
||||
static void northbridge_init(struct udevice *dev, int rev)
|
||||
{
|
||||
u32 bridge_type;
|
||||
|
||||
add_fixed_resources(dev, 6);
|
||||
northbridge_dmi_init(dev, rev);
|
||||
|
||||
bridge_type = readl(MCHBAR_REG(0x5f10));
|
||||
bridge_type &= ~0xff;
|
||||
|
||||
if ((rev & BASE_REV_MASK) == BASE_REV_IVB) {
|
||||
/* Enable Power Aware Interrupt Routing - fixed priority */
|
||||
clrsetbits_8(MCHBAR_REG(0x5418), 0xf, 0x4);
|
||||
|
||||
/* 30h for IvyBridge */
|
||||
bridge_type |= 0x30;
|
||||
} else {
|
||||
/* 20h for Sandybridge */
|
||||
bridge_type |= 0x20;
|
||||
}
|
||||
writel(bridge_type, MCHBAR_REG(0x5f10));
|
||||
|
||||
/*
|
||||
* Set bit 0 of BIOS_RESET_CPL to indicate to the CPU
|
||||
* that BIOS has initialized memory and power management
|
||||
*/
|
||||
setbits_8(MCHBAR_REG(BIOS_RESET_CPL), 1);
|
||||
debug("Set BIOS_RESET_CPL\n");
|
||||
|
||||
/* Configure turbo power limits 1ms after reset complete bit */
|
||||
mdelay(1);
|
||||
set_power_limits(28);
|
||||
|
||||
/*
|
||||
* CPUs with configurable TDP also need power limits set
|
||||
* in MCHBAR. Use same values from MSR_PKG_POWER_LIMIT.
|
||||
*/
|
||||
if (cpu_config_tdp_levels()) {
|
||||
msr_t msr = msr_read(MSR_PKG_POWER_LIMIT);
|
||||
|
||||
writel(msr.lo, MCHBAR_REG(0x59A0));
|
||||
writel(msr.hi, MCHBAR_REG(0x59A4));
|
||||
}
|
||||
|
||||
/* Set here before graphics PM init */
|
||||
writel(0x00100001, MCHBAR_REG(0x5500));
|
||||
}
|
||||
|
||||
static void sandybridge_setup_northbridge_bars(struct udevice *dev)
|
||||
{
|
||||
/* Set up all hardcoded northbridge BARs */
|
||||
debug("Setting up static registers\n");
|
||||
dm_pci_write_config32(dev, EPBAR, DEFAULT_EPBAR | 1);
|
||||
dm_pci_write_config32(dev, EPBAR + 4, (0LL + DEFAULT_EPBAR) >> 32);
|
||||
dm_pci_write_config32(dev, MCHBAR, MCH_BASE_ADDRESS | 1);
|
||||
dm_pci_write_config32(dev, MCHBAR + 4, (0LL + MCH_BASE_ADDRESS) >> 32);
|
||||
/* 64MB - busses 0-63 */
|
||||
dm_pci_write_config32(dev, PCIEXBAR, DEFAULT_PCIEXBAR | 5);
|
||||
dm_pci_write_config32(dev, PCIEXBAR + 4,
|
||||
(0LL + DEFAULT_PCIEXBAR) >> 32);
|
||||
dm_pci_write_config32(dev, DMIBAR, DEFAULT_DMIBAR | 1);
|
||||
dm_pci_write_config32(dev, DMIBAR + 4, (0LL + DEFAULT_DMIBAR) >> 32);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
static int bd82x6x_northbridge_early_init(struct udevice *dev)
|
||||
{
|
||||
const int chipset_type = SANDYBRIDGE_MOBILE;
|
||||
u32 capid0_a;
|
||||
u8 reg8;
|
||||
|
||||
/* Device ID Override Enable should be done very early */
|
||||
dm_pci_read_config32(dev, 0xe4, &capid0_a);
|
||||
if (capid0_a & (1 << 10)) {
|
||||
dm_pci_read_config8(dev, 0xf3, ®8);
|
||||
reg8 &= ~7; /* Clear 2:0 */
|
||||
|
||||
if (chipset_type == SANDYBRIDGE_MOBILE)
|
||||
reg8 |= 1; /* Set bit 0 */
|
||||
|
||||
dm_pci_write_config8(dev, 0xf3, reg8);
|
||||
}
|
||||
|
||||
sandybridge_setup_northbridge_bars(dev);
|
||||
|
||||
/* Device Enable */
|
||||
dm_pci_write_config32(dev, DEVEN, DEVEN_HOST | DEVEN_IGD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd82x6x_northbridge_probe(struct udevice *dev)
|
||||
{
|
||||
int rev;
|
||||
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return bd82x6x_northbridge_early_init(dev);
|
||||
|
||||
rev = bridge_silicon_revision(dev);
|
||||
northbridge_init(dev, rev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id bd82x6x_northbridge_ids[] = {
|
||||
{ .compatible = "intel,bd82x6x-northbridge" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bd82x6x_northbridge_drv) = {
|
||||
.name = "bd82x6x_northbridge",
|
||||
.id = UCLASS_NORTHBRIDGE,
|
||||
.of_match = bd82x6x_northbridge_ids,
|
||||
.probe = bd82x6x_northbridge_probe,
|
||||
};
|
||||
239
u-boot/arch/x86/cpu/ivybridge/sata.c
Normal file
239
u-boot/arch/x86/cpu/ivybridge/sata.c
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* From Coreboot
|
||||
* Copyright (C) 2008-2009 coresystems GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pch_common.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/bd82x6x.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static void common_sata_init(struct udevice *dev, unsigned int port_map)
|
||||
{
|
||||
u32 reg32;
|
||||
u16 reg16;
|
||||
|
||||
/* Set IDE I/O Configuration */
|
||||
reg32 = SIG_MODE_PRI_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0;
|
||||
dm_pci_write_config32(dev, IDE_CONFIG, reg32);
|
||||
|
||||
/* Port enable */
|
||||
dm_pci_read_config16(dev, 0x92, ®16);
|
||||
reg16 &= ~0x3f;
|
||||
reg16 |= port_map;
|
||||
dm_pci_write_config16(dev, 0x92, reg16);
|
||||
|
||||
/* SATA Initialization register */
|
||||
port_map &= 0xff;
|
||||
dm_pci_write_config32(dev, 0x94, ((port_map ^ 0x3f) << 24) | 0x183);
|
||||
}
|
||||
|
||||
static void bd82x6x_sata_init(struct udevice *dev, struct udevice *pch)
|
||||
{
|
||||
unsigned int port_map, speed_support, port_tx;
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
const char *mode;
|
||||
u32 reg32;
|
||||
u16 reg16;
|
||||
|
||||
debug("SATA: Initializing...\n");
|
||||
|
||||
/* SATA configuration */
|
||||
port_map = fdtdec_get_int(blob, node, "intel,sata-port-map", 0);
|
||||
speed_support = fdtdec_get_int(blob, node,
|
||||
"sata_interface_speed_support", 0);
|
||||
|
||||
mode = fdt_getprop(blob, node, "intel,sata-mode", NULL);
|
||||
if (!mode || !strcmp(mode, "ahci")) {
|
||||
u32 abar;
|
||||
|
||||
debug("SATA: Controller in AHCI mode\n");
|
||||
|
||||
/* Set timings */
|
||||
dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE |
|
||||
IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS |
|
||||
IDE_PPE0 | IDE_IE0 | IDE_TIME0);
|
||||
dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE |
|
||||
IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS);
|
||||
|
||||
/* Sync DMA */
|
||||
dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_PSDE0);
|
||||
dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0001);
|
||||
|
||||
common_sata_init(dev, 0x8000 | port_map);
|
||||
|
||||
/* Initialize AHCI memory-mapped space */
|
||||
abar = dm_pci_read_bar32(dev, 5);
|
||||
debug("ABAR: %08X\n", abar);
|
||||
/* CAP (HBA Capabilities) : enable power management */
|
||||
reg32 = readl(abar + 0x00);
|
||||
reg32 |= 0x0c006000; /* set PSC+SSC+SALP+SSS */
|
||||
reg32 &= ~0x00020060; /* clear SXS+EMS+PMS */
|
||||
/* Set ISS, if available */
|
||||
if (speed_support) {
|
||||
reg32 &= ~0x00f00000;
|
||||
reg32 |= (speed_support & 0x03) << 20;
|
||||
}
|
||||
writel(reg32, abar + 0x00);
|
||||
/* PI (Ports implemented) */
|
||||
writel(port_map, abar + 0x0c);
|
||||
(void) readl(abar + 0x0c); /* Read back 1 */
|
||||
(void) readl(abar + 0x0c); /* Read back 2 */
|
||||
/* CAP2 (HBA Capabilities Extended)*/
|
||||
reg32 = readl(abar + 0x24);
|
||||
reg32 &= ~0x00000002;
|
||||
writel(reg32, abar + 0x24);
|
||||
/* VSP (Vendor Specific Register */
|
||||
reg32 = readl(abar + 0xa0);
|
||||
reg32 &= ~0x00000005;
|
||||
writel(reg32, abar + 0xa0);
|
||||
} else if (!strcmp(mode, "combined")) {
|
||||
debug("SATA: Controller in combined mode\n");
|
||||
|
||||
/* No AHCI: clear AHCI base */
|
||||
dm_pci_write_bar32(dev, 5, 0x00000000);
|
||||
/* And without AHCI BAR no memory decoding */
|
||||
dm_pci_read_config16(dev, PCI_COMMAND, ®16);
|
||||
reg16 &= ~PCI_COMMAND_MEMORY;
|
||||
dm_pci_write_config16(dev, PCI_COMMAND, reg16);
|
||||
|
||||
dm_pci_write_config8(dev, 0x09, 0x80);
|
||||
|
||||
/* Set timings */
|
||||
dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE |
|
||||
IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS);
|
||||
dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE |
|
||||
IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS |
|
||||
IDE_PPE0 | IDE_IE0 | IDE_TIME0);
|
||||
|
||||
/* Sync DMA */
|
||||
dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0);
|
||||
dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0200);
|
||||
|
||||
common_sata_init(dev, port_map);
|
||||
} else {
|
||||
debug("SATA: Controller in plain-ide mode\n");
|
||||
|
||||
/* No AHCI: clear AHCI base */
|
||||
dm_pci_write_bar32(dev, 5, 0x00000000);
|
||||
|
||||
/* And without AHCI BAR no memory decoding */
|
||||
dm_pci_read_config16(dev, PCI_COMMAND, ®16);
|
||||
reg16 &= ~PCI_COMMAND_MEMORY;
|
||||
dm_pci_write_config16(dev, PCI_COMMAND, reg16);
|
||||
|
||||
/*
|
||||
* Native mode capable on both primary and secondary (0xa)
|
||||
* OR'ed with enabled (0x50) = 0xf
|
||||
*/
|
||||
dm_pci_write_config8(dev, 0x09, 0x8f);
|
||||
|
||||
/* Set timings */
|
||||
dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE |
|
||||
IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS |
|
||||
IDE_PPE0 | IDE_IE0 | IDE_TIME0);
|
||||
dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE |
|
||||
IDE_SITRE | IDE_ISP_3_CLOCKS |
|
||||
IDE_RCT_1_CLOCKS | IDE_IE0 | IDE_TIME0);
|
||||
|
||||
/* Sync DMA */
|
||||
dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0 | IDE_PSDE0);
|
||||
dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0201);
|
||||
|
||||
common_sata_init(dev, port_map);
|
||||
}
|
||||
|
||||
/* Set Gen3 Transmitter settings if needed */
|
||||
port_tx = fdtdec_get_int(blob, node, "intel,sata-port0-gen3-tx", 0);
|
||||
if (port_tx)
|
||||
pch_iobp_update(pch, SATA_IOBP_SP0G3IR, 0, port_tx);
|
||||
|
||||
port_tx = fdtdec_get_int(blob, node, "intel,sata-port1-gen3-tx", 0);
|
||||
if (port_tx)
|
||||
pch_iobp_update(pch, SATA_IOBP_SP1G3IR, 0, port_tx);
|
||||
|
||||
/* Additional Programming Requirements */
|
||||
pch_common_sir_write(dev, 0x04, 0x00001600);
|
||||
pch_common_sir_write(dev, 0x28, 0xa0000033);
|
||||
reg32 = pch_common_sir_read(dev, 0x54);
|
||||
reg32 &= 0xff000000;
|
||||
reg32 |= 0x5555aa;
|
||||
pch_common_sir_write(dev, 0x54, reg32);
|
||||
pch_common_sir_write(dev, 0x64, 0xcccc8484);
|
||||
reg32 = pch_common_sir_read(dev, 0x68);
|
||||
reg32 &= 0xffff0000;
|
||||
reg32 |= 0xcccc;
|
||||
pch_common_sir_write(dev, 0x68, reg32);
|
||||
reg32 = pch_common_sir_read(dev, 0x78);
|
||||
reg32 &= 0x0000ffff;
|
||||
reg32 |= 0x88880000;
|
||||
pch_common_sir_write(dev, 0x78, reg32);
|
||||
pch_common_sir_write(dev, 0x84, 0x001c7000);
|
||||
pch_common_sir_write(dev, 0x88, 0x88338822);
|
||||
pch_common_sir_write(dev, 0xa0, 0x001c7000);
|
||||
pch_common_sir_write(dev, 0xc4, 0x0c0c0c0c);
|
||||
pch_common_sir_write(dev, 0xc8, 0x0c0c0c0c);
|
||||
pch_common_sir_write(dev, 0xd4, 0x10000000);
|
||||
|
||||
pch_iobp_update(pch, 0xea004001, 0x3fffffff, 0xc0000000);
|
||||
pch_iobp_update(pch, 0xea00408a, 0xfffffcff, 0x00000100);
|
||||
}
|
||||
|
||||
static void bd82x6x_sata_enable(struct udevice *dev)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
unsigned port_map;
|
||||
const char *mode;
|
||||
u16 map = 0;
|
||||
|
||||
/*
|
||||
* Set SATA controller mode early so the resource allocator can
|
||||
* properly assign IO/Memory resources for the controller.
|
||||
*/
|
||||
mode = fdt_getprop(blob, node, "intel,sata-mode", NULL);
|
||||
if (mode && !strcmp(mode, "ahci"))
|
||||
map = 0x0060;
|
||||
port_map = fdtdec_get_int(blob, node, "intel,sata-port-map", 0);
|
||||
|
||||
map |= (port_map ^ 0x3f) << 8;
|
||||
dm_pci_write_config16(dev, 0x90, map);
|
||||
}
|
||||
|
||||
static int bd82x6x_sata_probe(struct udevice *dev)
|
||||
{
|
||||
struct udevice *pch;
|
||||
int ret;
|
||||
|
||||
ret = uclass_first_device_err(UCLASS_PCH, &pch);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
bd82x6x_sata_enable(dev);
|
||||
else
|
||||
bd82x6x_sata_init(dev, pch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id bd82x6x_ahci_ids[] = {
|
||||
{ .compatible = "intel,pantherpoint-ahci" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(ahci_ivybridge_drv) = {
|
||||
.name = "ahci_ivybridge",
|
||||
.id = UCLASS_AHCI,
|
||||
.of_match = bd82x6x_ahci_ids,
|
||||
.probe = bd82x6x_sata_probe,
|
||||
};
|
||||
537
u-boot/arch/x86/cpu/ivybridge/sdram.c
Normal file
537
u-boot/arch/x86/cpu/ivybridge/sdram.c
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors.
|
||||
* (C) Copyright 2010,2011
|
||||
* Graeme Russ, <graeme.russ@gmail.com>
|
||||
*
|
||||
* Portions from Coreboot mainboard/google/link/romstage.c
|
||||
* Copyright (C) 2007-2010 coresystems GmbH
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <rtc.h>
|
||||
#include <spi.h>
|
||||
#include <spi_flash.h>
|
||||
#include <syscon.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/intel_regs.h>
|
||||
#include <asm/mrccache.h>
|
||||
#include <asm/mrc_common.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/report_platform.h>
|
||||
#include <asm/arch/me.h>
|
||||
#include <asm/arch/pei_data.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/arch/sandybridge.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define CMOS_OFFSET_MRC_SEED 152
|
||||
#define CMOS_OFFSET_MRC_SEED_S3 156
|
||||
#define CMOS_OFFSET_MRC_SEED_CHK 160
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
static int read_seed_from_cmos(struct pei_data *pei_data)
|
||||
{
|
||||
u16 c1, c2, checksum, seed_checksum;
|
||||
struct udevice *dev;
|
||||
int ret = 0;
|
||||
|
||||
ret = uclass_get_device(UCLASS_RTC, 0, &dev);
|
||||
if (ret) {
|
||||
debug("Cannot find RTC: err=%d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read scrambler seeds from CMOS RAM. We don't want to store them in
|
||||
* SPI flash since they change on every boot and that would wear down
|
||||
* the flash too much. So we store these in CMOS and the large MRC
|
||||
* data in SPI flash.
|
||||
*/
|
||||
ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED, &pei_data->scrambler_seed);
|
||||
if (!ret) {
|
||||
ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED_S3,
|
||||
&pei_data->scrambler_seed_s3);
|
||||
}
|
||||
if (ret) {
|
||||
debug("Failed to read from RTC %s\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
debug("Read scrambler seed 0x%08x from CMOS 0x%02x\n",
|
||||
pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED);
|
||||
debug("Read S3 scrambler seed 0x%08x from CMOS 0x%02x\n",
|
||||
pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3);
|
||||
|
||||
/* Compute seed checksum and compare */
|
||||
c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed,
|
||||
sizeof(u32));
|
||||
c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3,
|
||||
sizeof(u32));
|
||||
checksum = add_ip_checksums(sizeof(u32), c1, c2);
|
||||
|
||||
seed_checksum = rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK);
|
||||
seed_checksum |= rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1) << 8;
|
||||
|
||||
if (checksum != seed_checksum) {
|
||||
debug("%s: invalid seed checksum\n", __func__);
|
||||
pei_data->scrambler_seed = 0;
|
||||
pei_data->scrambler_seed_s3 = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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 = read_seed_from_cmos(pei_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = mrccache_get_region(NULL, &entry);
|
||||
if (ret)
|
||||
return ret;
|
||||
mrc_cache = mrccache_find_current(&entry);
|
||||
if (!mrc_cache)
|
||||
return -ENOENT;
|
||||
|
||||
pei_data->mrc_input = mrc_cache->data;
|
||||
pei_data->mrc_input_len = mrc_cache->data_size;
|
||||
debug("%s: at %p, size %x checksum %04x\n", __func__,
|
||||
pei_data->mrc_input, pei_data->mrc_input_len,
|
||||
mrc_cache->checksum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_seeds_to_cmos(struct pei_data *pei_data)
|
||||
{
|
||||
u16 c1, c2, checksum;
|
||||
struct udevice *dev;
|
||||
int ret = 0;
|
||||
|
||||
ret = uclass_get_device(UCLASS_RTC, 0, &dev);
|
||||
if (ret) {
|
||||
debug("Cannot find RTC: err=%d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Save the MRC seed values to CMOS */
|
||||
rtc_write32(dev, CMOS_OFFSET_MRC_SEED, pei_data->scrambler_seed);
|
||||
debug("Save scrambler seed 0x%08x to CMOS 0x%02x\n",
|
||||
pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED);
|
||||
|
||||
rtc_write32(dev, CMOS_OFFSET_MRC_SEED_S3, pei_data->scrambler_seed_s3);
|
||||
debug("Save s3 scrambler seed 0x%08x to CMOS 0x%02x\n",
|
||||
pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3);
|
||||
|
||||
/* Save a simple checksum of the seed values */
|
||||
c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed,
|
||||
sizeof(u32));
|
||||
c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3,
|
||||
sizeof(u32));
|
||||
checksum = add_ip_checksums(sizeof(u32), c1, c2);
|
||||
|
||||
rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK, checksum & 0xff);
|
||||
rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1, (checksum >> 8) & 0xff);
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void post_system_agent_init(struct udevice *dev, struct udevice *me_dev,
|
||||
struct pei_data *pei_data)
|
||||
{
|
||||
uint16_t done;
|
||||
|
||||
/*
|
||||
* Send ME init done for SandyBridge here. This is done inside the
|
||||
* SystemAgent binary on IvyBridge
|
||||
*/
|
||||
dm_pci_read_config16(dev, PCI_DEVICE_ID, &done);
|
||||
done &= BASE_REV_MASK;
|
||||
if (BASE_REV_SNB == done)
|
||||
intel_early_me_init_done(dev, me_dev, ME_INIT_STATUS_SUCCESS);
|
||||
else
|
||||
intel_me_status(me_dev);
|
||||
|
||||
/* If PCIe init is skipped, set the PEG clock gating */
|
||||
if (!pei_data->pcie_init)
|
||||
setbits_le32(MCHBAR_REG(0x7010), 1);
|
||||
}
|
||||
|
||||
static int recovery_mode_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int copy_spd(struct udevice *dev, struct pei_data *peid)
|
||||
{
|
||||
const void *data;
|
||||
int ret;
|
||||
|
||||
ret = mrc_locate_spd(dev, sizeof(peid->spd_data[0]), &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(peid->spd_data[0], data, sizeof(peid->spd_data[0]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
uint32_t tseg_base, uma_size, tolud;
|
||||
uint64_t tom, me_base, touud;
|
||||
uint64_t uma_memory_base = 0;
|
||||
uint64_t uma_memory_size;
|
||||
unsigned long long tomk;
|
||||
uint16_t ggc;
|
||||
u32 val;
|
||||
|
||||
/* Total Memory 2GB example:
|
||||
*
|
||||
* 00000000 0000MB-1992MB 1992MB RAM (writeback)
|
||||
* 7c800000 1992MB-2000MB 8MB TSEG (SMRR)
|
||||
* 7d000000 2000MB-2002MB 2MB GFX GTT (uncached)
|
||||
* 7d200000 2002MB-2034MB 32MB GFX UMA (uncached)
|
||||
* 7f200000 2034MB TOLUD
|
||||
* 7f800000 2040MB MEBASE
|
||||
* 7f800000 2040MB-2048MB 8MB ME UMA (uncached)
|
||||
* 80000000 2048MB TOM
|
||||
* 100000000 4096MB-4102MB 6MB RAM (writeback)
|
||||
*
|
||||
* Total Memory 4GB example:
|
||||
*
|
||||
* 00000000 0000MB-2768MB 2768MB RAM (writeback)
|
||||
* ad000000 2768MB-2776MB 8MB TSEG (SMRR)
|
||||
* ad800000 2776MB-2778MB 2MB GFX GTT (uncached)
|
||||
* ada00000 2778MB-2810MB 32MB GFX UMA (uncached)
|
||||
* afa00000 2810MB TOLUD
|
||||
* ff800000 4088MB MEBASE
|
||||
* ff800000 4088MB-4096MB 8MB ME UMA (uncached)
|
||||
* 100000000 4096MB TOM
|
||||
* 100000000 4096MB-5374MB 1278MB RAM (writeback)
|
||||
* 14fe00000 5368MB TOUUD
|
||||
*/
|
||||
|
||||
/* Top of Upper Usable DRAM, including remap */
|
||||
dm_pci_read_config32(dev, TOUUD + 4, &val);
|
||||
touud = (uint64_t)val << 32;
|
||||
dm_pci_read_config32(dev, TOUUD, &val);
|
||||
touud |= val;
|
||||
|
||||
/* Top of Lower Usable DRAM */
|
||||
dm_pci_read_config32(dev, TOLUD, &tolud);
|
||||
|
||||
/* Top of Memory - does not account for any UMA */
|
||||
dm_pci_read_config32(dev, 0xa4, &val);
|
||||
tom = (uint64_t)val << 32;
|
||||
dm_pci_read_config32(dev, 0xa0, &val);
|
||||
tom |= val;
|
||||
|
||||
debug("TOUUD %llx TOLUD %08x TOM %llx\n", touud, tolud, tom);
|
||||
|
||||
/* ME UMA needs excluding if total memory <4GB */
|
||||
dm_pci_read_config32(dev, 0x74, &val);
|
||||
me_base = (uint64_t)val << 32;
|
||||
dm_pci_read_config32(dev, 0x70, &val);
|
||||
me_base |= val;
|
||||
|
||||
debug("MEBASE %llx\n", me_base);
|
||||
|
||||
/* TODO: Get rid of all this shifting by 10 bits */
|
||||
tomk = tolud >> 10;
|
||||
if (me_base == tolud) {
|
||||
/* ME is from MEBASE-TOM */
|
||||
uma_size = (tom - me_base) >> 10;
|
||||
/* Increment TOLUD to account for ME as RAM */
|
||||
tolud += uma_size << 10;
|
||||
/* UMA starts at old TOLUD */
|
||||
uma_memory_base = tomk * 1024ULL;
|
||||
uma_memory_size = uma_size * 1024ULL;
|
||||
debug("ME UMA base %llx size %uM\n", me_base, uma_size >> 10);
|
||||
}
|
||||
|
||||
/* Graphics memory comes next */
|
||||
dm_pci_read_config16(dev, GGC, &ggc);
|
||||
if (!(ggc & 2)) {
|
||||
debug("IGD decoded, subtracting ");
|
||||
|
||||
/* Graphics memory */
|
||||
uma_size = ((ggc >> 3) & 0x1f) * 32 * 1024ULL;
|
||||
debug("%uM UMA", uma_size >> 10);
|
||||
tomk -= uma_size;
|
||||
uma_memory_base = tomk * 1024ULL;
|
||||
uma_memory_size += uma_size * 1024ULL;
|
||||
|
||||
/* GTT Graphics Stolen Memory Size (GGMS) */
|
||||
uma_size = ((ggc >> 8) & 0x3) * 1024ULL;
|
||||
tomk -= uma_size;
|
||||
uma_memory_base = tomk * 1024ULL;
|
||||
uma_memory_size += uma_size * 1024ULL;
|
||||
debug(" and %uM GTT\n", uma_size >> 10);
|
||||
}
|
||||
|
||||
/* Calculate TSEG size from its base which must be below GTT */
|
||||
dm_pci_read_config32(dev, 0xb8, &tseg_base);
|
||||
uma_size = (uma_memory_base - tseg_base) >> 10;
|
||||
tomk -= uma_size;
|
||||
uma_memory_base = tomk * 1024ULL;
|
||||
uma_memory_size += uma_size * 1024ULL;
|
||||
debug("TSEG base 0x%08x size %uM\n", tseg_base, uma_size >> 10);
|
||||
|
||||
debug("Available memory below 4GB: %lluM\n", tomk >> 10);
|
||||
|
||||
/* Report the memory regions */
|
||||
mrc_add_memory_area(info, 1 << 20, 2 << 28);
|
||||
mrc_add_memory_area(info, (2 << 28) + (2 << 20), 4 << 28);
|
||||
mrc_add_memory_area(info, (4 << 28) + (2 << 20), tseg_base);
|
||||
mrc_add_memory_area(info, 1ULL << 32, touud);
|
||||
|
||||
/* Add MTRRs for memory */
|
||||
mtrr_add_request(MTRR_TYPE_WRBACK, 0, 2ULL << 30);
|
||||
mtrr_add_request(MTRR_TYPE_WRBACK, 2ULL << 30, 512 << 20);
|
||||
mtrr_add_request(MTRR_TYPE_WRBACK, 0xaULL << 28, 256 << 20);
|
||||
mtrr_add_request(MTRR_TYPE_UNCACHEABLE, tseg_base, 16 << 20);
|
||||
mtrr_add_request(MTRR_TYPE_UNCACHEABLE, tseg_base + (16 << 20),
|
||||
32 << 20);
|
||||
|
||||
/*
|
||||
* If >= 4GB installed then memory from TOLUD to 4GB
|
||||
* is remapped above TOM, TOUUD will account for both
|
||||
*/
|
||||
if (touud > (1ULL << 32ULL)) {
|
||||
debug("Available memory above 4GB: %lluM\n",
|
||||
(touud >> 20) - 4096);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcba_config(void)
|
||||
{
|
||||
/*
|
||||
* GFX INTA -> PIRQA (MSI)
|
||||
* D28IP_P3IP WLAN INTA -> PIRQB
|
||||
* D29IP_E1P EHCI1 INTA -> PIRQD
|
||||
* D26IP_E2P EHCI2 INTA -> PIRQF
|
||||
* D31IP_SIP SATA INTA -> PIRQF (MSI)
|
||||
* D31IP_SMIP SMBUS INTB -> PIRQH
|
||||
* D31IP_TTIP THRT INTC -> PIRQA
|
||||
* D27IP_ZIP HDA INTA -> PIRQA (MSI)
|
||||
*
|
||||
* TRACKPAD -> PIRQE (Edge Triggered)
|
||||
* TOUCHSCREEN -> PIRQG (Edge Triggered)
|
||||
*/
|
||||
|
||||
/* Device interrupt pin register (board specific) */
|
||||
writel((INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) |
|
||||
(INTB << D31IP_SMIP) | (INTA << D31IP_SIP), RCB_REG(D31IP));
|
||||
writel(NOINT << D30IP_PIP, RCB_REG(D30IP));
|
||||
writel(INTA << D29IP_E1P, RCB_REG(D29IP));
|
||||
writel(INTA << D28IP_P3IP, RCB_REG(D28IP));
|
||||
writel(INTA << D27IP_ZIP, RCB_REG(D27IP));
|
||||
writel(INTA << D26IP_E2P, RCB_REG(D26IP));
|
||||
writel(NOINT << D25IP_LIP, RCB_REG(D25IP));
|
||||
writel(NOINT << D22IP_MEI1IP, RCB_REG(D22IP));
|
||||
|
||||
/* Device interrupt route registers */
|
||||
writel(DIR_ROUTE(PIRQB, PIRQH, PIRQA, PIRQC), RCB_REG(D31IR));
|
||||
writel(DIR_ROUTE(PIRQD, PIRQE, PIRQF, PIRQG), RCB_REG(D29IR));
|
||||
writel(DIR_ROUTE(PIRQB, PIRQC, PIRQD, PIRQE), RCB_REG(D28IR));
|
||||
writel(DIR_ROUTE(PIRQA, PIRQH, PIRQA, PIRQB), RCB_REG(D27IR));
|
||||
writel(DIR_ROUTE(PIRQF, PIRQE, PIRQG, PIRQH), RCB_REG(D26IR));
|
||||
writel(DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD), RCB_REG(D25IR));
|
||||
writel(DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD), RCB_REG(D22IR));
|
||||
|
||||
/* Enable IOAPIC (generic) */
|
||||
writew(0x0100, RCB_REG(OIC));
|
||||
/* PCH BWG says to read back the IOAPIC enable register */
|
||||
(void)readw(RCB_REG(OIC));
|
||||
|
||||
/* Disable unused devices (board specific) */
|
||||
setbits_le32(RCB_REG(FD), PCH_DISABLE_ALWAYS);
|
||||
}
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
struct pei_data _pei_data __aligned(8) = {
|
||||
.pei_version = PEI_VERSION,
|
||||
.mchbar = MCH_BASE_ADDRESS,
|
||||
.dmibar = DEFAULT_DMIBAR,
|
||||
.epbar = DEFAULT_EPBAR,
|
||||
.pciexbar = CONFIG_PCIE_ECAM_BASE,
|
||||
.smbusbar = SMBUS_IO_BASE,
|
||||
.wdbbar = 0x4000000,
|
||||
.wdbsize = 0x1000,
|
||||
.hpet_address = CONFIG_HPET_ADDRESS,
|
||||
.rcba = DEFAULT_RCBABASE,
|
||||
.pmbase = DEFAULT_PMBASE,
|
||||
.gpiobase = DEFAULT_GPIOBASE,
|
||||
.thermalbase = 0xfed08000,
|
||||
.system_type = 0, /* 0 Mobile, 1 Desktop/Server */
|
||||
.tseg_size = CONFIG_SMM_TSEG_SIZE,
|
||||
.ts_addresses = { 0x00, 0x00, 0x00, 0x00 },
|
||||
.ec_present = 1,
|
||||
.ddr3lv_support = 1,
|
||||
/*
|
||||
* 0 = leave channel enabled
|
||||
* 1 = disable dimm 0 on channel
|
||||
* 2 = disable dimm 1 on channel
|
||||
* 3 = disable dimm 0+1 on channel
|
||||
*/
|
||||
.dimm_channel0_disabled = 2,
|
||||
.dimm_channel1_disabled = 2,
|
||||
.max_ddr3_freq = 1600,
|
||||
.usb_port_config = {
|
||||
/*
|
||||
* Empty and onboard Ports 0-7, set to un-used pin
|
||||
* OC3
|
||||
*/
|
||||
{ 0, 3, 0x0000 }, /* P0= Empty */
|
||||
{ 1, 0, 0x0040 }, /* P1= Left USB 1 (OC0) */
|
||||
{ 1, 1, 0x0040 }, /* P2= Left USB 2 (OC1) */
|
||||
{ 1, 3, 0x0040 }, /* P3= SDCARD (no OC) */
|
||||
{ 0, 3, 0x0000 }, /* P4= Empty */
|
||||
{ 1, 3, 0x0040 }, /* P5= WWAN (no OC) */
|
||||
{ 0, 3, 0x0000 }, /* P6= Empty */
|
||||
{ 0, 3, 0x0000 }, /* P7= Empty */
|
||||
/*
|
||||
* Empty and onboard Ports 8-13, set to un-used pin
|
||||
* OC4
|
||||
*/
|
||||
{ 1, 4, 0x0040 }, /* P8= Camera (no OC) */
|
||||
{ 1, 4, 0x0040 }, /* P9= Bluetooth (no OC) */
|
||||
{ 0, 4, 0x0000 }, /* P10= Empty */
|
||||
{ 0, 4, 0x0000 }, /* P11= Empty */
|
||||
{ 0, 4, 0x0000 }, /* P12= Empty */
|
||||
{ 0, 4, 0x0000 }, /* P13= Empty */
|
||||
},
|
||||
};
|
||||
struct pei_data *pei_data = &_pei_data;
|
||||
struct udevice *dev, *me_dev;
|
||||
int ret;
|
||||
|
||||
ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = copy_spd(dev, pei_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
pei_data->boot_mode = gd->arch.pei_boot_mode;
|
||||
debug("Boot mode %d\n", gd->arch.pei_boot_mode);
|
||||
debug("mrc_input %p\n", pei_data->mrc_input);
|
||||
|
||||
/*
|
||||
* Do not pass MRC data in for recovery mode boot,
|
||||
* Always pass it in for S3 resume.
|
||||
*/
|
||||
if (!recovery_mode_enabled() ||
|
||||
pei_data->boot_mode == PEI_BOOT_RESUME) {
|
||||
ret = prepare_mrc_cache(pei_data);
|
||||
if (ret)
|
||||
debug("prepare_mrc_cache failed: %d\n", ret);
|
||||
}
|
||||
|
||||
/* If MRC data is not found we cannot continue S3 resume. */
|
||||
if (pei_data->boot_mode == PEI_BOOT_RESUME && !pei_data->mrc_input) {
|
||||
debug("Giving up in sdram_initialize: No MRC data\n");
|
||||
reset_cpu(0);
|
||||
}
|
||||
|
||||
/* Pass console handler in pei_data */
|
||||
pei_data->tx_byte = sdram_console_tx_byte;
|
||||
|
||||
/* Wait for ME to be ready */
|
||||
ret = intel_early_me_init(me_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = intel_early_me_uma_size(me_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mrc_common_init(dev, pei_data, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sdram_find(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
gd->ram_size = gd->arch.meminfo.total_32bit_memory;
|
||||
|
||||
debug("MRC output data length %#x at %p\n", pei_data->mrc_output_len,
|
||||
pei_data->mrc_output);
|
||||
|
||||
post_system_agent_init(dev, me_dev, pei_data);
|
||||
report_memory_config();
|
||||
|
||||
/* S3 resume: don't save scrambler seed or MRC data */
|
||||
if (pei_data->boot_mode != PEI_BOOT_RESUME) {
|
||||
/*
|
||||
* This will be copied to SDRAM in reserve_arch(), then written
|
||||
* to SPI flash in mrccache_save()
|
||||
*/
|
||||
gd->arch.mrc_output = (char *)pei_data->mrc_output;
|
||||
gd->arch.mrc_output_len = pei_data->mrc_output_len;
|
||||
ret = write_seeds_to_cmos(pei_data);
|
||||
if (ret)
|
||||
debug("Failed to write seeds to CMOS: %d\n", ret);
|
||||
}
|
||||
|
||||
writew(0xCAFE, MCHBAR_REG(SSKPD));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rcba_config();
|
||||
|
||||
return 0;
|
||||
}
|
||||
159
u-boot/arch/x86/cpu/lapic.c
Normal file
159
u-boot/arch/x86/cpu/lapic.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* From coreboot file of same name
|
||||
*
|
||||
* Copyright (C) 2008-2009 coresystems GmbH
|
||||
* Copyright (C) 2014 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/lapic.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/msr-index.h>
|
||||
#include <asm/post.h>
|
||||
|
||||
unsigned long lapic_read(unsigned long reg)
|
||||
{
|
||||
return readl(LAPIC_DEFAULT_BASE + reg);
|
||||
}
|
||||
|
||||
#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
|
||||
sizeof(*(ptr))))
|
||||
|
||||
struct __xchg_dummy { unsigned long a[100]; };
|
||||
#define __xg(x) ((struct __xchg_dummy *)(x))
|
||||
|
||||
/*
|
||||
* Note: no "lock" prefix even on SMP. xchg always implies lock anyway.
|
||||
*
|
||||
* Note 2: xchg has side effect, so that attribute volatile is necessary,
|
||||
* but generally the primitive is invalid, *ptr is output argument.
|
||||
*/
|
||||
static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
|
||||
int size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
__asm__ __volatile__("xchgb %b0,%1"
|
||||
: "=q" (x)
|
||||
: "m" (*__xg(ptr)), "0" (x)
|
||||
: "memory");
|
||||
break;
|
||||
case 2:
|
||||
__asm__ __volatile__("xchgw %w0,%1"
|
||||
: "=r" (x)
|
||||
: "m" (*__xg(ptr)), "0" (x)
|
||||
: "memory");
|
||||
break;
|
||||
case 4:
|
||||
__asm__ __volatile__("xchgl %0,%1"
|
||||
: "=r" (x)
|
||||
: "m" (*__xg(ptr)), "0" (x)
|
||||
: "memory");
|
||||
break;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void lapic_write(unsigned long reg, unsigned long v)
|
||||
{
|
||||
(void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v);
|
||||
}
|
||||
|
||||
void enable_lapic(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_INTEL_QUARK)) {
|
||||
msr_t msr;
|
||||
|
||||
msr = msr_read(MSR_IA32_APICBASE);
|
||||
msr.hi &= 0xffffff00;
|
||||
msr.lo |= MSR_IA32_APICBASE_ENABLE;
|
||||
msr.lo &= ~MSR_IA32_APICBASE_BASE;
|
||||
msr.lo |= LAPIC_DEFAULT_BASE;
|
||||
msr_write(MSR_IA32_APICBASE, msr);
|
||||
}
|
||||
}
|
||||
|
||||
void disable_lapic(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_INTEL_QUARK)) {
|
||||
msr_t msr;
|
||||
|
||||
msr = msr_read(MSR_IA32_APICBASE);
|
||||
msr.lo &= ~MSR_IA32_APICBASE_ENABLE;
|
||||
msr_write(MSR_IA32_APICBASE, msr);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long lapicid(void)
|
||||
{
|
||||
return lapic_read(LAPIC_ID) >> 24;
|
||||
}
|
||||
|
||||
static void lapic_wait_icr_idle(void)
|
||||
{
|
||||
do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
|
||||
}
|
||||
|
||||
int lapic_remote_read(int apicid, int reg, unsigned long *pvalue)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long status;
|
||||
int result;
|
||||
|
||||
lapic_wait_icr_idle();
|
||||
lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
|
||||
lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
|
||||
|
||||
timeout = 0;
|
||||
do {
|
||||
status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
|
||||
} while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
|
||||
|
||||
result = -1;
|
||||
if (status == LAPIC_ICR_RR_VALID) {
|
||||
*pvalue = lapic_read(LAPIC_RRR);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void lapic_setup(void)
|
||||
{
|
||||
/* Only Pentium Pro and later have those MSR stuff */
|
||||
debug("Setting up local apic: ");
|
||||
|
||||
/* Enable the local apic */
|
||||
enable_lapic();
|
||||
|
||||
/* Set Task Priority to 'accept all' */
|
||||
lapic_write(LAPIC_TASKPRI,
|
||||
lapic_read(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK);
|
||||
|
||||
/* Put the local apic in virtual wire mode */
|
||||
lapic_write(LAPIC_SPIV, (lapic_read(LAPIC_SPIV) &
|
||||
~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE);
|
||||
lapic_write(LAPIC_LVT0, (lapic_read(LAPIC_LVT0) &
|
||||
~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER |
|
||||
LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY |
|
||||
LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 |
|
||||
LAPIC_DELIVERY_MODE_MASK)) |
|
||||
(LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING |
|
||||
LAPIC_DELIVERY_MODE_EXTINT));
|
||||
lapic_write(LAPIC_LVT1, (lapic_read(LAPIC_LVT1) &
|
||||
~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER |
|
||||
LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY |
|
||||
LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 |
|
||||
LAPIC_DELIVERY_MODE_MASK)) |
|
||||
(LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING |
|
||||
LAPIC_DELIVERY_MODE_NMI));
|
||||
|
||||
debug("apic_id: 0x%02lx, ", lapicid());
|
||||
|
||||
debug("done.\n");
|
||||
post_code(POST_LAPIC);
|
||||
}
|
||||
576
u-boot/arch/x86/cpu/mp_init.c
Normal file
576
u-boot/arch/x86/cpu/mp_init.c
Normal file
@@ -0,0 +1,576 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Based on code from the coreboot file of the same name
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <qfw.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/interrupt.h>
|
||||
#include <asm/lapic.h>
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/mp.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/sipi.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dm/root.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* Total CPUs include BSP */
|
||||
static int num_cpus;
|
||||
|
||||
/* This also needs to match the sipi.S assembly code for saved MSR encoding */
|
||||
struct saved_msr {
|
||||
uint32_t index;
|
||||
uint32_t lo;
|
||||
uint32_t hi;
|
||||
} __packed;
|
||||
|
||||
|
||||
struct mp_flight_plan {
|
||||
int num_records;
|
||||
struct mp_flight_record *records;
|
||||
};
|
||||
|
||||
static struct mp_flight_plan mp_info;
|
||||
|
||||
struct cpu_map {
|
||||
struct udevice *dev;
|
||||
int apic_id;
|
||||
int err_code;
|
||||
};
|
||||
|
||||
static inline void barrier_wait(atomic_t *b)
|
||||
{
|
||||
while (atomic_read(b) == 0)
|
||||
asm("pause");
|
||||
mfence();
|
||||
}
|
||||
|
||||
static inline void release_barrier(atomic_t *b)
|
||||
{
|
||||
mfence();
|
||||
atomic_set(b, 1);
|
||||
}
|
||||
|
||||
static inline void stop_this_cpu(void)
|
||||
{
|
||||
/* Called by an AP when it is ready to halt and wait for a new task */
|
||||
for (;;)
|
||||
cpu_hlt();
|
||||
}
|
||||
|
||||
/* Returns 1 if timeout waiting for APs. 0 if target APs found */
|
||||
static int wait_for_aps(atomic_t *val, int target, int total_delay,
|
||||
int delay_step)
|
||||
{
|
||||
int timeout = 0;
|
||||
int delayed = 0;
|
||||
|
||||
while (atomic_read(val) != target) {
|
||||
udelay(delay_step);
|
||||
delayed += delay_step;
|
||||
if (delayed >= total_delay) {
|
||||
timeout = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
static void ap_do_flight_plan(struct udevice *cpu)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mp_info.num_records; i++) {
|
||||
struct mp_flight_record *rec = &mp_info.records[i];
|
||||
|
||||
atomic_inc(&rec->cpus_entered);
|
||||
barrier_wait(&rec->barrier);
|
||||
|
||||
if (rec->ap_call != NULL)
|
||||
rec->ap_call(cpu, rec->ap_arg);
|
||||
}
|
||||
}
|
||||
|
||||
static int find_cpu_by_apic_id(int apic_id, struct udevice **devp)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
*devp = NULL;
|
||||
for (uclass_find_first_device(UCLASS_CPU, &dev);
|
||||
dev;
|
||||
uclass_find_next_device(&dev)) {
|
||||
struct cpu_platdata *plat = dev_get_parent_platdata(dev);
|
||||
|
||||
if (plat->cpu_id == apic_id) {
|
||||
*devp = dev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* By the time APs call ap_init() caching has been setup, and microcode has
|
||||
* been loaded
|
||||
*/
|
||||
static void ap_init(unsigned int cpu_index)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int apic_id;
|
||||
int ret;
|
||||
|
||||
/* Ensure the local apic is enabled */
|
||||
enable_lapic();
|
||||
|
||||
apic_id = lapicid();
|
||||
ret = find_cpu_by_apic_id(apic_id, &dev);
|
||||
if (ret) {
|
||||
debug("Unknown CPU apic_id %x\n", apic_id);
|
||||
goto done;
|
||||
}
|
||||
|
||||
debug("AP: slot %d apic_id %x, dev %s\n", cpu_index, apic_id,
|
||||
dev ? dev->name : "(apic_id not found)");
|
||||
|
||||
/* Walk the flight plan */
|
||||
ap_do_flight_plan(dev);
|
||||
|
||||
/* Park the AP */
|
||||
debug("parking\n");
|
||||
done:
|
||||
stop_this_cpu();
|
||||
}
|
||||
|
||||
static const unsigned int fixed_mtrrs[NUM_FIXED_MTRRS] = {
|
||||
MTRR_FIX_64K_00000_MSR, MTRR_FIX_16K_80000_MSR, MTRR_FIX_16K_A0000_MSR,
|
||||
MTRR_FIX_4K_C0000_MSR, MTRR_FIX_4K_C8000_MSR, MTRR_FIX_4K_D0000_MSR,
|
||||
MTRR_FIX_4K_D8000_MSR, MTRR_FIX_4K_E0000_MSR, MTRR_FIX_4K_E8000_MSR,
|
||||
MTRR_FIX_4K_F0000_MSR, MTRR_FIX_4K_F8000_MSR,
|
||||
};
|
||||
|
||||
static inline struct saved_msr *save_msr(int index, struct saved_msr *entry)
|
||||
{
|
||||
msr_t msr;
|
||||
|
||||
msr = msr_read(index);
|
||||
entry->index = index;
|
||||
entry->lo = msr.lo;
|
||||
entry->hi = msr.hi;
|
||||
|
||||
/* Return the next entry */
|
||||
entry++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static int save_bsp_msrs(char *start, int size)
|
||||
{
|
||||
int msr_count;
|
||||
int num_var_mtrrs;
|
||||
struct saved_msr *msr_entry;
|
||||
int i;
|
||||
msr_t msr;
|
||||
|
||||
/* Determine number of MTRRs need to be saved */
|
||||
msr = msr_read(MTRR_CAP_MSR);
|
||||
num_var_mtrrs = msr.lo & 0xff;
|
||||
|
||||
/* 2 * num_var_mtrrs for base and mask. +1 for IA32_MTRR_DEF_TYPE */
|
||||
msr_count = 2 * num_var_mtrrs + NUM_FIXED_MTRRS + 1;
|
||||
|
||||
if ((msr_count * sizeof(struct saved_msr)) > size) {
|
||||
printf("Cannot mirror all %d msrs\n", msr_count);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
msr_entry = (void *)start;
|
||||
for (i = 0; i < NUM_FIXED_MTRRS; i++)
|
||||
msr_entry = save_msr(fixed_mtrrs[i], msr_entry);
|
||||
|
||||
for (i = 0; i < num_var_mtrrs; i++) {
|
||||
msr_entry = save_msr(MTRR_PHYS_BASE_MSR(i), msr_entry);
|
||||
msr_entry = save_msr(MTRR_PHYS_MASK_MSR(i), msr_entry);
|
||||
}
|
||||
|
||||
msr_entry = save_msr(MTRR_DEF_TYPE_MSR, msr_entry);
|
||||
|
||||
return msr_count;
|
||||
}
|
||||
|
||||
static int load_sipi_vector(atomic_t **ap_countp, int num_cpus)
|
||||
{
|
||||
struct sipi_params_16bit *params16;
|
||||
struct sipi_params *params;
|
||||
static char msr_save[512];
|
||||
char *stack;
|
||||
ulong addr;
|
||||
int code_len;
|
||||
int size;
|
||||
int ret;
|
||||
|
||||
/* Copy in the code */
|
||||
code_len = ap_start16_code_end - ap_start16;
|
||||
debug("Copying SIPI code to %x: %d bytes\n", AP_DEFAULT_BASE,
|
||||
code_len);
|
||||
memcpy((void *)AP_DEFAULT_BASE, ap_start16, code_len);
|
||||
|
||||
addr = AP_DEFAULT_BASE + (ulong)sipi_params_16bit - (ulong)ap_start16;
|
||||
params16 = (struct sipi_params_16bit *)addr;
|
||||
params16->ap_start = (uint32_t)ap_start;
|
||||
params16->gdt = (uint32_t)gd->arch.gdt;
|
||||
params16->gdt_limit = X86_GDT_SIZE - 1;
|
||||
debug("gdt = %x, gdt_limit = %x\n", params16->gdt, params16->gdt_limit);
|
||||
|
||||
params = (struct sipi_params *)sipi_params;
|
||||
debug("SIPI 32-bit params at %p\n", params);
|
||||
params->idt_ptr = (uint32_t)x86_get_idt();
|
||||
|
||||
params->stack_size = CONFIG_AP_STACK_SIZE;
|
||||
size = params->stack_size * num_cpus;
|
||||
stack = memalign(4096, size);
|
||||
if (!stack)
|
||||
return -ENOMEM;
|
||||
params->stack_top = (u32)(stack + size);
|
||||
#if !defined(CONFIG_QEMU) && !defined(CONFIG_HAVE_FSP)
|
||||
params->microcode_ptr = ucode_base;
|
||||
debug("Microcode at %x\n", params->microcode_ptr);
|
||||
#endif
|
||||
params->msr_table_ptr = (u32)msr_save;
|
||||
ret = save_bsp_msrs(msr_save, sizeof(msr_save));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
params->msr_count = ret;
|
||||
|
||||
params->c_handler = (uint32_t)&ap_init;
|
||||
|
||||
*ap_countp = ¶ms->ap_count;
|
||||
atomic_set(*ap_countp, 0);
|
||||
debug("SIPI vector is ready\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_cpu_devices(int expected_cpus)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < expected_cpus; i++) {
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
ret = uclass_find_device(UCLASS_CPU, i, &dev);
|
||||
if (ret) {
|
||||
debug("Cannot find CPU %d in device tree\n", i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 1 for timeout. 0 on success */
|
||||
static int apic_wait_timeout(int total_delay, const char *msg)
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
if (!(lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY))
|
||||
return 0;
|
||||
|
||||
debug("Waiting for %s...", msg);
|
||||
while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY) {
|
||||
udelay(50);
|
||||
total += 50;
|
||||
if (total >= total_delay) {
|
||||
debug("timed out: aborting\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
debug("done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_aps(int ap_count, atomic_t *num_aps)
|
||||
{
|
||||
int sipi_vector;
|
||||
/* Max location is 4KiB below 1MiB */
|
||||
const int max_vector_loc = ((1 << 20) - (1 << 12)) >> 12;
|
||||
|
||||
if (ap_count == 0)
|
||||
return 0;
|
||||
|
||||
/* The vector is sent as a 4k aligned address in one byte */
|
||||
sipi_vector = AP_DEFAULT_BASE >> 12;
|
||||
|
||||
if (sipi_vector > max_vector_loc) {
|
||||
printf("SIPI vector too large! 0x%08x\n",
|
||||
sipi_vector);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("Attempting to start %d APs\n", ap_count);
|
||||
|
||||
if (apic_wait_timeout(1000, "ICR not to be busy"))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* Send INIT IPI to all but self */
|
||||
lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
|
||||
lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
|
||||
LAPIC_DM_INIT);
|
||||
debug("Waiting for 10ms after sending INIT\n");
|
||||
mdelay(10);
|
||||
|
||||
/* Send 1st SIPI */
|
||||
if (apic_wait_timeout(1000, "ICR not to be busy"))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
|
||||
lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
|
||||
LAPIC_DM_STARTUP | sipi_vector);
|
||||
if (apic_wait_timeout(10000, "first SIPI to complete"))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* Wait for CPUs to check in up to 200 us */
|
||||
wait_for_aps(num_aps, ap_count, 200, 15);
|
||||
|
||||
/* Send 2nd SIPI */
|
||||
if (apic_wait_timeout(1000, "ICR not to be busy"))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
|
||||
lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
|
||||
LAPIC_DM_STARTUP | sipi_vector);
|
||||
if (apic_wait_timeout(10000, "second SIPI to complete"))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* Wait for CPUs to check in */
|
||||
if (wait_for_aps(num_aps, ap_count, 10000, 50)) {
|
||||
debug("Not all APs checked in: %d/%d\n",
|
||||
atomic_read(num_aps), ap_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
const int timeout_us = 100000;
|
||||
const int step_us = 100;
|
||||
int num_aps = num_cpus - 1;
|
||||
|
||||
for (i = 0; i < mp_params->num_records; i++) {
|
||||
struct mp_flight_record *rec = &mp_params->flight_plan[i];
|
||||
|
||||
/* Wait for APs if the record is not released */
|
||||
if (atomic_read(&rec->barrier) == 0) {
|
||||
/* Wait for the APs to check in */
|
||||
if (wait_for_aps(&rec->cpus_entered, num_aps,
|
||||
timeout_us, step_us)) {
|
||||
debug("MP record %d timeout\n", i);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rec->bsp_call != NULL)
|
||||
rec->bsp_call(cpu, rec->bsp_arg);
|
||||
|
||||
release_barrier(&rec->barrier);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int init_bsp(struct udevice **devp)
|
||||
{
|
||||
char processor_name[CPU_MAX_NAME_LEN];
|
||||
int apic_id;
|
||||
int ret;
|
||||
|
||||
cpu_get_name(processor_name);
|
||||
debug("CPU: %s\n", processor_name);
|
||||
|
||||
apic_id = lapicid();
|
||||
ret = find_cpu_by_apic_id(apic_id, devp);
|
||||
if (ret) {
|
||||
printf("Cannot find boot CPU, APIC ID %d\n", apic_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QFW
|
||||
static int qemu_cpu_fixup(void)
|
||||
{
|
||||
int ret;
|
||||
int cpu_num;
|
||||
int cpu_online;
|
||||
struct udevice *dev, *pdev;
|
||||
struct cpu_platdata *plat;
|
||||
char *cpu;
|
||||
|
||||
/* first we need to find '/cpus' */
|
||||
for (device_find_first_child(dm_root(), &pdev);
|
||||
pdev;
|
||||
device_find_next_child(&pdev)) {
|
||||
if (!strcmp(pdev->name, "cpus"))
|
||||
break;
|
||||
}
|
||||
if (!pdev) {
|
||||
printf("unable to find cpus device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* calculate cpus that are already bound */
|
||||
cpu_num = 0;
|
||||
for (uclass_find_first_device(UCLASS_CPU, &dev);
|
||||
dev;
|
||||
uclass_find_next_device(&dev)) {
|
||||
cpu_num++;
|
||||
}
|
||||
|
||||
/* get actual cpu number */
|
||||
cpu_online = qemu_fwcfg_online_cpus();
|
||||
if (cpu_online < 0) {
|
||||
printf("unable to get online cpu number: %d\n", cpu_online);
|
||||
return cpu_online;
|
||||
}
|
||||
|
||||
/* bind addtional cpus */
|
||||
dev = NULL;
|
||||
for (; cpu_num < cpu_online; cpu_num++) {
|
||||
/*
|
||||
* allocate device name here as device_bind_driver() does
|
||||
* not copy device name, 8 bytes are enough for
|
||||
* sizeof("cpu@") + 3 digits cpu number + '\0'
|
||||
*/
|
||||
cpu = malloc(8);
|
||||
if (!cpu) {
|
||||
printf("unable to allocate device name\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sprintf(cpu, "cpu@%d", cpu_num);
|
||||
ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev);
|
||||
if (ret) {
|
||||
printf("binding cpu@%d failed: %d\n", cpu_num, ret);
|
||||
return ret;
|
||||
}
|
||||
plat = dev_get_parent_platdata(dev);
|
||||
plat->cpu_id = cpu_num;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mp_init(struct mp_params *p)
|
||||
{
|
||||
int num_aps;
|
||||
atomic_t *ap_count;
|
||||
struct udevice *cpu;
|
||||
int ret;
|
||||
|
||||
/* This will cause the CPUs devices to be bound */
|
||||
struct uclass *uc;
|
||||
ret = uclass_get(UCLASS_CPU, &uc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_QFW
|
||||
ret = qemu_cpu_fixup();
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
ret = init_bsp(&cpu);
|
||||
if (ret) {
|
||||
debug("Cannot init boot CPU: err=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (p == NULL || p->flight_plan == NULL || p->num_records < 1) {
|
||||
printf("Invalid MP parameters\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_cpus = cpu_get_count(cpu);
|
||||
if (num_cpus < 0) {
|
||||
debug("Cannot get number of CPUs: err=%d\n", num_cpus);
|
||||
return num_cpus;
|
||||
}
|
||||
|
||||
if (num_cpus < 2)
|
||||
debug("Warning: Only 1 CPU is detected\n");
|
||||
|
||||
ret = check_cpu_devices(num_cpus);
|
||||
if (ret)
|
||||
debug("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n");
|
||||
|
||||
/* Copy needed parameters so that APs have a reference to the plan */
|
||||
mp_info.num_records = p->num_records;
|
||||
mp_info.records = p->flight_plan;
|
||||
|
||||
/* Load the SIPI vector */
|
||||
ret = load_sipi_vector(&ap_count, num_cpus);
|
||||
if (ap_count == NULL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Make sure SIPI data hits RAM so the APs that come up will see
|
||||
* the startup code even if the caches are disabled
|
||||
*/
|
||||
wbinvd();
|
||||
|
||||
/* Start the APs providing number of APs and the cpus_entered field */
|
||||
num_aps = num_cpus - 1;
|
||||
ret = start_aps(num_aps, ap_count);
|
||||
if (ret) {
|
||||
mdelay(1000);
|
||||
debug("%d/%d eventually checked in?\n", atomic_read(ap_count),
|
||||
num_aps);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Walk the flight plan for the BSP */
|
||||
ret = bsp_do_flight_plan(cpu, p);
|
||||
if (ret) {
|
||||
debug("CPU init failed: err=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp_init_cpu(struct udevice *cpu, void *unused)
|
||||
{
|
||||
struct cpu_platdata *plat = dev_get_parent_platdata(cpu);
|
||||
|
||||
/*
|
||||
* Multiple APs are brought up simultaneously and they may get the same
|
||||
* seq num in the uclass_resolve_seq() during device_probe(). To avoid
|
||||
* this, set req_seq to the reg number in the device tree in advance.
|
||||
*/
|
||||
cpu->req_seq = fdtdec_get_int(gd->fdt_blob, cpu->of_offset, "reg", -1);
|
||||
plat->ucode_version = microcode_read_rev();
|
||||
plat->device_id = gd->arch.x86_device;
|
||||
|
||||
return device_probe(cpu);
|
||||
}
|
||||
95
u-boot/arch/x86/cpu/mtrr.c
Normal file
95
u-boot/arch/x86/cpu/mtrr.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* (C) Copyright 2014 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Memory Type Range Regsters - these are used to tell the CPU whether
|
||||
* memory is cacheable and if so the cache write mode to use.
|
||||
*
|
||||
* These can speed up booting. See the mtrr command.
|
||||
*
|
||||
* Reference: Intel Architecture Software Developer's Manual, Volume 3:
|
||||
* System Programming
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/mtrr.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* Prepare to adjust MTRRs */
|
||||
void mtrr_open(struct mtrr_state *state)
|
||||
{
|
||||
if (!gd->arch.has_mtrr)
|
||||
return;
|
||||
|
||||
state->enable_cache = dcache_status();
|
||||
|
||||
if (state->enable_cache)
|
||||
disable_caches();
|
||||
state->deftype = native_read_msr(MTRR_DEF_TYPE_MSR);
|
||||
wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype & ~MTRR_DEF_TYPE_EN);
|
||||
}
|
||||
|
||||
/* Clean up after adjusting MTRRs, and enable them */
|
||||
void mtrr_close(struct mtrr_state *state)
|
||||
{
|
||||
if (!gd->arch.has_mtrr)
|
||||
return;
|
||||
|
||||
wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype | MTRR_DEF_TYPE_EN);
|
||||
if (state->enable_cache)
|
||||
enable_caches();
|
||||
}
|
||||
|
||||
int mtrr_commit(bool do_caches)
|
||||
{
|
||||
struct mtrr_request *req = gd->arch.mtrr_req;
|
||||
struct mtrr_state state;
|
||||
uint64_t mask;
|
||||
int i;
|
||||
|
||||
if (!gd->arch.has_mtrr)
|
||||
return -ENOSYS;
|
||||
|
||||
mtrr_open(&state);
|
||||
for (i = 0; i < gd->arch.mtrr_req_count; i++, req++) {
|
||||
mask = ~(req->size - 1);
|
||||
mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
|
||||
wrmsrl(MTRR_PHYS_BASE_MSR(i), req->start | req->type);
|
||||
wrmsrl(MTRR_PHYS_MASK_MSR(i), mask | MTRR_PHYS_MASK_VALID);
|
||||
}
|
||||
|
||||
/* Clear the ones that are unused */
|
||||
for (; i < MTRR_COUNT; i++)
|
||||
wrmsrl(MTRR_PHYS_MASK_MSR(i), 0);
|
||||
mtrr_close(&state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtrr_add_request(int type, uint64_t start, uint64_t size)
|
||||
{
|
||||
struct mtrr_request *req;
|
||||
uint64_t mask;
|
||||
|
||||
if (!gd->arch.has_mtrr)
|
||||
return -ENOSYS;
|
||||
|
||||
if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS)
|
||||
return -ENOSPC;
|
||||
req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++];
|
||||
req->type = type;
|
||||
req->start = start;
|
||||
req->size = size;
|
||||
debug("%d: type=%d, %08llx %08llx\n", gd->arch.mtrr_req_count - 1,
|
||||
req->type, req->start, req->size);
|
||||
mask = ~(req->size - 1);
|
||||
mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
|
||||
mask |= MTRR_PHYS_MASK_VALID;
|
||||
debug(" %016llx %016llx\n", req->start | req->type, mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
88
u-boot/arch/x86/cpu/pci.c
Normal file
88
u-boot/arch/x86/cpu/pci.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors.
|
||||
* (C) Copyright 2008,2009
|
||||
* Graeme Russ, <graeme.russ@gmail.com>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <pci.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pci.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset,
|
||||
ulong *valuep, enum pci_size_t size)
|
||||
{
|
||||
outl(bdf | (offset & 0xfc) | PCI_CFG_EN, PCI_REG_ADDR);
|
||||
switch (size) {
|
||||
case PCI_SIZE_8:
|
||||
*valuep = inb(PCI_REG_DATA + (offset & 3));
|
||||
break;
|
||||
case PCI_SIZE_16:
|
||||
*valuep = inw(PCI_REG_DATA + (offset & 2));
|
||||
break;
|
||||
case PCI_SIZE_32:
|
||||
*valuep = inl(PCI_REG_DATA);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset,
|
||||
ulong value, enum pci_size_t size)
|
||||
{
|
||||
outl(bdf | (offset & 0xfc) | PCI_CFG_EN, PCI_REG_ADDR);
|
||||
switch (size) {
|
||||
case PCI_SIZE_8:
|
||||
outb(value, PCI_REG_DATA + (offset & 3));
|
||||
break;
|
||||
case PCI_SIZE_16:
|
||||
outw(value, PCI_REG_DATA + (offset & 2));
|
||||
break;
|
||||
case PCI_SIZE_32:
|
||||
outl(value, PCI_REG_DATA);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pci_assign_irqs(int bus, int device, u8 irq[4])
|
||||
{
|
||||
pci_dev_t bdf;
|
||||
int func;
|
||||
u16 vendor;
|
||||
u8 pin, line;
|
||||
|
||||
for (func = 0; func < 8; func++) {
|
||||
bdf = PCI_BDF(bus, device, func);
|
||||
pci_read_config16(bdf, PCI_VENDOR_ID, &vendor);
|
||||
if (vendor == 0xffff || vendor == 0x0000)
|
||||
continue;
|
||||
|
||||
pci_read_config8(bdf, PCI_INTERRUPT_PIN, &pin);
|
||||
|
||||
/* PCI spec says all values except 1..4 are reserved */
|
||||
if ((pin < 1) || (pin > 4))
|
||||
continue;
|
||||
|
||||
line = irq[pin - 1];
|
||||
if (!line)
|
||||
continue;
|
||||
|
||||
debug("Assigning IRQ %d to PCI device %d.%x.%d (INT%c)\n",
|
||||
line, bus, device, func, 'A' + pin - 1);
|
||||
|
||||
pci_write_config8(bdf, PCI_INTERRUPT_LINE, line);
|
||||
}
|
||||
}
|
||||
27
u-boot/arch/x86/cpu/qemu/Kconfig
Normal file
27
u-boot/arch/x86/cpu/qemu/Kconfig
Normal file
@@ -0,0 +1,27 @@
|
||||
#
|
||||
# Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
config QEMU
|
||||
bool
|
||||
|
||||
if QEMU
|
||||
|
||||
config SYS_CAR_ADDR
|
||||
hex
|
||||
default 0xd0000
|
||||
|
||||
config SYS_CAR_SIZE
|
||||
hex
|
||||
default 0x10000
|
||||
|
||||
config ACPI_PM1_BASE
|
||||
hex
|
||||
default 0xe400
|
||||
help
|
||||
ACPI Power Managment 1 (PM1) i/o-mapped base address.
|
||||
This device is defined in ACPI specification, with 16 bytes in size.
|
||||
|
||||
endif
|
||||
11
u-boot/arch/x86/cpu/qemu/Makefile
Normal file
11
u-boot/arch/x86/cpu/qemu/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
ifndef CONFIG_EFI_STUB
|
||||
obj-y += car.o dram.o
|
||||
endif
|
||||
obj-y += qemu.o
|
||||
obj-$(CONFIG_QFW) += cpu.o e820.o
|
||||
26
u-boot/arch/x86/cpu/qemu/car.S
Normal file
26
u-boot/arch/x86/cpu/qemu/car.S
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/post.h>
|
||||
|
||||
.globl car_init
|
||||
car_init:
|
||||
/* Save the BIST result */
|
||||
movl %eax, %ebp
|
||||
|
||||
post_code(POST_CAR_START)
|
||||
|
||||
/*
|
||||
* Since we know we are running inside emulator,
|
||||
* we can do nothing here for CAR initialization.
|
||||
*/
|
||||
|
||||
/* Restore the BIST result */
|
||||
movl %ebp, %eax
|
||||
|
||||
post_code(POST_CAR_CPU_CACHE)
|
||||
jmp car_init_ret
|
||||
46
u-boot/arch/x86/cpu/qemu/cpu.c
Normal file
46
u-boot/arch/x86/cpu/qemu/cpu.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Miao Yan <yanmiaobest@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <qfw.h>
|
||||
#include <asm/cpu.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int cpu_qemu_get_desc(struct udevice *dev, char *buf, int size)
|
||||
{
|
||||
if (size < CPU_MAX_NAME_LEN)
|
||||
return -ENOSPC;
|
||||
|
||||
cpu_get_name(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpu_qemu_get_count(struct udevice *dev)
|
||||
{
|
||||
return qemu_fwcfg_online_cpus();
|
||||
}
|
||||
|
||||
static const struct cpu_ops cpu_qemu_ops = {
|
||||
.get_desc = cpu_qemu_get_desc,
|
||||
.get_count = cpu_qemu_get_count,
|
||||
};
|
||||
|
||||
static const struct udevice_id cpu_qemu_ids[] = {
|
||||
{ .compatible = "cpu-qemu" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(cpu_qemu_drv) = {
|
||||
.name = "cpu_qemu",
|
||||
.id = UCLASS_CPU,
|
||||
.of_match = cpu_qemu_ids,
|
||||
.ops = &cpu_qemu_ops,
|
||||
};
|
||||
46
u-boot/arch/x86/cpu/qemu/dram.c
Normal file
46
u-boot/arch/x86/cpu/qemu/dram.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/arch/qemu.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
u32 ram;
|
||||
|
||||
outb(HIGH_RAM_ADDR, CMOS_ADDR_PORT);
|
||||
ram = ((u32)inb(CMOS_DATA_PORT)) << 14;
|
||||
outb(LOW_RAM_ADDR, CMOS_ADDR_PORT);
|
||||
ram |= ((u32)inb(CMOS_DATA_PORT)) << 6;
|
||||
ram += 16 * 1024;
|
||||
|
||||
gd->ram_size = ram * 1024;
|
||||
post_code(POST_DRAM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dram_init_banksize(void)
|
||||
{
|
||||
gd->bd->bi_dram[0].start = 0;
|
||||
gd->bd->bi_dram[0].size = gd->ram_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function looks for the highest region of memory lower than 4GB which
|
||||
* has enough space for U-Boot where U-Boot is aligned on a page boundary.
|
||||
* It overrides the default implementation found elsewhere which simply
|
||||
* picks the end of ram, wherever that may be. The location of the stack,
|
||||
* the relocation address, and how far U-Boot is moved by relocation are
|
||||
* set in the global data structure.
|
||||
*/
|
||||
ulong board_get_usable_ram_top(ulong total_size)
|
||||
{
|
||||
return gd->ram_size;
|
||||
}
|
||||
43
u-boot/arch/x86/cpu/qemu/e820.c
Normal file
43
u-boot/arch/x86/cpu/qemu/e820.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/e820.h>
|
||||
|
||||
unsigned install_e820_map(unsigned max_entries, struct e820entry *entries)
|
||||
{
|
||||
entries[0].addr = 0;
|
||||
entries[0].size = ISA_START_ADDRESS;
|
||||
entries[0].type = E820_RAM;
|
||||
|
||||
entries[1].addr = ISA_START_ADDRESS;
|
||||
entries[1].size = ISA_END_ADDRESS - ISA_START_ADDRESS;
|
||||
entries[1].type = E820_RESERVED;
|
||||
|
||||
/*
|
||||
* since we use memalign(malloc) to allocate high memory for
|
||||
* storing ACPI tables, we need to reserve them in e820 tables,
|
||||
* otherwise kernel will reclaim them and data will be corrupted
|
||||
*/
|
||||
entries[2].addr = ISA_END_ADDRESS;
|
||||
entries[2].size = gd->relocaddr - TOTAL_MALLOC_LEN - ISA_END_ADDRESS;
|
||||
entries[2].type = E820_RAM;
|
||||
|
||||
/* for simplicity, reserve entire malloc space */
|
||||
entries[3].addr = gd->relocaddr - TOTAL_MALLOC_LEN;
|
||||
entries[3].size = TOTAL_MALLOC_LEN;
|
||||
entries[3].type = E820_RESERVED;
|
||||
|
||||
entries[4].addr = gd->relocaddr;
|
||||
entries[4].size = gd->ram_size - gd->relocaddr;
|
||||
entries[4].type = E820_RESERVED;
|
||||
|
||||
entries[5].addr = CONFIG_PCIE_ECAM_BASE;
|
||||
entries[5].size = CONFIG_PCIE_ECAM_SIZE;
|
||||
entries[5].type = E820_RESERVED;
|
||||
|
||||
return 6;
|
||||
}
|
||||
197
u-boot/arch/x86/cpu/qemu/qemu.c
Normal file
197
u-boot/arch/x86/cpu/qemu/qemu.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <pci.h>
|
||||
#include <qfw.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/arch/device.h>
|
||||
#include <asm/arch/qemu.h>
|
||||
|
||||
static bool i440fx;
|
||||
|
||||
#ifdef CONFIG_QFW
|
||||
|
||||
/* on x86, the qfw registers are all IO ports */
|
||||
#define FW_CONTROL_PORT 0x510
|
||||
#define FW_DATA_PORT 0x511
|
||||
#define FW_DMA_PORT_LOW 0x514
|
||||
#define FW_DMA_PORT_HIGH 0x518
|
||||
|
||||
static void qemu_x86_fwcfg_read_entry_pio(uint16_t entry,
|
||||
uint32_t size, void *address)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint8_t *data = address;
|
||||
|
||||
/*
|
||||
* writting FW_CFG_INVALID will cause read operation to resume at
|
||||
* last offset, otherwise read will start at offset 0
|
||||
*
|
||||
* Note: on platform where the control register is IO port, the
|
||||
* endianness is little endian.
|
||||
*/
|
||||
if (entry != FW_CFG_INVALID)
|
||||
outw(cpu_to_le16(entry), FW_CONTROL_PORT);
|
||||
|
||||
/* the endianness of data register is string-preserving */
|
||||
while (size--)
|
||||
data[i++] = inb(FW_DATA_PORT);
|
||||
}
|
||||
|
||||
static void qemu_x86_fwcfg_read_entry_dma(struct fw_cfg_dma_access *dma)
|
||||
{
|
||||
/* the DMA address register is big endian */
|
||||
outl(cpu_to_be32((uint32_t)dma), FW_DMA_PORT_HIGH);
|
||||
|
||||
while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR)
|
||||
__asm__ __volatile__ ("pause");
|
||||
}
|
||||
|
||||
static struct fw_cfg_arch_ops fwcfg_x86_ops = {
|
||||
.arch_read_pio = qemu_x86_fwcfg_read_entry_pio,
|
||||
.arch_read_dma = qemu_x86_fwcfg_read_entry_dma
|
||||
};
|
||||
#endif
|
||||
|
||||
static void enable_pm_piix(void)
|
||||
{
|
||||
u8 en;
|
||||
u16 cmd;
|
||||
|
||||
/* Set the PM I/O base */
|
||||
pci_write_config32(PIIX_PM, PMBA, CONFIG_ACPI_PM1_BASE | 1);
|
||||
|
||||
/* Enable access to the PM I/O space */
|
||||
pci_read_config16(PIIX_PM, PCI_COMMAND, &cmd);
|
||||
cmd |= PCI_COMMAND_IO;
|
||||
pci_write_config16(PIIX_PM, PCI_COMMAND, cmd);
|
||||
|
||||
/* PM I/O Space Enable (PMIOSE) */
|
||||
pci_read_config8(PIIX_PM, PMREGMISC, &en);
|
||||
en |= PMIOSE;
|
||||
pci_write_config8(PIIX_PM, PMREGMISC, en);
|
||||
}
|
||||
|
||||
static void enable_pm_ich9(void)
|
||||
{
|
||||
/* Set the PM I/O base */
|
||||
pci_write_config32(ICH9_PM, PMBA, CONFIG_ACPI_PM1_BASE | 1);
|
||||
}
|
||||
|
||||
static void qemu_chipset_init(void)
|
||||
{
|
||||
u16 device, xbcs;
|
||||
int pam, i;
|
||||
|
||||
/*
|
||||
* i440FX and Q35 chipset have different PAM register offset, but with
|
||||
* the same bitfield layout. Here we determine the offset based on its
|
||||
* PCI device ID.
|
||||
*/
|
||||
pci_read_config16(PCI_BDF(0, 0, 0), PCI_DEVICE_ID, &device);
|
||||
i440fx = (device == PCI_DEVICE_ID_INTEL_82441);
|
||||
pam = i440fx ? I440FX_PAM : Q35_PAM;
|
||||
|
||||
/*
|
||||
* Initialize Programmable Attribute Map (PAM) Registers
|
||||
*
|
||||
* Configure legacy segments C/D/E/F to system RAM
|
||||
*/
|
||||
for (i = 0; i < PAM_NUM; i++)
|
||||
pci_write_config8(PCI_BDF(0, 0, 0), pam + i, PAM_RW);
|
||||
|
||||
if (i440fx) {
|
||||
/*
|
||||
* Enable legacy IDE I/O ports decode
|
||||
*
|
||||
* Note: QEMU always decode legacy IDE I/O port on PIIX chipset.
|
||||
* However Linux ata_piix driver does sanity check on these two
|
||||
* registers to see whether legacy ports decode is turned on.
|
||||
* This is to make Linux ata_piix driver happy.
|
||||
*/
|
||||
pci_write_config16(PIIX_IDE, IDE0_TIM, IDE_DECODE_EN);
|
||||
pci_write_config16(PIIX_IDE, IDE1_TIM, IDE_DECODE_EN);
|
||||
|
||||
/* Enable I/O APIC */
|
||||
pci_read_config16(PIIX_ISA, XBCS, &xbcs);
|
||||
xbcs |= APIC_EN;
|
||||
pci_write_config16(PIIX_ISA, XBCS, xbcs);
|
||||
|
||||
enable_pm_piix();
|
||||
} else {
|
||||
/* Configure PCIe ECAM base address */
|
||||
pci_write_config32(PCI_BDF(0, 0, 0), PCIEX_BAR,
|
||||
CONFIG_PCIE_ECAM_BASE | BAR_EN);
|
||||
|
||||
enable_pm_ich9();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QFW
|
||||
qemu_fwcfg_init(&fwcfg_x86_ops);
|
||||
#endif
|
||||
}
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
post_code(POST_CPU_INIT);
|
||||
|
||||
ret = x86_cpu_init_f();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_EFI_STUB
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
post_code(POST_CPU_INFO);
|
||||
return default_print_cpuinfo();
|
||||
}
|
||||
#endif
|
||||
|
||||
void reset_cpu(ulong addr)
|
||||
{
|
||||
/* cold reset */
|
||||
x86_full_reset();
|
||||
}
|
||||
|
||||
int arch_early_init_r(void)
|
||||
{
|
||||
qemu_chipset_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERATE_MP_TABLE
|
||||
int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq)
|
||||
{
|
||||
u8 irq;
|
||||
|
||||
if (i440fx) {
|
||||
/*
|
||||
* Not like most x86 platforms, the PIRQ[A-D] on PIIX3 are not
|
||||
* connected to I/O APIC INTPIN#16-19. Instead they are routed
|
||||
* to an irq number controled by the PIRQ routing register.
|
||||
*/
|
||||
pci_read_config8(PCI_BDF(bus, dev, func),
|
||||
PCI_INTERRUPT_LINE, &irq);
|
||||
} else {
|
||||
/*
|
||||
* ICH9's PIRQ[A-H] are not consecutive numbers from 0 to 7.
|
||||
* PIRQ[A-D] still maps to [0-3] but PIRQ[E-H] maps to [8-11].
|
||||
*/
|
||||
irq = pirq < 8 ? pirq + 16 : pirq + 12;
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
#endif
|
||||
121
u-boot/arch/x86/cpu/quark/Kconfig
Normal file
121
u-boot/arch/x86/cpu/quark/Kconfig
Normal file
@@ -0,0 +1,121 @@
|
||||
#
|
||||
# Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
config INTEL_QUARK
|
||||
bool
|
||||
select HAVE_RMU
|
||||
|
||||
if INTEL_QUARK
|
||||
|
||||
config HAVE_RMU
|
||||
bool "Add a Remote Management Unit (RMU) binary"
|
||||
help
|
||||
Select this option to add a Remote Management Unit (RMU) binary
|
||||
to the resulting U-Boot image. It is a data block (up to 64K) of
|
||||
machine-specific code which must be put in the flash for the RMU
|
||||
within the Quark SoC processor to access when powered up before
|
||||
system BIOS is executed.
|
||||
|
||||
config RMU_FILE
|
||||
string "Remote Management Unit (RMU) binary filename"
|
||||
depends on HAVE_RMU
|
||||
default "rmu.bin"
|
||||
help
|
||||
The filename of the file to use as Remote Management Unit (RMU)
|
||||
binary in the board directory.
|
||||
|
||||
config RMU_ADDR
|
||||
hex "Remote Management Unit (RMU) binary location"
|
||||
depends on HAVE_RMU
|
||||
default 0xfff00000
|
||||
help
|
||||
The location of the RMU binary is determined by a strap. It must be
|
||||
put in flash at a location matching the strap-determined base address.
|
||||
|
||||
The default base address of 0xfff00000 indicates that the binary must
|
||||
be located at offset 0 from the beginning of a 1MB flash device.
|
||||
|
||||
config HAVE_CMC
|
||||
bool
|
||||
default HAVE_RMU
|
||||
|
||||
config CMC_FILE
|
||||
string
|
||||
depends on HAVE_CMC
|
||||
default RMU_FILE
|
||||
|
||||
config CMC_ADDR
|
||||
hex
|
||||
depends on HAVE_CMC
|
||||
default RMU_ADDR
|
||||
|
||||
config ESRAM_BASE
|
||||
hex
|
||||
default 0x80000000
|
||||
help
|
||||
Embedded SRAM (eSRAM) memory-mapped base address.
|
||||
|
||||
config PCIE_ECAM_BASE
|
||||
hex
|
||||
default 0xe0000000
|
||||
|
||||
config RCBA_BASE
|
||||
hex
|
||||
default 0xfed1c000
|
||||
help
|
||||
Root Complex register block memory-mapped base address.
|
||||
|
||||
config ACPI_PM1_BASE
|
||||
hex
|
||||
default 0x1000
|
||||
help
|
||||
ACPI Power Managment 1 (PM1) i/o-mapped base address.
|
||||
This device is defined in ACPI specification, with 16 bytes in size.
|
||||
|
||||
config ACPI_PBLK_BASE
|
||||
hex
|
||||
default 0x1010
|
||||
help
|
||||
ACPI Processor Block (PBLK) i/o-mapped base address.
|
||||
This device is defined in ACPI specification, with 16 bytes in size.
|
||||
|
||||
config SPI_DMA_BASE
|
||||
hex
|
||||
default 0x1020
|
||||
help
|
||||
SPI DMA i/o-mapped base address.
|
||||
|
||||
config GPIO_BASE
|
||||
hex
|
||||
default 0x1080
|
||||
help
|
||||
GPIO i/o-mapped base address.
|
||||
|
||||
config ACPI_GPE0_BASE
|
||||
hex
|
||||
default 0x1100
|
||||
help
|
||||
ACPI General Purpose Event 0 (GPE0) i/o-mapped base address.
|
||||
This device is defined in ACPI specification, with 64 bytes in size.
|
||||
|
||||
config WDT_BASE
|
||||
hex
|
||||
default 0x1140
|
||||
help
|
||||
Watchdog timer i/o-mapped base address.
|
||||
|
||||
config SYS_CAR_ADDR
|
||||
hex
|
||||
default ESRAM_BASE
|
||||
|
||||
config SYS_CAR_SIZE
|
||||
hex
|
||||
default 0x8000
|
||||
help
|
||||
Space in bytes in eSRAM used as Cache-As-ARM (CAR).
|
||||
Note this size must not exceed eSRAM's total size.
|
||||
|
||||
endif
|
||||
9
u-boot/arch/x86/cpu/quark/Makefile
Normal file
9
u-boot/arch/x86/cpu/quark/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += car.o dram.o irq.o msg_port.o quark.o
|
||||
obj-y += mrc.o mrc_util.o hte.o smc.o
|
||||
obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o
|
||||
163
u-boot/arch/x86/cpu/quark/acpi.c
Normal file
163
u-boot/arch/x86/cpu/quark/acpi.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/acpi_table.h>
|
||||
#include <asm/ioapic.h>
|
||||
#include <asm/mpspec.h>
|
||||
#include <asm/tables.h>
|
||||
#include <asm/arch/iomap.h>
|
||||
|
||||
void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs,
|
||||
void *dsdt)
|
||||
{
|
||||
struct acpi_table_header *header = &(fadt->header);
|
||||
u16 pmbase = ACPI_PM1_BASE_ADDRESS;
|
||||
|
||||
memset((void *)fadt, 0, sizeof(struct acpi_fadt));
|
||||
|
||||
acpi_fill_header(header, "FACP");
|
||||
header->length = sizeof(struct acpi_fadt);
|
||||
header->revision = 4;
|
||||
|
||||
fadt->firmware_ctrl = (u32)facs;
|
||||
fadt->dsdt = (u32)dsdt;
|
||||
fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED;
|
||||
fadt->sci_int = 9;
|
||||
fadt->smi_cmd = 0;
|
||||
fadt->acpi_enable = 0;
|
||||
fadt->acpi_disable = 0;
|
||||
fadt->s4bios_req = 0;
|
||||
fadt->pstate_cnt = 0;
|
||||
fadt->pm1a_evt_blk = pmbase;
|
||||
fadt->pm1b_evt_blk = 0x0;
|
||||
fadt->pm1a_cnt_blk = pmbase + 0x4;
|
||||
fadt->pm1b_cnt_blk = 0x0;
|
||||
fadt->pm2_cnt_blk = 0x0;
|
||||
fadt->pm_tmr_blk = pmbase + 0x8;
|
||||
fadt->gpe0_blk = ACPI_GPE0_BASE_ADDRESS;
|
||||
fadt->gpe1_blk = 0;
|
||||
fadt->pm1_evt_len = 4;
|
||||
fadt->pm1_cnt_len = 2;
|
||||
fadt->pm2_cnt_len = 0;
|
||||
fadt->pm_tmr_len = 4;
|
||||
fadt->gpe0_blk_len = 8;
|
||||
fadt->gpe1_blk_len = 0;
|
||||
fadt->gpe1_base = 0;
|
||||
fadt->cst_cnt = 0;
|
||||
fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
|
||||
fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
|
||||
fadt->flush_size = 0;
|
||||
fadt->flush_stride = 0;
|
||||
fadt->duty_offset = 1;
|
||||
fadt->duty_width = 3;
|
||||
fadt->day_alrm = 0x00;
|
||||
fadt->mon_alrm = 0x00;
|
||||
fadt->century = 0x00;
|
||||
fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES;
|
||||
fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
|
||||
ACPI_FADT_POWER_BUTTON | ACPI_FADT_SLEEP_BUTTON |
|
||||
ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_RESET_REGISTER |
|
||||
ACPI_FADT_PLATFORM_CLOCK;
|
||||
|
||||
fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->reset_reg.bit_width = 8;
|
||||
fadt->reset_reg.bit_offset = 0;
|
||||
fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
|
||||
fadt->reset_reg.addrl = IO_PORT_RESET;
|
||||
fadt->reset_reg.addrh = 0;
|
||||
fadt->reset_value = SYS_RST | RST_CPU;
|
||||
|
||||
fadt->x_firmware_ctl_l = (u32)facs;
|
||||
fadt->x_firmware_ctl_h = 0;
|
||||
fadt->x_dsdt_l = (u32)dsdt;
|
||||
fadt->x_dsdt_h = 0;
|
||||
|
||||
fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8;
|
||||
fadt->x_pm1a_evt_blk.bit_offset = 0;
|
||||
fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
|
||||
fadt->x_pm1a_evt_blk.addrl = fadt->pm1a_evt_blk;
|
||||
fadt->x_pm1a_evt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm1b_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm1b_evt_blk.bit_width = 0;
|
||||
fadt->x_pm1b_evt_blk.bit_offset = 0;
|
||||
fadt->x_pm1b_evt_blk.access_size = 0;
|
||||
fadt->x_pm1b_evt_blk.addrl = 0x0;
|
||||
fadt->x_pm1b_evt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm1a_cnt_blk.bit_width = fadt->pm1_cnt_len * 8;
|
||||
fadt->x_pm1a_cnt_blk.bit_offset = 0;
|
||||
fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
|
||||
fadt->x_pm1a_cnt_blk.addrl = fadt->pm1a_cnt_blk;
|
||||
fadt->x_pm1a_cnt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm1b_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm1b_cnt_blk.bit_width = 0;
|
||||
fadt->x_pm1b_cnt_blk.bit_offset = 0;
|
||||
fadt->x_pm1b_cnt_blk.access_size = 0;
|
||||
fadt->x_pm1b_cnt_blk.addrl = 0x0;
|
||||
fadt->x_pm1b_cnt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm2_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm2_cnt_blk.bit_width = fadt->pm2_cnt_len * 8;
|
||||
fadt->x_pm2_cnt_blk.bit_offset = 0;
|
||||
fadt->x_pm2_cnt_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
|
||||
fadt->x_pm2_cnt_blk.addrl = fadt->pm2_cnt_blk;
|
||||
fadt->x_pm2_cnt_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_pm_tmr_blk.bit_width = fadt->pm_tmr_len * 8;
|
||||
fadt->x_pm_tmr_blk.bit_offset = 0;
|
||||
fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
|
||||
fadt->x_pm_tmr_blk.addrl = fadt->pm_tmr_blk;
|
||||
fadt->x_pm_tmr_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_gpe0_blk.bit_width = fadt->gpe0_blk_len * 8;
|
||||
fadt->x_gpe0_blk.bit_offset = 0;
|
||||
fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
|
||||
fadt->x_gpe0_blk.addrl = fadt->gpe0_blk;
|
||||
fadt->x_gpe0_blk.addrh = 0x0;
|
||||
|
||||
fadt->x_gpe1_blk.space_id = ACPI_ADDRESS_SPACE_IO;
|
||||
fadt->x_gpe1_blk.bit_width = 0;
|
||||
fadt->x_gpe1_blk.bit_offset = 0;
|
||||
fadt->x_gpe1_blk.access_size = 0;
|
||||
fadt->x_gpe1_blk.addrl = 0x0;
|
||||
fadt->x_gpe1_blk.addrh = 0x0;
|
||||
|
||||
header->checksum = table_compute_checksum(fadt, header->length);
|
||||
}
|
||||
|
||||
static int acpi_create_madt_irq_overrides(u32 current)
|
||||
{
|
||||
struct acpi_madt_irqoverride *irqovr;
|
||||
u16 sci_flags = MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_HIGH;
|
||||
int length = 0;
|
||||
|
||||
irqovr = (void *)current;
|
||||
length += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0);
|
||||
|
||||
irqovr = (void *)(current + length);
|
||||
length += acpi_create_madt_irqoverride(irqovr, 0, 9, 9, sci_flags);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
u32 acpi_fill_madt(u32 current)
|
||||
{
|
||||
current += acpi_create_madt_lapics(current);
|
||||
|
||||
current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current,
|
||||
io_apic_read(IO_APIC_ID) >> 24, IO_APIC_ADDR, 0);
|
||||
|
||||
current += acpi_create_madt_irq_overrides(current);
|
||||
|
||||
return current;
|
||||
}
|
||||
105
u-boot/arch/x86/cpu/quark/car.S
Normal file
105
u-boot/arch/x86/cpu/quark/car.S
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/arch/quark.h>
|
||||
#include <asm/arch/msg_port.h>
|
||||
|
||||
.globl car_init
|
||||
car_init:
|
||||
post_code(POST_CAR_START)
|
||||
|
||||
/*
|
||||
* Quark SoC contains an embedded 512KiB SRAM (eSRAM) that is
|
||||
* initialized by hardware. eSRAM is the ideal place to be used
|
||||
* for Cache-As-RAM (CAR) before system memory is available.
|
||||
*
|
||||
* Relocate this eSRAM to a suitable location in the physical
|
||||
* memory map and enable it.
|
||||
*/
|
||||
|
||||
/* Host Memory Bound Register P03h:R08h */
|
||||
mov $((MSG_PORT_HOST_BRIDGE << 16) | (HM_BOUND << 8)), %eax
|
||||
mov $(DRAM_BASE + DRAM_MAX_SIZE + ESRAM_SIZE), %edx
|
||||
lea 1f, %esp
|
||||
jmp msg_port_write
|
||||
1:
|
||||
|
||||
/* eSRAM Block Page Control Register P05h:R82h */
|
||||
mov $((MSG_PORT_MEM_MGR << 16) | (ESRAM_BLK_CTRL << 8)), %eax
|
||||
mov $(ESRAM_BLOCK_MODE | (CONFIG_ESRAM_BASE >> 24)), %edx
|
||||
lea 2f, %esp
|
||||
jmp msg_port_write
|
||||
2:
|
||||
|
||||
post_code(POST_CAR_CPU_CACHE)
|
||||
jmp car_init_ret
|
||||
|
||||
msg_port_read:
|
||||
/*
|
||||
* Parameter:
|
||||
* eax[23:16] - Message Port ID
|
||||
* eax[15:08] - Register Address
|
||||
*
|
||||
* Return Value:
|
||||
* eax - Message Port Register value
|
||||
*
|
||||
* Return Address: esp
|
||||
*/
|
||||
|
||||
or $((MSG_OP_READ << 24) | MSG_BYTE_ENABLE), %eax
|
||||
mov %eax, %ebx
|
||||
|
||||
/* Write MCR B0:D0:F0:RD0 */
|
||||
mov $(PCI_CFG_EN | MSG_CTRL_REG), %eax
|
||||
mov $PCI_REG_ADDR, %dx
|
||||
out %eax, %dx
|
||||
mov $PCI_REG_DATA, %dx
|
||||
mov %ebx, %eax
|
||||
out %eax, %dx
|
||||
|
||||
/* Read MDR B0:D0:F0:RD4 */
|
||||
mov $(PCI_CFG_EN | MSG_DATA_REG), %eax
|
||||
mov $PCI_REG_ADDR, %dx
|
||||
out %eax, %dx
|
||||
mov $PCI_REG_DATA, %dx
|
||||
in %dx, %eax
|
||||
|
||||
jmp *%esp
|
||||
|
||||
msg_port_write:
|
||||
/*
|
||||
* Parameter:
|
||||
* eax[23:16] - Message Port ID
|
||||
* eax[15:08] - Register Address
|
||||
* edx - Message Port Register value to write
|
||||
*
|
||||
* Return Address: esp
|
||||
*/
|
||||
|
||||
or $((MSG_OP_WRITE << 24) | MSG_BYTE_ENABLE), %eax
|
||||
mov %eax, %esi
|
||||
mov %edx, %edi
|
||||
|
||||
/* Write MDR B0:D0:F0:RD4 */
|
||||
mov $(PCI_CFG_EN | MSG_DATA_REG), %eax
|
||||
mov $PCI_REG_ADDR, %dx
|
||||
out %eax, %dx
|
||||
mov $PCI_REG_DATA, %dx
|
||||
mov %edi, %eax
|
||||
out %eax, %dx
|
||||
|
||||
/* Write MCR B0:D0:F0:RD0 */
|
||||
mov $(PCI_CFG_EN | MSG_CTRL_REG), %eax
|
||||
mov $PCI_REG_ADDR, %dx
|
||||
out %eax, %dx
|
||||
mov $PCI_REG_DATA, %dx
|
||||
mov %esi, %eax
|
||||
out %eax, %dx
|
||||
|
||||
jmp *%esp
|
||||
182
u-boot/arch/x86/cpu/quark/dram.c
Normal file
182
u-boot/arch/x86/cpu/quark/dram.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/mrccache.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/arch/mrc.h>
|
||||
#include <asm/arch/msg_port.h>
|
||||
#include <asm/arch/quark.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static __maybe_unused int prepare_mrc_cache(struct mrc_params *mrc_params)
|
||||
{
|
||||
struct mrc_data_container *cache;
|
||||
struct mrc_region entry;
|
||||
int ret;
|
||||
|
||||
ret = mrccache_get_region(NULL, &entry);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cache = mrccache_find_current(&entry);
|
||||
if (!cache)
|
||||
return -ENOENT;
|
||||
|
||||
debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__,
|
||||
cache->data, cache->data_size, cache->checksum);
|
||||
|
||||
/* copy mrc cache to the mrc_params */
|
||||
memcpy(&mrc_params->timings, cache->data, cache->data_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mrc_configure_params(struct mrc_params *mrc_params)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node;
|
||||
int mrc_flags;
|
||||
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_QRK_MRC);
|
||||
if (node < 0) {
|
||||
debug("%s: Cannot find MRC node\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
mrc_params->boot_mode = prepare_mrc_cache(mrc_params);
|
||||
if (mrc_params->boot_mode)
|
||||
mrc_params->boot_mode = BM_COLD;
|
||||
else
|
||||
mrc_params->boot_mode = BM_FAST;
|
||||
#else
|
||||
mrc_params->boot_mode = BM_COLD;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
*
|
||||
* We need determine ECC by pin strap state
|
||||
*
|
||||
* Disable ECC by default for now
|
||||
*/
|
||||
mrc_params->ecc_enables = 0;
|
||||
|
||||
mrc_flags = fdtdec_get_int(blob, node, "flags", 0);
|
||||
if (mrc_flags & MRC_FLAG_SCRAMBLE_EN)
|
||||
mrc_params->scrambling_enables = 1;
|
||||
else
|
||||
mrc_params->scrambling_enables = 0;
|
||||
|
||||
mrc_params->dram_width = fdtdec_get_int(blob, node, "dram-width", 0);
|
||||
mrc_params->ddr_speed = fdtdec_get_int(blob, node, "dram-speed", 0);
|
||||
mrc_params->ddr_type = fdtdec_get_int(blob, node, "dram-type", 0);
|
||||
|
||||
mrc_params->rank_enables = fdtdec_get_int(blob, node, "rank-mask", 0);
|
||||
mrc_params->channel_enables = fdtdec_get_int(blob, node,
|
||||
"chan-mask", 0);
|
||||
mrc_params->channel_width = fdtdec_get_int(blob, node,
|
||||
"chan-width", 0);
|
||||
mrc_params->address_mode = fdtdec_get_int(blob, node, "addr-mode", 0);
|
||||
|
||||
mrc_params->refresh_rate = fdtdec_get_int(blob, node,
|
||||
"refresh-rate", 0);
|
||||
mrc_params->sr_temp_range = fdtdec_get_int(blob, node,
|
||||
"sr-temp-range", 0);
|
||||
mrc_params->ron_value = fdtdec_get_int(blob, node,
|
||||
"ron-value", 0);
|
||||
mrc_params->rtt_nom_value = fdtdec_get_int(blob, node,
|
||||
"rtt-nom-value", 0);
|
||||
mrc_params->rd_odt_value = fdtdec_get_int(blob, node,
|
||||
"rd-odt-value", 0);
|
||||
|
||||
mrc_params->params.density = fdtdec_get_int(blob, node,
|
||||
"dram-density", 0);
|
||||
mrc_params->params.cl = fdtdec_get_int(blob, node, "dram-cl", 0);
|
||||
mrc_params->params.ras = fdtdec_get_int(blob, node, "dram-ras", 0);
|
||||
mrc_params->params.wtr = fdtdec_get_int(blob, node, "dram-wtr", 0);
|
||||
mrc_params->params.rrd = fdtdec_get_int(blob, node, "dram-rrd", 0);
|
||||
mrc_params->params.faw = fdtdec_get_int(blob, node, "dram-faw", 0);
|
||||
|
||||
debug("MRC dram_width %d\n", mrc_params->dram_width);
|
||||
debug("MRC rank_enables %d\n", mrc_params->rank_enables);
|
||||
debug("MRC ddr_speed %d\n", mrc_params->ddr_speed);
|
||||
debug("MRC flags: %s\n",
|
||||
(mrc_params->scrambling_enables) ? "SCRAMBLE_EN" : "");
|
||||
|
||||
debug("MRC density=%d tCL=%d tRAS=%d tWTR=%d tRRD=%d tFAW=%d\n",
|
||||
mrc_params->params.density, mrc_params->params.cl,
|
||||
mrc_params->params.ras, mrc_params->params.wtr,
|
||||
mrc_params->params.rrd, mrc_params->params.faw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
struct mrc_params mrc_params;
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
char *cache;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
memset(&mrc_params, 0, sizeof(struct mrc_params));
|
||||
ret = mrc_configure_params(&mrc_params);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set up the DRAM by calling the memory reference code */
|
||||
mrc_init(&mrc_params);
|
||||
if (mrc_params.status)
|
||||
return -EIO;
|
||||
|
||||
gd->ram_size = mrc_params.mem_size;
|
||||
post_code(POST_DRAM);
|
||||
|
||||
/* variable range MTRR#2: RAM area */
|
||||
disable_caches();
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_VAR_PHYBASE(MTRR_VAR_RAM),
|
||||
0 | MTRR_TYPE_WRBACK);
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_VAR_PHYMASK(MTRR_VAR_RAM),
|
||||
(~(gd->ram_size - 1)) | MTRR_PHYS_MASK_VALID);
|
||||
enable_caches();
|
||||
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
cache = malloc(sizeof(struct mrc_timings));
|
||||
if (cache) {
|
||||
memcpy(cache, &mrc_params.timings, sizeof(struct mrc_timings));
|
||||
gd->arch.mrc_output = cache;
|
||||
gd->arch.mrc_output_len = sizeof(struct mrc_timings);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dram_init_banksize(void)
|
||||
{
|
||||
gd->bd->bi_dram[0].start = 0;
|
||||
gd->bd->bi_dram[0].size = gd->ram_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function looks for the highest region of memory lower than 4GB which
|
||||
* has enough space for U-Boot where U-Boot is aligned on a page boundary.
|
||||
* It overrides the default implementation found elsewhere which simply
|
||||
* picks the end of ram, wherever that may be. The location of the stack,
|
||||
* the relocation address, and how far U-Boot is moved by relocation are
|
||||
* set in the global data structure.
|
||||
*/
|
||||
ulong board_get_usable_ram_top(ulong total_size)
|
||||
{
|
||||
return gd->ram_size;
|
||||
}
|
||||
396
u-boot/arch/x86/cpu/quark/hte.c
Normal file
396
u-boot/arch/x86/cpu/quark/hte.c
Normal file
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* Ported from Intel released Quark UEFI BIOS
|
||||
* QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
|
||||
*
|
||||
* SPDX-License-Identifier: Intel
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/mrc.h>
|
||||
#include <asm/arch/msg_port.h>
|
||||
#include "mrc_util.h"
|
||||
#include "hte.h"
|
||||
|
||||
/**
|
||||
* Enable HTE to detect all possible errors for the given training parameters
|
||||
* (per-bit or full byte lane).
|
||||
*/
|
||||
static void hte_enable_all_errors(void)
|
||||
{
|
||||
msg_port_write(HTE, 0x000200a2, 0xffffffff);
|
||||
msg_port_write(HTE, 0x000200a3, 0x000000ff);
|
||||
msg_port_write(HTE, 0x000200a4, 0x00000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go and read the HTE register in order to find any error
|
||||
*
|
||||
* @return: The errors detected in the HTE status register
|
||||
*/
|
||||
static u32 hte_check_errors(void)
|
||||
{
|
||||
return msg_port_read(HTE, 0x000200a7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until HTE finishes
|
||||
*/
|
||||
static void hte_wait_for_complete(void)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
ENTERFN();
|
||||
|
||||
do {} while ((msg_port_read(HTE, 0x00020012) & (1 << 30)) != 0);
|
||||
|
||||
tmp = msg_port_read(HTE, 0x00020011);
|
||||
tmp |= (1 << 9);
|
||||
tmp &= ~((1 << 12) | (1 << 13));
|
||||
msg_port_write(HTE, 0x00020011, tmp);
|
||||
|
||||
LEAVEFN();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear registers related with errors in the HTE
|
||||
*/
|
||||
static void hte_clear_error_regs(void)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
/*
|
||||
* Clear all HTE errors and enable error checking
|
||||
* for burst and chunk.
|
||||
*/
|
||||
tmp = msg_port_read(HTE, 0x000200a1);
|
||||
tmp |= (1 << 8);
|
||||
msg_port_write(HTE, 0x000200a1, tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a basic single-cache-line memory write/read/verify test using simple
|
||||
* constant pattern, different for READ_TRAIN and WRITE_TRAIN modes.
|
||||
*
|
||||
* See hte_basic_write_read() which is the external visible wrapper.
|
||||
*
|
||||
* @mrc_params: host structure for all MRC global data
|
||||
* @addr: memory adress being tested (must hit specific channel/rank)
|
||||
* @first_run: if set then the HTE registers are configured, otherwise it is
|
||||
* assumed configuration is done and we just re-run the test
|
||||
* @mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
|
||||
*
|
||||
* @return: byte lane failure on each bit (for Quark only bit0 and bit1)
|
||||
*/
|
||||
static u16 hte_basic_data_cmp(struct mrc_params *mrc_params, u32 addr,
|
||||
u8 first_run, u8 mode)
|
||||
{
|
||||
u32 pattern;
|
||||
u32 offset;
|
||||
|
||||
if (first_run) {
|
||||
msg_port_write(HTE, 0x00020020, 0x01b10021);
|
||||
msg_port_write(HTE, 0x00020021, 0x06000000);
|
||||
msg_port_write(HTE, 0x00020022, addr >> 6);
|
||||
msg_port_write(HTE, 0x00020062, 0x00800015);
|
||||
msg_port_write(HTE, 0x00020063, 0xaaaaaaaa);
|
||||
msg_port_write(HTE, 0x00020064, 0xcccccccc);
|
||||
msg_port_write(HTE, 0x00020065, 0xf0f0f0f0);
|
||||
msg_port_write(HTE, 0x00020061, 0x00030008);
|
||||
|
||||
if (mode == WRITE_TRAIN)
|
||||
pattern = 0xc33c0000;
|
||||
else /* READ_TRAIN */
|
||||
pattern = 0xaa5555aa;
|
||||
|
||||
for (offset = 0x80; offset <= 0x8f; offset++)
|
||||
msg_port_write(HTE, offset, pattern);
|
||||
}
|
||||
|
||||
msg_port_write(HTE, 0x000200a1, 0xffff1000);
|
||||
msg_port_write(HTE, 0x00020011, 0x00011000);
|
||||
msg_port_write(HTE, 0x00020011, 0x00011100);
|
||||
|
||||
hte_wait_for_complete();
|
||||
|
||||
/*
|
||||
* Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for
|
||||
* any bytelane errors.
|
||||
*/
|
||||
return (hte_check_errors() >> 8) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine a single-cache-line memory with write/read/verify test using multiple
|
||||
* data patterns (victim-aggressor algorithm).
|
||||
*
|
||||
* See hte_write_stress_bit_lanes() which is the external visible wrapper.
|
||||
*
|
||||
* @mrc_params: host structure for all MRC global data
|
||||
* @addr: memory adress being tested (must hit specific channel/rank)
|
||||
* @loop_cnt: number of test iterations
|
||||
* @seed_victim: victim data pattern seed
|
||||
* @seed_aggressor: aggressor data pattern seed
|
||||
* @victim_bit: should be 0 as auto-rotate feature is in use
|
||||
* @first_run: if set then the HTE registers are configured, otherwise it is
|
||||
* assumed configuration is done and we just re-run the test
|
||||
*
|
||||
* @return: byte lane failure on each bit (for Quark only bit0 and bit1)
|
||||
*/
|
||||
static u16 hte_rw_data_cmp(struct mrc_params *mrc_params, u32 addr,
|
||||
u8 loop_cnt, u32 seed_victim, u32 seed_aggressor,
|
||||
u8 victim_bit, u8 first_run)
|
||||
{
|
||||
u32 offset;
|
||||
u32 tmp;
|
||||
|
||||
if (first_run) {
|
||||
msg_port_write(HTE, 0x00020020, 0x00910024);
|
||||
msg_port_write(HTE, 0x00020023, 0x00810024);
|
||||
msg_port_write(HTE, 0x00020021, 0x06070000);
|
||||
msg_port_write(HTE, 0x00020024, 0x06070000);
|
||||
msg_port_write(HTE, 0x00020022, addr >> 6);
|
||||
msg_port_write(HTE, 0x00020025, addr >> 6);
|
||||
msg_port_write(HTE, 0x00020062, 0x0000002a);
|
||||
msg_port_write(HTE, 0x00020063, seed_victim);
|
||||
msg_port_write(HTE, 0x00020064, seed_aggressor);
|
||||
msg_port_write(HTE, 0x00020065, seed_victim);
|
||||
|
||||
/*
|
||||
* Write the pattern buffers to select the victim bit
|
||||
*
|
||||
* Start with bit0
|
||||
*/
|
||||
for (offset = 0x80; offset <= 0x8f; offset++) {
|
||||
if ((offset % 8) == victim_bit)
|
||||
msg_port_write(HTE, offset, 0x55555555);
|
||||
else
|
||||
msg_port_write(HTE, offset, 0xcccccccc);
|
||||
}
|
||||
|
||||
msg_port_write(HTE, 0x00020061, 0x00000000);
|
||||
msg_port_write(HTE, 0x00020066, 0x03440000);
|
||||
msg_port_write(HTE, 0x000200a1, 0xffff1000);
|
||||
}
|
||||
|
||||
tmp = 0x10001000 | (loop_cnt << 16);
|
||||
msg_port_write(HTE, 0x00020011, tmp);
|
||||
msg_port_write(HTE, 0x00020011, tmp | (1 << 8));
|
||||
|
||||
hte_wait_for_complete();
|
||||
|
||||
/*
|
||||
* Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for
|
||||
* any bytelane errors.
|
||||
*/
|
||||
return (hte_check_errors() >> 8) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use HW HTE engine to initialize or test all memory attached to a given DUNIT.
|
||||
* If flag is MRC_MEM_INIT, this routine writes 0s to all memory locations to
|
||||
* initialize ECC. If flag is MRC_MEM_TEST, this routine will send an 5AA55AA5
|
||||
* pattern to all memory locations on the RankMask and then read it back.
|
||||
* Then it sends an A55AA55A pattern to all memory locations on the RankMask
|
||||
* and reads it back.
|
||||
*
|
||||
* @mrc_params: host structure for all MRC global data
|
||||
* @flag: MRC_MEM_INIT or MRC_MEM_TEST
|
||||
*
|
||||
* @return: errors register showing HTE failures. Also prints out which rank
|
||||
* failed the HTE test if failure occurs. For rank detection to work,
|
||||
* the address map must be left in its default state. If MRC changes
|
||||
* the address map, this function must be modified to change it back
|
||||
* to default at the beginning, then restore it at the end.
|
||||
*/
|
||||
u32 hte_mem_init(struct mrc_params *mrc_params, u8 flag)
|
||||
{
|
||||
u32 offset;
|
||||
int test_num;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Clear out the error registers at the start of each memory
|
||||
* init or memory test run.
|
||||
*/
|
||||
hte_clear_error_regs();
|
||||
|
||||
msg_port_write(HTE, 0x00020062, 0x00000015);
|
||||
|
||||
for (offset = 0x80; offset <= 0x8f; offset++)
|
||||
msg_port_write(HTE, offset, ((offset & 1) ? 0xa55a : 0x5aa5));
|
||||
|
||||
msg_port_write(HTE, 0x00020021, 0x00000000);
|
||||
msg_port_write(HTE, 0x00020022, (mrc_params->mem_size >> 6) - 1);
|
||||
msg_port_write(HTE, 0x00020063, 0xaaaaaaaa);
|
||||
msg_port_write(HTE, 0x00020064, 0xcccccccc);
|
||||
msg_port_write(HTE, 0x00020065, 0xf0f0f0f0);
|
||||
msg_port_write(HTE, 0x00020066, 0x03000000);
|
||||
|
||||
switch (flag) {
|
||||
case MRC_MEM_INIT:
|
||||
/*
|
||||
* Only 1 write pass through memory is needed
|
||||
* to initialize ECC
|
||||
*/
|
||||
test_num = 1;
|
||||
break;
|
||||
case MRC_MEM_TEST:
|
||||
/* Write/read then write/read with inverted pattern */
|
||||
test_num = 4;
|
||||
break;
|
||||
default:
|
||||
DPF(D_INFO, "Unknown parameter for flag: %d\n", flag);
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
DPF(D_INFO, "hte_mem_init");
|
||||
|
||||
for (i = 0; i < test_num; i++) {
|
||||
DPF(D_INFO, ".");
|
||||
|
||||
if (i == 0) {
|
||||
msg_port_write(HTE, 0x00020061, 0x00000000);
|
||||
msg_port_write(HTE, 0x00020020, 0x00110010);
|
||||
} else if (i == 1) {
|
||||
msg_port_write(HTE, 0x00020061, 0x00000000);
|
||||
msg_port_write(HTE, 0x00020020, 0x00010010);
|
||||
} else if (i == 2) {
|
||||
msg_port_write(HTE, 0x00020061, 0x00010100);
|
||||
msg_port_write(HTE, 0x00020020, 0x00110010);
|
||||
} else {
|
||||
msg_port_write(HTE, 0x00020061, 0x00010100);
|
||||
msg_port_write(HTE, 0x00020020, 0x00010010);
|
||||
}
|
||||
|
||||
msg_port_write(HTE, 0x00020011, 0x00111000);
|
||||
msg_port_write(HTE, 0x00020011, 0x00111100);
|
||||
|
||||
hte_wait_for_complete();
|
||||
|
||||
/* If this is a READ pass, check for errors at the end */
|
||||
if ((i % 2) == 1) {
|
||||
/* Return immediately if error */
|
||||
if (hte_check_errors())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DPF(D_INFO, "done\n");
|
||||
|
||||
return hte_check_errors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a basic single-cache-line memory write/read/verify test using simple
|
||||
* constant pattern, different for READ_TRAIN and WRITE_TRAIN modes.
|
||||
*
|
||||
* @mrc_params: host structure for all MRC global data
|
||||
* @addr: memory adress being tested (must hit specific channel/rank)
|
||||
* @first_run: if set then the HTE registers are configured, otherwise it is
|
||||
* assumed configuration is done and we just re-run the test
|
||||
* @mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
|
||||
*
|
||||
* @return: byte lane failure on each bit (for Quark only bit0 and bit1)
|
||||
*/
|
||||
u16 hte_basic_write_read(struct mrc_params *mrc_params, u32 addr,
|
||||
u8 first_run, u8 mode)
|
||||
{
|
||||
u16 errors;
|
||||
|
||||
ENTERFN();
|
||||
|
||||
/* Enable all error reporting in preparation for HTE test */
|
||||
hte_enable_all_errors();
|
||||
hte_clear_error_regs();
|
||||
|
||||
errors = hte_basic_data_cmp(mrc_params, addr, first_run, mode);
|
||||
|
||||
LEAVEFN();
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine a single-cache-line memory with write/read/verify test using multiple
|
||||
* data patterns (victim-aggressor algorithm).
|
||||
*
|
||||
* @mrc_params: host structure for all MRC global data
|
||||
* @addr: memory adress being tested (must hit specific channel/rank)
|
||||
* @first_run: if set then the HTE registers are configured, otherwise it is
|
||||
* assumed configuration is done and we just re-run the test
|
||||
*
|
||||
* @return: byte lane failure on each bit (for Quark only bit0 and bit1)
|
||||
*/
|
||||
u16 hte_write_stress_bit_lanes(struct mrc_params *mrc_params,
|
||||
u32 addr, u8 first_run)
|
||||
{
|
||||
u16 errors;
|
||||
u8 victim_bit = 0;
|
||||
|
||||
ENTERFN();
|
||||
|
||||
/* Enable all error reporting in preparation for HTE test */
|
||||
hte_enable_all_errors();
|
||||
hte_clear_error_regs();
|
||||
|
||||
/*
|
||||
* Loop through each bit in the bytelane.
|
||||
*
|
||||
* Each pass creates a victim bit while keeping all other bits the same
|
||||
* as aggressors. AVN HTE adds an auto-rotate feature which allows us
|
||||
* to program the entire victim/aggressor sequence in 1 step.
|
||||
*
|
||||
* The victim bit rotates on each pass so no need to have software
|
||||
* implement a victim bit loop like on VLV.
|
||||
*/
|
||||
errors = hte_rw_data_cmp(mrc_params, addr, HTE_LOOP_CNT,
|
||||
HTE_LFSR_VICTIM_SEED, HTE_LFSR_AGRESSOR_SEED,
|
||||
victim_bit, first_run);
|
||||
|
||||
LEAVEFN();
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a basic single-cache-line memory write or read.
|
||||
* This is just for receive enable / fine write-levelling purpose.
|
||||
*
|
||||
* @addr: memory adress being tested (must hit specific channel/rank)
|
||||
* @first_run: if set then the HTE registers are configured, otherwise it is
|
||||
* assumed configuration is done and we just re-run the test
|
||||
* @is_write: when non-zero memory write operation executed, otherwise read
|
||||
*/
|
||||
void hte_mem_op(u32 addr, u8 first_run, u8 is_write)
|
||||
{
|
||||
u32 offset;
|
||||
u32 tmp;
|
||||
|
||||
hte_enable_all_errors();
|
||||
hte_clear_error_regs();
|
||||
|
||||
if (first_run) {
|
||||
tmp = is_write ? 0x01110021 : 0x01010021;
|
||||
msg_port_write(HTE, 0x00020020, tmp);
|
||||
|
||||
msg_port_write(HTE, 0x00020021, 0x06000000);
|
||||
msg_port_write(HTE, 0x00020022, addr >> 6);
|
||||
msg_port_write(HTE, 0x00020062, 0x00800015);
|
||||
msg_port_write(HTE, 0x00020063, 0xaaaaaaaa);
|
||||
msg_port_write(HTE, 0x00020064, 0xcccccccc);
|
||||
msg_port_write(HTE, 0x00020065, 0xf0f0f0f0);
|
||||
msg_port_write(HTE, 0x00020061, 0x00030008);
|
||||
|
||||
for (offset = 0x80; offset <= 0x8f; offset++)
|
||||
msg_port_write(HTE, offset, 0xc33c0000);
|
||||
}
|
||||
|
||||
msg_port_write(HTE, 0x000200a1, 0xffff1000);
|
||||
msg_port_write(HTE, 0x00020011, 0x00011000);
|
||||
msg_port_write(HTE, 0x00020011, 0x00011100);
|
||||
|
||||
hte_wait_for_complete();
|
||||
}
|
||||
44
u-boot/arch/x86/cpu/quark/hte.h
Normal file
44
u-boot/arch/x86/cpu/quark/hte.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* Ported from Intel released Quark UEFI BIOS
|
||||
* QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
|
||||
*
|
||||
* SPDX-License-Identifier: Intel
|
||||
*/
|
||||
|
||||
#ifndef _HTE_H_
|
||||
#define _HTE_H_
|
||||
|
||||
enum {
|
||||
MRC_MEM_INIT,
|
||||
MRC_MEM_TEST
|
||||
};
|
||||
|
||||
enum {
|
||||
READ_TRAIN,
|
||||
WRITE_TRAIN
|
||||
};
|
||||
|
||||
/*
|
||||
* EXP_LOOP_CNT field of HTE_CMD_CTL
|
||||
*
|
||||
* This CANNOT be less than 4!
|
||||
*/
|
||||
#define HTE_LOOP_CNT 5
|
||||
|
||||
/* random seed for victim */
|
||||
#define HTE_LFSR_VICTIM_SEED 0xf294ba21
|
||||
|
||||
/* random seed for aggressor */
|
||||
#define HTE_LFSR_AGRESSOR_SEED 0xeba7492d
|
||||
|
||||
u32 hte_mem_init(struct mrc_params *mrc_params, u8 flag);
|
||||
u16 hte_basic_write_read(struct mrc_params *mrc_params, u32 addr,
|
||||
u8 first_run, u8 mode);
|
||||
u16 hte_write_stress_bit_lanes(struct mrc_params *mrc_params,
|
||||
u32 addr, u8 first_run);
|
||||
void hte_mem_op(u32 addr, u8 first_run, u8 is_write);
|
||||
|
||||
#endif /* _HTE_H_ */
|
||||
49
u-boot/arch/x86/cpu/quark/irq.c
Normal file
49
u-boot/arch/x86/cpu/quark/irq.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
* Copyright (C) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/arch/device.h>
|
||||
#include <asm/arch/quark.h>
|
||||
|
||||
int quark_irq_router_probe(struct udevice *dev)
|
||||
{
|
||||
struct quark_rcba *rcba;
|
||||
u32 base;
|
||||
|
||||
qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, LB_RCBA, &base);
|
||||
base &= ~MEM_BAR_EN;
|
||||
rcba = (struct quark_rcba *)base;
|
||||
|
||||
/*
|
||||
* Route Quark PCI device interrupt pin to PIRQ
|
||||
*
|
||||
* Route device#23's INTA/B/C/D to PIRQA/B/C/D
|
||||
* Route device#20,21's INTA/B/C/D to PIRQE/F/G/H
|
||||
*/
|
||||
writew(PIRQC, &rcba->rmu_ir);
|
||||
writew(PIRQA | (PIRQB << 4) | (PIRQC << 8) | (PIRQD << 12),
|
||||
&rcba->d23_ir);
|
||||
writew(PIRQD, &rcba->core_ir);
|
||||
writew(PIRQE | (PIRQF << 4) | (PIRQG << 8) | (PIRQH << 12),
|
||||
&rcba->d20d21_ir);
|
||||
|
||||
return irq_router_common_init(dev);
|
||||
}
|
||||
|
||||
static const struct udevice_id quark_irq_router_ids[] = {
|
||||
{ .compatible = "intel,quark-irq-router" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(quark_irq_router_drv) = {
|
||||
.name = "quark_intel_irq",
|
||||
.id = UCLASS_IRQ,
|
||||
.of_match = quark_irq_router_ids,
|
||||
.probe = quark_irq_router_probe,
|
||||
};
|
||||
205
u-boot/arch/x86/cpu/quark/mrc.c
Normal file
205
u-boot/arch/x86/cpu/quark/mrc.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* Ported from Intel released Quark UEFI BIOS
|
||||
* QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
|
||||
*
|
||||
* SPDX-License-Identifier: Intel
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the main Quark Memory Reference Code (MRC)
|
||||
*
|
||||
* These functions are generic and should work for any Quark-based board.
|
||||
*
|
||||
* MRC requires two data structures to be passed in which are initialized by
|
||||
* mrc_adjust_params().
|
||||
*
|
||||
* The basic flow is as follows:
|
||||
* 01) Check for supported DDR speed configuration
|
||||
* 02) Set up Memory Manager buffer as pass-through (POR)
|
||||
* 03) Set Channel Interleaving Mode and Channel Stride to the most aggressive
|
||||
* setting possible
|
||||
* 04) Set up the Memory Controller logic
|
||||
* 05) Set up the DDR_PHY logic
|
||||
* 06) Initialise the DRAMs (JEDEC)
|
||||
* 07) Perform the Receive Enable Calibration algorithm
|
||||
* 08) Perform the Write Leveling algorithm
|
||||
* 09) Perform the Read Training algorithm (includes internal Vref)
|
||||
* 10) Perform the Write Training algorithm
|
||||
* 11) Set Channel Interleaving Mode and Channel Stride to the desired settings
|
||||
*
|
||||
* DRAM unit configuration based on Valleyview MRC.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <version.h>
|
||||
#include <asm/arch/mrc.h>
|
||||
#include <asm/arch/msg_port.h>
|
||||
#include "mrc_util.h"
|
||||
#include "smc.h"
|
||||
|
||||
static const struct mem_init init[] = {
|
||||
{ 0x0101, BM_COLD | BM_FAST | BM_WARM | BM_S3, clear_self_refresh },
|
||||
{ 0x0200, BM_COLD | BM_FAST | BM_WARM | BM_S3, prog_ddr_timing_control },
|
||||
{ 0x0103, BM_COLD | BM_FAST , prog_decode_before_jedec },
|
||||
{ 0x0104, BM_COLD | BM_FAST , perform_ddr_reset },
|
||||
{ 0x0300, BM_COLD | BM_FAST | BM_S3, ddrphy_init },
|
||||
{ 0x0400, BM_COLD | BM_FAST , perform_jedec_init },
|
||||
{ 0x0105, BM_COLD | BM_FAST , set_ddr_init_complete },
|
||||
{ 0x0106, BM_FAST | BM_WARM | BM_S3, restore_timings },
|
||||
{ 0x0106, BM_COLD , default_timings },
|
||||
{ 0x0500, BM_COLD , rcvn_cal },
|
||||
{ 0x0600, BM_COLD , wr_level },
|
||||
{ 0x0120, BM_COLD , prog_page_ctrl },
|
||||
{ 0x0700, BM_COLD , rd_train },
|
||||
{ 0x0800, BM_COLD , wr_train },
|
||||
{ 0x010b, BM_COLD , store_timings },
|
||||
{ 0x010c, BM_COLD | BM_FAST | BM_WARM | BM_S3, enable_scrambling },
|
||||
{ 0x010d, BM_COLD | BM_FAST | BM_WARM | BM_S3, prog_ddr_control },
|
||||
{ 0x010e, BM_COLD | BM_FAST | BM_WARM | BM_S3, prog_dra_drb },
|
||||
{ 0x010f, BM_WARM | BM_S3, perform_wake },
|
||||
{ 0x0110, BM_COLD | BM_FAST | BM_WARM | BM_S3, change_refresh_period },
|
||||
{ 0x0111, BM_COLD | BM_FAST | BM_WARM | BM_S3, set_auto_refresh },
|
||||
{ 0x0112, BM_COLD | BM_FAST | BM_WARM | BM_S3, ecc_enable },
|
||||
{ 0x0113, BM_COLD | BM_FAST , memory_test },
|
||||
{ 0x0114, BM_COLD | BM_FAST | BM_WARM | BM_S3, lock_registers }
|
||||
};
|
||||
|
||||
/* Adjust configuration parameters before initialization sequence */
|
||||
static void mrc_adjust_params(struct mrc_params *mrc_params)
|
||||
{
|
||||
const struct dram_params *dram_params;
|
||||
uint8_t dram_width;
|
||||
uint32_t rank_enables;
|
||||
uint32_t channel_width;
|
||||
|
||||
ENTERFN();
|
||||
|
||||
/* initially expect success */
|
||||
mrc_params->status = MRC_SUCCESS;
|
||||
|
||||
dram_width = mrc_params->dram_width;
|
||||
rank_enables = mrc_params->rank_enables;
|
||||
channel_width = mrc_params->channel_width;
|
||||
|
||||
/*
|
||||
* Setup board layout (must be reviewed as is selecting static timings)
|
||||
* 0 == R0 (DDR3 x16), 1 == R1 (DDR3 x16),
|
||||
* 2 == DV (DDR3 x8), 3 == SV (DDR3 x8).
|
||||
*/
|
||||
if (dram_width == X8)
|
||||
mrc_params->board_id = 2; /* select x8 layout */
|
||||
else
|
||||
mrc_params->board_id = 0; /* select x16 layout */
|
||||
|
||||
/* initially no memory */
|
||||
mrc_params->mem_size = 0;
|
||||
|
||||
/* begin of channel settings */
|
||||
dram_params = &mrc_params->params;
|
||||
|
||||
/*
|
||||
* Determine column bits:
|
||||
*
|
||||
* Column: 11 for 8Gbx8, else 10
|
||||
*/
|
||||
mrc_params->column_bits[0] =
|
||||
(dram_params[0].density == 4) &&
|
||||
(dram_width == X8) ? 11 : 10;
|
||||
|
||||
/*
|
||||
* Determine row bits:
|
||||
*
|
||||
* 512Mbx16=12 512Mbx8=13
|
||||
* 1Gbx16=13 1Gbx8=14
|
||||
* 2Gbx16=14 2Gbx8=15
|
||||
* 4Gbx16=15 4Gbx8=16
|
||||
* 8Gbx16=16 8Gbx8=16
|
||||
*/
|
||||
mrc_params->row_bits[0] = 12 + dram_params[0].density +
|
||||
(dram_params[0].density < 4) &&
|
||||
(dram_width == X8) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Determine per-channel memory size:
|
||||
*
|
||||
* (For 2 RANKs, multiply by 2)
|
||||
* (For 16 bit data bus, divide by 2)
|
||||
*
|
||||
* DENSITY WIDTH MEM_AVAILABLE
|
||||
* 512Mb x16 0x008000000 ( 128MB)
|
||||
* 512Mb x8 0x010000000 ( 256MB)
|
||||
* 1Gb x16 0x010000000 ( 256MB)
|
||||
* 1Gb x8 0x020000000 ( 512MB)
|
||||
* 2Gb x16 0x020000000 ( 512MB)
|
||||
* 2Gb x8 0x040000000 (1024MB)
|
||||
* 4Gb x16 0x040000000 (1024MB)
|
||||
* 4Gb x8 0x080000000 (2048MB)
|
||||
*/
|
||||
mrc_params->channel_size[0] = 1 << dram_params[0].density;
|
||||
mrc_params->channel_size[0] *= (dram_width == X8) ? 2 : 1;
|
||||
mrc_params->channel_size[0] *= (rank_enables == 0x3) ? 2 : 1;
|
||||
mrc_params->channel_size[0] *= (channel_width == X16) ? 1 : 2;
|
||||
|
||||
/* Determine memory size (convert number of 64MB/512Mb units) */
|
||||
mrc_params->mem_size += mrc_params->channel_size[0] << 26;
|
||||
|
||||
LEAVEFN();
|
||||
}
|
||||
|
||||
static void mrc_mem_init(struct mrc_params *mrc_params)
|
||||
{
|
||||
int i;
|
||||
|
||||
ENTERFN();
|
||||
|
||||
/* MRC started */
|
||||
mrc_post_code(0x01, 0x00);
|
||||
|
||||
if (mrc_params->boot_mode != BM_COLD) {
|
||||
if (mrc_params->ddr_speed != mrc_params->timings.ddr_speed) {
|
||||
/* full training required as frequency changed */
|
||||
mrc_params->boot_mode = BM_COLD;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(init); i++) {
|
||||
uint64_t my_tsc;
|
||||
|
||||
if (mrc_params->boot_mode & init[i].boot_path) {
|
||||
uint8_t major = init[i].post_code >> 8 & 0xff;
|
||||
uint8_t minor = init[i].post_code >> 0 & 0xff;
|
||||
mrc_post_code(major, minor);
|
||||
|
||||
my_tsc = rdtsc();
|
||||
init[i].init_fn(mrc_params);
|
||||
DPF(D_TIME, "Execution time %llx", rdtsc() - my_tsc);
|
||||
}
|
||||
}
|
||||
|
||||
/* display the timings */
|
||||
print_timings(mrc_params);
|
||||
|
||||
/* MRC complete */
|
||||
mrc_post_code(0x01, 0xff);
|
||||
|
||||
LEAVEFN();
|
||||
}
|
||||
|
||||
void mrc_init(struct mrc_params *mrc_params)
|
||||
{
|
||||
ENTERFN();
|
||||
|
||||
DPF(D_INFO, "MRC Version %04x %s %s\n", MRC_VERSION,
|
||||
U_BOOT_DATE, U_BOOT_TIME);
|
||||
|
||||
/* Set up the data structures used by mrc_mem_init() */
|
||||
mrc_adjust_params(mrc_params);
|
||||
|
||||
/* Initialize system memory */
|
||||
mrc_mem_init(mrc_params);
|
||||
|
||||
LEAVEFN();
|
||||
}
|
||||
1472
u-boot/arch/x86/cpu/quark/mrc_util.c
Normal file
1472
u-boot/arch/x86/cpu/quark/mrc_util.c
Normal file
File diff suppressed because it is too large
Load Diff
119
u-boot/arch/x86/cpu/quark/mrc_util.h
Normal file
119
u-boot/arch/x86/cpu/quark/mrc_util.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* Ported from Intel released Quark UEFI BIOS
|
||||
* QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
|
||||
*
|
||||
* SPDX-License-Identifier: Intel
|
||||
*/
|
||||
|
||||
#ifndef _MRC_UTIL_H_
|
||||
#define _MRC_UTIL_H_
|
||||
|
||||
/* Turn on this macro to enable MRC debugging output */
|
||||
#undef MRC_DEBUG
|
||||
|
||||
/* MRC Debug Support */
|
||||
#define DPF debug_cond
|
||||
|
||||
/* debug print type */
|
||||
|
||||
#ifdef MRC_DEBUG
|
||||
#define D_ERROR 0x0001
|
||||
#define D_INFO 0x0002
|
||||
#define D_REGRD 0x0004
|
||||
#define D_REGWR 0x0008
|
||||
#define D_FCALL 0x0010
|
||||
#define D_TRN 0x0020
|
||||
#define D_TIME 0x0040
|
||||
#else
|
||||
#define D_ERROR 0
|
||||
#define D_INFO 0
|
||||
#define D_REGRD 0
|
||||
#define D_REGWR 0
|
||||
#define D_FCALL 0
|
||||
#define D_TRN 0
|
||||
#define D_TIME 0
|
||||
#endif
|
||||
|
||||
#define ENTERFN(...) debug_cond(D_FCALL, "<%s>\n", __func__)
|
||||
#define LEAVEFN(...) debug_cond(D_FCALL, "</%s>\n", __func__)
|
||||
#define REPORTFN(...) debug_cond(D_FCALL, "<%s/>\n", __func__)
|
||||
|
||||
/* Message Bus Port */
|
||||
#define MEM_CTLR 0x01
|
||||
#define HOST_BRIDGE 0x03
|
||||
#define MEM_MGR 0x05
|
||||
#define HTE 0x11
|
||||
#define DDRPHY 0x12
|
||||
|
||||
/* number of sample points */
|
||||
#define SAMPLE_CNT 3
|
||||
/* number of PIs to increment per sample */
|
||||
#define SAMPLE_DLY 26
|
||||
|
||||
enum {
|
||||
/* indicates to decrease delays when looking for edge */
|
||||
BACKWARD,
|
||||
/* indicates to increase delays when looking for edge */
|
||||
FORWARD
|
||||
};
|
||||
|
||||
enum {
|
||||
RCVN,
|
||||
WDQS,
|
||||
WDQX,
|
||||
RDQS,
|
||||
VREF,
|
||||
WCMD,
|
||||
WCTL,
|
||||
WCLK,
|
||||
MAX_ALGOS,
|
||||
};
|
||||
|
||||
void mrc_write_mask(u32 unit, u32 addr, u32 data, u32 mask);
|
||||
void mrc_alt_write_mask(u32 unit, u32 addr, u32 data, u32 mask);
|
||||
void mrc_post_code(uint8_t major, uint8_t minor);
|
||||
void delay_n(uint32_t ns);
|
||||
void delay_u(uint32_t ms);
|
||||
void select_mem_mgr(void);
|
||||
void select_hte(void);
|
||||
void dram_init_command(uint32_t data);
|
||||
void dram_wake_command(void);
|
||||
void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane);
|
||||
|
||||
void set_rcvn(uint8_t channel, uint8_t rank,
|
||||
uint8_t byte_lane, uint32_t pi_count);
|
||||
uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane);
|
||||
void set_rdqs(uint8_t channel, uint8_t rank,
|
||||
uint8_t byte_lane, uint32_t pi_count);
|
||||
uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);
|
||||
void set_wdqs(uint8_t channel, uint8_t rank,
|
||||
uint8_t byte_lane, uint32_t pi_count);
|
||||
uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);
|
||||
void set_wdq(uint8_t channel, uint8_t rank,
|
||||
uint8_t byte_lane, uint32_t pi_count);
|
||||
uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane);
|
||||
void set_wcmd(uint8_t channel, uint32_t pi_count);
|
||||
uint32_t get_wcmd(uint8_t channel);
|
||||
void set_wclk(uint8_t channel, uint8_t rank, uint32_t pi_count);
|
||||
uint32_t get_wclk(uint8_t channel, uint8_t rank);
|
||||
void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count);
|
||||
uint32_t get_wctl(uint8_t channel, uint8_t rank);
|
||||
void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting);
|
||||
uint32_t get_vref(uint8_t channel, uint8_t byte_lane);
|
||||
|
||||
uint32_t get_addr(uint8_t channel, uint8_t rank);
|
||||
uint32_t sample_dqs(struct mrc_params *mrc_params, uint8_t channel,
|
||||
uint8_t rank, bool rcvn);
|
||||
void find_rising_edge(struct mrc_params *mrc_params, uint32_t delay[],
|
||||
uint8_t channel, uint8_t rank, bool rcvn);
|
||||
uint32_t byte_lane_mask(struct mrc_params *mrc_params);
|
||||
uint32_t check_rw_coarse(struct mrc_params *mrc_params, uint32_t address);
|
||||
uint32_t check_bls_ex(struct mrc_params *mrc_params, uint32_t address);
|
||||
void lfsr32(uint32_t *lfsr_ptr);
|
||||
void clear_pointers(void);
|
||||
void print_timings(struct mrc_params *mrc_params);
|
||||
|
||||
#endif /* _MRC_UTIL_H_ */
|
||||
77
u-boot/arch/x86/cpu/quark/msg_port.c
Normal file
77
u-boot/arch/x86/cpu/quark/msg_port.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/device.h>
|
||||
#include <asm/arch/msg_port.h>
|
||||
#include <asm/arch/quark.h>
|
||||
|
||||
void msg_port_setup(int op, int port, int reg)
|
||||
{
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_REG,
|
||||
(((op) << 24) | ((port) << 16) |
|
||||
(((reg) << 8) & 0xff00) | MSG_BYTE_ENABLE));
|
||||
}
|
||||
|
||||
u32 msg_port_read(u8 port, u32 reg)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
|
||||
reg & 0xffffff00);
|
||||
msg_port_setup(MSG_OP_READ, port, reg);
|
||||
qrk_pci_read_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void msg_port_write(u8 port, u32 reg, u32 value)
|
||||
{
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, value);
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
|
||||
reg & 0xffffff00);
|
||||
msg_port_setup(MSG_OP_WRITE, port, reg);
|
||||
}
|
||||
|
||||
u32 msg_port_alt_read(u8 port, u32 reg)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
|
||||
reg & 0xffffff00);
|
||||
msg_port_setup(MSG_OP_ALT_READ, port, reg);
|
||||
qrk_pci_read_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void msg_port_alt_write(u8 port, u32 reg, u32 value)
|
||||
{
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, value);
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
|
||||
reg & 0xffffff00);
|
||||
msg_port_setup(MSG_OP_ALT_WRITE, port, reg);
|
||||
}
|
||||
|
||||
u32 msg_port_io_read(u8 port, u32 reg)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
|
||||
reg & 0xffffff00);
|
||||
msg_port_setup(MSG_OP_IO_READ, port, reg);
|
||||
qrk_pci_read_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void msg_port_io_write(u8 port, u32 reg, u32 value)
|
||||
{
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, value);
|
||||
qrk_pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG,
|
||||
reg & 0xffffff00);
|
||||
msg_port_setup(MSG_OP_IO_WRITE, port, reg);
|
||||
}
|
||||
366
u-boot/arch/x86/cpu/quark/quark.c
Normal file
366
u-boot/arch/x86/cpu/quark/quark.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mmc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/ioapic.h>
|
||||
#include <asm/mrccache.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/arch/device.h>
|
||||
#include <asm/arch/msg_port.h>
|
||||
#include <asm/arch/quark.h>
|
||||
|
||||
static struct pci_device_id mmc_supported[] = {
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_SDIO },
|
||||
{},
|
||||
};
|
||||
|
||||
static void quark_setup_mtrr(void)
|
||||
{
|
||||
u32 base, mask;
|
||||
int i;
|
||||
|
||||
disable_caches();
|
||||
|
||||
/* mark the VGA RAM area as uncacheable */
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_FIX_16K_A0000,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE));
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_FIX_16K_B0000,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE));
|
||||
|
||||
/* mark other fixed range areas as cacheable */
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_FIX_64K_00000,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_FIX_64K_40000,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_FIX_16K_80000,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_FIX_16K_90000,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
|
||||
for (i = MTRR_FIX_4K_C0000; i <= MTRR_FIX_4K_FC000; i++)
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, i,
|
||||
MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
|
||||
|
||||
/* variable range MTRR#0: ROM area */
|
||||
mask = ~(CONFIG_SYS_MONITOR_LEN - 1);
|
||||
base = CONFIG_SYS_TEXT_BASE & mask;
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_VAR_PHYBASE(MTRR_VAR_ROM),
|
||||
base | MTRR_TYPE_WRBACK);
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_VAR_PHYMASK(MTRR_VAR_ROM),
|
||||
mask | MTRR_PHYS_MASK_VALID);
|
||||
|
||||
/* variable range MTRR#1: eSRAM area */
|
||||
mask = ~(ESRAM_SIZE - 1);
|
||||
base = CONFIG_ESRAM_BASE & mask;
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_VAR_PHYBASE(MTRR_VAR_ESRAM),
|
||||
base | MTRR_TYPE_WRBACK);
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_VAR_PHYMASK(MTRR_VAR_ESRAM),
|
||||
mask | MTRR_PHYS_MASK_VALID);
|
||||
|
||||
/* enable both variable and fixed range MTRRs */
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, MTRR_DEF_TYPE,
|
||||
MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN);
|
||||
|
||||
enable_caches();
|
||||
}
|
||||
|
||||
static void quark_setup_bars(void)
|
||||
{
|
||||
/* GPIO - D31:F0:R44h */
|
||||
qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_GBA,
|
||||
CONFIG_GPIO_BASE | IO_BAR_EN);
|
||||
|
||||
/* ACPI PM1 Block - D31:F0:R48h */
|
||||
qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_PM1BLK,
|
||||
CONFIG_ACPI_PM1_BASE | IO_BAR_EN);
|
||||
|
||||
/* GPE0 - D31:F0:R4Ch */
|
||||
qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_GPE0BLK,
|
||||
CONFIG_ACPI_GPE0_BASE | IO_BAR_EN);
|
||||
|
||||
/* WDT - D31:F0:R84h */
|
||||
qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_WDTBA,
|
||||
CONFIG_WDT_BASE | IO_BAR_EN);
|
||||
|
||||
/* RCBA - D31:F0:RF0h */
|
||||
qrk_pci_write_config_dword(QUARK_LEGACY_BRIDGE, LB_RCBA,
|
||||
CONFIG_RCBA_BASE | MEM_BAR_EN);
|
||||
|
||||
/* ACPI P Block - Msg Port 04:R70h */
|
||||
msg_port_write(MSG_PORT_RMU, PBLK_BA,
|
||||
CONFIG_ACPI_PBLK_BASE | IO_BAR_EN);
|
||||
|
||||
/* SPI DMA - Msg Port 04:R7Ah */
|
||||
msg_port_write(MSG_PORT_RMU, SPI_DMA_BA,
|
||||
CONFIG_SPI_DMA_BASE | IO_BAR_EN);
|
||||
|
||||
/* PCIe ECAM */
|
||||
msg_port_write(MSG_PORT_MEM_ARBITER, AEC_CTRL,
|
||||
CONFIG_PCIE_ECAM_BASE | MEM_BAR_EN);
|
||||
msg_port_write(MSG_PORT_HOST_BRIDGE, HEC_REG,
|
||||
CONFIG_PCIE_ECAM_BASE | MEM_BAR_EN);
|
||||
}
|
||||
|
||||
static void quark_pcie_early_init(void)
|
||||
{
|
||||
/*
|
||||
* Step1: Assert PCIe signal PERST#
|
||||
*
|
||||
* The CPU interface to the PERST# signal is platform dependent.
|
||||
* Call the board-specific codes to perform this task.
|
||||
*/
|
||||
board_assert_perst();
|
||||
|
||||
/* Step2: PHY common lane reset */
|
||||
msg_port_alt_setbits(MSG_PORT_SOC_UNIT, PCIE_CFG, PCIE_PHY_LANE_RST);
|
||||
/* wait 1 ms for PHY common lane reset */
|
||||
mdelay(1);
|
||||
|
||||
/* Step3: PHY sideband interface reset and controller main reset */
|
||||
msg_port_alt_setbits(MSG_PORT_SOC_UNIT, PCIE_CFG,
|
||||
PCIE_PHY_SB_RST | PCIE_CTLR_MAIN_RST);
|
||||
/* wait 80ms for PLL to lock */
|
||||
mdelay(80);
|
||||
|
||||
/* Step4: Controller sideband interface reset */
|
||||
msg_port_alt_setbits(MSG_PORT_SOC_UNIT, PCIE_CFG, PCIE_CTLR_SB_RST);
|
||||
/* wait 20ms for controller sideband interface reset */
|
||||
mdelay(20);
|
||||
|
||||
/* Step5: De-assert PERST# */
|
||||
board_deassert_perst();
|
||||
|
||||
/* Step6: Controller primary interface reset */
|
||||
msg_port_alt_setbits(MSG_PORT_SOC_UNIT, PCIE_CFG, PCIE_CTLR_PRI_RST);
|
||||
|
||||
/* Mixer Load Lane 0 */
|
||||
msg_port_io_clrbits(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L0,
|
||||
(1 << 6) | (1 << 7));
|
||||
|
||||
/* Mixer Load Lane 1 */
|
||||
msg_port_io_clrbits(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L1,
|
||||
(1 << 6) | (1 << 7));
|
||||
}
|
||||
|
||||
static void quark_usb_early_init(void)
|
||||
{
|
||||
/* The sequence below comes from Quark firmware writer guide */
|
||||
|
||||
msg_port_alt_clrsetbits(MSG_PORT_USB_AFE, USB2_GLOBAL_PORT,
|
||||
1 << 1, (1 << 6) | (1 << 7));
|
||||
|
||||
msg_port_alt_clrsetbits(MSG_PORT_USB_AFE, USB2_COMPBG,
|
||||
(1 << 8) | (1 << 9), (1 << 7) | (1 << 10));
|
||||
|
||||
msg_port_alt_setbits(MSG_PORT_USB_AFE, USB2_PLL2, 1 << 29);
|
||||
|
||||
msg_port_alt_setbits(MSG_PORT_USB_AFE, USB2_PLL1, 1 << 1);
|
||||
|
||||
msg_port_alt_clrsetbits(MSG_PORT_USB_AFE, USB2_PLL1,
|
||||
(1 << 3) | (1 << 4) | (1 << 5), 1 << 6);
|
||||
|
||||
msg_port_alt_clrbits(MSG_PORT_USB_AFE, USB2_PLL2, 1 << 29);
|
||||
|
||||
msg_port_alt_setbits(MSG_PORT_USB_AFE, USB2_PLL2, 1 << 24);
|
||||
}
|
||||
|
||||
static void quark_thermal_early_init(void)
|
||||
{
|
||||
/* The sequence below comes from Quark firmware writer guide */
|
||||
|
||||
/* thermal sensor mode config */
|
||||
msg_port_alt_clrsetbits(MSG_PORT_SOC_UNIT, TS_CFG1,
|
||||
(1 << 3) | (1 << 4) | (1 << 5), 1 << 5);
|
||||
msg_port_alt_clrsetbits(MSG_PORT_SOC_UNIT, TS_CFG1,
|
||||
(1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) |
|
||||
(1 << 12), 1 << 9);
|
||||
msg_port_alt_setbits(MSG_PORT_SOC_UNIT, TS_CFG1, 1 << 14);
|
||||
msg_port_alt_clrbits(MSG_PORT_SOC_UNIT, TS_CFG1, 1 << 17);
|
||||
msg_port_alt_clrbits(MSG_PORT_SOC_UNIT, TS_CFG1, 1 << 18);
|
||||
msg_port_alt_clrsetbits(MSG_PORT_SOC_UNIT, TS_CFG2, 0xffff, 0x011f);
|
||||
msg_port_alt_clrsetbits(MSG_PORT_SOC_UNIT, TS_CFG3, 0xff, 0x17);
|
||||
msg_port_alt_clrsetbits(MSG_PORT_SOC_UNIT, TS_CFG3,
|
||||
(1 << 8) | (1 << 9), 1 << 8);
|
||||
msg_port_alt_clrbits(MSG_PORT_SOC_UNIT, TS_CFG3, 0xff000000);
|
||||
msg_port_alt_clrsetbits(MSG_PORT_SOC_UNIT, TS_CFG4,
|
||||
0x7ff800, 0xc8 << 11);
|
||||
|
||||
/* thermal monitor catastrophic trip set point (105 celsius) */
|
||||
msg_port_clrsetbits(MSG_PORT_RMU, TS_TRIP, 0xff, 155);
|
||||
|
||||
/* thermal monitor catastrophic trip clear point (0 celsius) */
|
||||
msg_port_clrsetbits(MSG_PORT_RMU, TS_TRIP, 0xff0000, 50 << 16);
|
||||
|
||||
/* take thermal sensor out of reset */
|
||||
msg_port_alt_clrbits(MSG_PORT_SOC_UNIT, TS_CFG4, 1 << 0);
|
||||
|
||||
/* enable thermal monitor */
|
||||
msg_port_setbits(MSG_PORT_RMU, TS_MODE, 1 << 15);
|
||||
|
||||
/* lock all thermal configuration */
|
||||
msg_port_setbits(MSG_PORT_RMU, RMU_CTRL, (1 << 5) | (1 << 6));
|
||||
}
|
||||
|
||||
static void quark_enable_legacy_seg(void)
|
||||
{
|
||||
msg_port_setbits(MSG_PORT_HOST_BRIDGE, HMISC2,
|
||||
HMISC2_SEGE | HMISC2_SEGF | HMISC2_SEGAB);
|
||||
}
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
post_code(POST_CPU_INIT);
|
||||
|
||||
ret = x86_cpu_init_f();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Quark SoC does not support MSR MTRRs. Fixed and variable range MTRRs
|
||||
* are accessed indirectly via the message port and not the traditional
|
||||
* MSR mechanism. Only UC, WT and WB cache types are supported.
|
||||
*/
|
||||
quark_setup_mtrr();
|
||||
|
||||
/*
|
||||
* Quark SoC has some non-standard BARs (excluding PCI standard BARs)
|
||||
* which need be initialized with suggested values
|
||||
*/
|
||||
quark_setup_bars();
|
||||
|
||||
/* Initialize USB2 PHY */
|
||||
quark_usb_early_init();
|
||||
|
||||
/* Initialize thermal sensor */
|
||||
quark_thermal_early_init();
|
||||
|
||||
/* Turn on legacy segments (A/B/E/F) decode to system RAM */
|
||||
quark_enable_legacy_seg();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_cpu_init_dm(void)
|
||||
{
|
||||
/*
|
||||
* Initialize PCIe controller
|
||||
*
|
||||
* Quark SoC holds the PCIe controller in reset following a power on.
|
||||
* U-Boot needs to release the PCIe controller from reset. The PCIe
|
||||
* controller (D23:F0/F1) will not be visible in PCI configuration
|
||||
* space and any access to its PCI configuration registers will cause
|
||||
* system hang while it is held in reset.
|
||||
*/
|
||||
quark_pcie_early_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
post_code(POST_CPU_INFO);
|
||||
return default_print_cpuinfo();
|
||||
}
|
||||
|
||||
void reset_cpu(ulong addr)
|
||||
{
|
||||
/* cold reset */
|
||||
x86_full_reset();
|
||||
}
|
||||
|
||||
static void quark_pcie_init(void)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* PCIe upstream non-posted & posted request size */
|
||||
qrk_pci_write_config_dword(QUARK_PCIE0, PCIE_RP_CCFG,
|
||||
CCFG_UPRS | CCFG_UNRS);
|
||||
qrk_pci_write_config_dword(QUARK_PCIE1, PCIE_RP_CCFG,
|
||||
CCFG_UPRS | CCFG_UNRS);
|
||||
|
||||
/* PCIe packet fast transmit mode (IPF) */
|
||||
qrk_pci_write_config_dword(QUARK_PCIE0, PCIE_RP_MPC2, MPC2_IPF);
|
||||
qrk_pci_write_config_dword(QUARK_PCIE1, PCIE_RP_MPC2, MPC2_IPF);
|
||||
|
||||
/* PCIe message bus idle counter (SBIC) */
|
||||
qrk_pci_read_config_dword(QUARK_PCIE0, PCIE_RP_MBC, &val);
|
||||
val |= MBC_SBIC;
|
||||
qrk_pci_write_config_dword(QUARK_PCIE0, PCIE_RP_MBC, val);
|
||||
qrk_pci_read_config_dword(QUARK_PCIE1, PCIE_RP_MBC, &val);
|
||||
val |= MBC_SBIC;
|
||||
qrk_pci_write_config_dword(QUARK_PCIE1, PCIE_RP_MBC, val);
|
||||
}
|
||||
|
||||
static void quark_usb_init(void)
|
||||
{
|
||||
u32 bar;
|
||||
|
||||
/* Change USB EHCI packet buffer OUT/IN threshold */
|
||||
qrk_pci_read_config_dword(QUARK_USB_EHCI, PCI_BASE_ADDRESS_0, &bar);
|
||||
writel((0x7f << 16) | 0x7f, bar + EHCI_INSNREG01);
|
||||
|
||||
/* Disable USB device interrupts */
|
||||
qrk_pci_read_config_dword(QUARK_USB_DEVICE, PCI_BASE_ADDRESS_0, &bar);
|
||||
writel(0x7f, bar + USBD_INT_MASK);
|
||||
writel((0xf << 16) | 0xf, bar + USBD_EP_INT_MASK);
|
||||
writel((0xf << 16) | 0xf, bar + USBD_EP_INT_STS);
|
||||
}
|
||||
|
||||
int arch_early_init_r(void)
|
||||
{
|
||||
quark_pcie_init();
|
||||
|
||||
quark_usb_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_mmc_init(bd_t *bis)
|
||||
{
|
||||
return pci_mmc_init("Quark SDHCI", mmc_supported);
|
||||
}
|
||||
|
||||
int arch_misc_init(void)
|
||||
{
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
/*
|
||||
* We intend not to check any return value here, as even MRC cache
|
||||
* is not saved successfully, it is not a severe error that will
|
||||
* prevent system from continuing to boot.
|
||||
*/
|
||||
mrccache_save();
|
||||
#endif
|
||||
|
||||
/* Assign a unique I/O APIC ID */
|
||||
io_apic_set_id(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void board_final_cleanup(void)
|
||||
{
|
||||
struct quark_rcba *rcba;
|
||||
u32 base, val;
|
||||
|
||||
qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, LB_RCBA, &base);
|
||||
base &= ~MEM_BAR_EN;
|
||||
rcba = (struct quark_rcba *)base;
|
||||
|
||||
/* Initialize 'Component ID' to zero */
|
||||
val = readl(&rcba->esd);
|
||||
val &= ~0xff0000;
|
||||
writel(val, &rcba->esd);
|
||||
|
||||
/* Lock HMBOUND for security */
|
||||
msg_port_setbits(MSG_PORT_HOST_BRIDGE, HM_BOUND, HM_BOUND_LOCK);
|
||||
|
||||
return;
|
||||
}
|
||||
2621
u-boot/arch/x86/cpu/quark/smc.c
Normal file
2621
u-boot/arch/x86/cpu/quark/smc.c
Normal file
File diff suppressed because it is too large
Load Diff
533
u-boot/arch/x86/cpu/quark/smc.h
Normal file
533
u-boot/arch/x86/cpu/quark/smc.h
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* Ported from Intel released Quark UEFI BIOS
|
||||
* QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
|
||||
*
|
||||
* SPDX-License-Identifier: Intel
|
||||
*/
|
||||
|
||||
#ifndef _SMC_H_
|
||||
#define _SMC_H_
|
||||
|
||||
/* System Memory Controller Register Defines */
|
||||
|
||||
/* Memory Controller Message Bus Registers Offsets */
|
||||
#define DRP 0x00
|
||||
#define DTR0 0x01
|
||||
#define DTR1 0x02
|
||||
#define DTR2 0x03
|
||||
#define DTR3 0x04
|
||||
#define DTR4 0x05
|
||||
#define DPMC0 0x06
|
||||
#define DPMC1 0x07
|
||||
#define DRFC 0x08
|
||||
#define DSCH 0x09
|
||||
#define DCAL 0x0a
|
||||
#define DRMC 0x0b
|
||||
#define PMSTS 0x0c
|
||||
#define DCO 0x0f
|
||||
#define DSTAT 0x20
|
||||
#define SSKPD0 0x4a
|
||||
#define SSKPD1 0x4b
|
||||
#define DECCCTRL 0x60
|
||||
#define DECCSTAT 0x61
|
||||
#define DECCSBECNT 0x62
|
||||
#define DECCSBECA 0x68
|
||||
#define DECCSBECS 0x69
|
||||
#define DECCDBECA 0x6a
|
||||
#define DECCDBECS 0x6b
|
||||
#define DFUSESTAT 0x70
|
||||
#define SCRMSEED 0x80
|
||||
#define SCRMLO 0x81
|
||||
#define SCRMHI 0x82
|
||||
|
||||
/* DRP register defines */
|
||||
#define DRP_RKEN0 (1 << 0)
|
||||
#define DRP_RKEN1 (1 << 1)
|
||||
#define DRP_PRI64BSPLITEN (1 << 13)
|
||||
#define DRP_ADDRMAP_MAP0 (1 << 14)
|
||||
#define DRP_ADDRMAP_MAP1 (1 << 15)
|
||||
#define DRP_ADDRMAP_MASK 0x0000c000
|
||||
|
||||
/* DTR0 register defines */
|
||||
#define DTR0_DFREQ_MASK 0x00000003
|
||||
#define DTR0_TRP_MASK 0x000000f0
|
||||
#define DTR0_TRCD_MASK 0x00000f00
|
||||
#define DTR0_TCL_MASK 0x00007000
|
||||
|
||||
/* DTR1 register defines */
|
||||
#define DTR1_TWCL_MASK 0x00000007
|
||||
#define DTR1_TCMD_MASK 0x00000030
|
||||
#define DTR1_TWTP_MASK 0x00000f00
|
||||
#define DTR1_TCCD_12CLK (1 << 12)
|
||||
#define DTR1_TCCD_18CLK (1 << 13)
|
||||
#define DTR1_TCCD_MASK 0x00003000
|
||||
#define DTR1_TFAW_MASK 0x000f0000
|
||||
#define DTR1_TRAS_MASK 0x00f00000
|
||||
#define DTR1_TRRD_MASK 0x03000000
|
||||
#define DTR1_TRTP_MASK 0x70000000
|
||||
|
||||
/* DTR2 register defines */
|
||||
#define DTR2_TRRDR_MASK 0x00000007
|
||||
#define DTR2_TWWDR_MASK 0x00000700
|
||||
#define DTR2_TRWDR_MASK 0x000f0000
|
||||
|
||||
/* DTR3 register defines */
|
||||
#define DTR3_TWRDR_MASK 0x00000007
|
||||
#define DTR3_TXXXX_MASK 0x00000070
|
||||
#define DTR3_TRWSR_MASK 0x00000f00
|
||||
#define DTR3_TWRSR_MASK 0x0001e000
|
||||
#define DTR3_TXP_MASK 0x00c00000
|
||||
|
||||
/* DTR4 register defines */
|
||||
#define DTR4_WRODTSTRT_MASK 0x00000003
|
||||
#define DTR4_WRODTSTOP_MASK 0x00000070
|
||||
#define DTR4_XXXX1_MASK 0x00000700
|
||||
#define DTR4_XXXX2_MASK 0x00007000
|
||||
#define DTR4_ODTDIS (1 << 15)
|
||||
#define DTR4_TRGSTRDIS (1 << 16)
|
||||
|
||||
/* DPMC0 register defines */
|
||||
#define DPMC0_PCLSTO_MASK 0x00070000
|
||||
#define DPMC0_PREAPWDEN (1 << 21)
|
||||
#define DPMC0_DYNSREN (1 << 23)
|
||||
#define DPMC0_CLKGTDIS (1 << 24)
|
||||
#define DPMC0_DISPWRDN (1 << 25)
|
||||
#define DPMC0_ENPHYCLKGATE (1 << 29)
|
||||
|
||||
/* DRFC register defines */
|
||||
#define DRFC_TREFI_MASK 0x00007000
|
||||
#define DRFC_REFDBTCLR (1 << 21)
|
||||
|
||||
/* DSCH register defines */
|
||||
#define DSCH_OOODIS (1 << 8)
|
||||
#define DSCH_OOOST3DIS (1 << 9)
|
||||
#define DSCH_NEWBYPDIS (1 << 12)
|
||||
|
||||
/* DCAL register defines */
|
||||
#define DCAL_ZQCINT_MASK 0x00000700
|
||||
#define DCAL_SRXZQCL_MASK 0x00003000
|
||||
|
||||
/* DRMC register defines */
|
||||
#define DRMC_CKEMODE (1 << 4)
|
||||
#define DRMC_ODTMODE (1 << 12)
|
||||
#define DRMC_COLDWAKE (1 << 16)
|
||||
|
||||
/* PMSTS register defines */
|
||||
#define PMSTS_DISR (1 << 0)
|
||||
|
||||
/* DCO register defines */
|
||||
#define DCO_DRPLOCK (1 << 0)
|
||||
#define DCO_CPGCLOCK (1 << 8)
|
||||
#define DCO_PMICTL (1 << 28)
|
||||
#define DCO_PMIDIS (1 << 29)
|
||||
#define DCO_IC (1 << 31)
|
||||
|
||||
/* DECCCTRL register defines */
|
||||
#define DECCCTRL_SBEEN (1 << 0)
|
||||
#define DECCCTRL_DBEEN (1 << 1)
|
||||
#define DECCCTRL_ENCBGEN (1 << 17)
|
||||
|
||||
/* DRAM init command */
|
||||
#define DCMD_MRS1(rnk, dat) (0 | ((rnk) << 22) | (1 << 3) | ((dat) << 6))
|
||||
#define DCMD_REF(rnk) (1 | ((rnk) << 22))
|
||||
#define DCMD_PRE(rnk) (2 | ((rnk) << 22))
|
||||
#define DCMD_PREA(rnk) (2 | ((rnk) << 22) | (0x400 << 6))
|
||||
#define DCMD_ACT(rnk, row) (3 | ((rnk) << 22) | ((row) << 6))
|
||||
#define DCMD_WR(rnk, col) (4 | ((rnk) << 22) | ((col) << 6))
|
||||
#define DCMD_RD(rnk, col) (5 | ((rnk) << 22) | ((col) << 6))
|
||||
#define DCMD_ZQCS(rnk) (6 | ((rnk) << 22))
|
||||
#define DCMD_ZQCL(rnk) (6 | ((rnk) << 22) | (0x400 << 6))
|
||||
#define DCMD_NOP(rnk) (7 | ((rnk) << 22))
|
||||
|
||||
#define DDR3_EMRS1_DIC_40 0
|
||||
#define DDR3_EMRS1_DIC_34 1
|
||||
|
||||
#define DDR3_EMRS1_RTTNOM_0 0
|
||||
#define DDR3_EMRS1_RTTNOM_60 0x04
|
||||
#define DDR3_EMRS1_RTTNOM_120 0x40
|
||||
#define DDR3_EMRS1_RTTNOM_40 0x44
|
||||
#define DDR3_EMRS1_RTTNOM_20 0x200
|
||||
#define DDR3_EMRS1_RTTNOM_30 0x204
|
||||
|
||||
#define DDR3_EMRS2_RTTWR_60 (1 << 9)
|
||||
#define DDR3_EMRS2_RTTWR_120 (1 << 10)
|
||||
|
||||
/* BEGIN DDRIO Registers */
|
||||
|
||||
/* DDR IOs & COMPs */
|
||||
#define DDRIODQ_BL_OFFSET 0x0800
|
||||
#define DDRIODQ_CH_OFFSET ((NUM_BYTE_LANES / 2) * DDRIODQ_BL_OFFSET)
|
||||
#define DDRIOCCC_CH_OFFSET 0x0800
|
||||
#define DDRCOMP_CH_OFFSET 0x0100
|
||||
|
||||
/* CH0-BL01-DQ */
|
||||
#define DQOBSCKEBBCTL 0x0000
|
||||
#define DQDLLTXCTL 0x0004
|
||||
#define DQDLLRXCTL 0x0008
|
||||
#define DQMDLLCTL 0x000c
|
||||
#define B0RXIOBUFCTL 0x0010
|
||||
#define B0VREFCTL 0x0014
|
||||
#define B0RXOFFSET1 0x0018
|
||||
#define B0RXOFFSET0 0x001c
|
||||
#define B1RXIOBUFCTL 0x0020
|
||||
#define B1VREFCTL 0x0024
|
||||
#define B1RXOFFSET1 0x0028
|
||||
#define B1RXOFFSET0 0x002c
|
||||
#define DQDFTCTL 0x0030
|
||||
#define DQTRAINSTS 0x0034
|
||||
#define B1DLLPICODER0 0x0038
|
||||
#define B0DLLPICODER0 0x003c
|
||||
#define B1DLLPICODER1 0x0040
|
||||
#define B0DLLPICODER1 0x0044
|
||||
#define B1DLLPICODER2 0x0048
|
||||
#define B0DLLPICODER2 0x004c
|
||||
#define B1DLLPICODER3 0x0050
|
||||
#define B0DLLPICODER3 0x0054
|
||||
#define B1RXDQSPICODE 0x0058
|
||||
#define B0RXDQSPICODE 0x005c
|
||||
#define B1RXDQPICODER32 0x0060
|
||||
#define B1RXDQPICODER10 0x0064
|
||||
#define B0RXDQPICODER32 0x0068
|
||||
#define B0RXDQPICODER10 0x006c
|
||||
#define B01PTRCTL0 0x0070
|
||||
#define B01PTRCTL1 0x0074
|
||||
#define B01DBCTL0 0x0078
|
||||
#define B01DBCTL1 0x007c
|
||||
#define B0LATCTL0 0x0080
|
||||
#define B1LATCTL0 0x0084
|
||||
#define B01LATCTL1 0x0088
|
||||
#define B0ONDURCTL 0x008c
|
||||
#define B1ONDURCTL 0x0090
|
||||
#define B0OVRCTL 0x0094
|
||||
#define B1OVRCTL 0x0098
|
||||
#define DQCTL 0x009c
|
||||
#define B0RK2RKCHGPTRCTRL 0x00a0
|
||||
#define B1RK2RKCHGPTRCTRL 0x00a4
|
||||
#define DQRK2RKCTL 0x00a8
|
||||
#define DQRK2RKPTRCTL 0x00ac
|
||||
#define B0RK2RKLAT 0x00b0
|
||||
#define B1RK2RKLAT 0x00b4
|
||||
#define DQCLKALIGNREG0 0x00b8
|
||||
#define DQCLKALIGNREG1 0x00bc
|
||||
#define DQCLKALIGNREG2 0x00c0
|
||||
#define DQCLKALIGNSTS0 0x00c4
|
||||
#define DQCLKALIGNSTS1 0x00c8
|
||||
#define DQCLKGATE 0x00cc
|
||||
#define B0COMPSLV1 0x00d0
|
||||
#define B1COMPSLV1 0x00d4
|
||||
#define B0COMPSLV2 0x00d8
|
||||
#define B1COMPSLV2 0x00dc
|
||||
#define B0COMPSLV3 0x00e0
|
||||
#define B1COMPSLV3 0x00e4
|
||||
#define DQVISALANECR0TOP 0x00e8
|
||||
#define DQVISALANECR1TOP 0x00ec
|
||||
#define DQVISACONTROLCRTOP 0x00f0
|
||||
#define DQVISALANECR0BL 0x00f4
|
||||
#define DQVISALANECR1BL 0x00f8
|
||||
#define DQVISACONTROLCRBL 0x00fc
|
||||
#define DQTIMINGCTRL 0x010c
|
||||
|
||||
/* CH0-ECC */
|
||||
#define ECCDLLTXCTL 0x2004
|
||||
#define ECCDLLRXCTL 0x2008
|
||||
#define ECCMDLLCTL 0x200c
|
||||
#define ECCB1DLLPICODER0 0x2038
|
||||
#define ECCB1DLLPICODER1 0x2040
|
||||
#define ECCB1DLLPICODER2 0x2048
|
||||
#define ECCB1DLLPICODER3 0x2050
|
||||
#define ECCB01DBCTL0 0x2078
|
||||
#define ECCB01DBCTL1 0x207c
|
||||
#define ECCCLKALIGNREG0 0x20b8
|
||||
#define ECCCLKALIGNREG1 0x20bc
|
||||
#define ECCCLKALIGNREG2 0x20c0
|
||||
|
||||
/* CH0-CMD */
|
||||
#define CMDOBSCKEBBCTL 0x4800
|
||||
#define CMDDLLTXCTL 0x4808
|
||||
#define CMDDLLRXCTL 0x480c
|
||||
#define CMDMDLLCTL 0x4810
|
||||
#define CMDRCOMPODT 0x4814
|
||||
#define CMDDLLPICODER0 0x4820
|
||||
#define CMDDLLPICODER1 0x4824
|
||||
#define CMDCFGREG0 0x4840
|
||||
#define CMDPTRREG 0x4844
|
||||
#define CMDCLKALIGNREG0 0x4850
|
||||
#define CMDCLKALIGNREG1 0x4854
|
||||
#define CMDCLKALIGNREG2 0x4858
|
||||
#define CMDPMCONFIG0 0x485c
|
||||
#define CMDPMDLYREG0 0x4860
|
||||
#define CMDPMDLYREG1 0x4864
|
||||
#define CMDPMDLYREG2 0x4868
|
||||
#define CMDPMDLYREG3 0x486c
|
||||
#define CMDPMDLYREG4 0x4870
|
||||
#define CMDCLKALIGNSTS0 0x4874
|
||||
#define CMDCLKALIGNSTS1 0x4878
|
||||
#define CMDPMSTS0 0x487c
|
||||
#define CMDPMSTS1 0x4880
|
||||
#define CMDCOMPSLV 0x4884
|
||||
#define CMDBONUS0 0x488c
|
||||
#define CMDBONUS1 0x4890
|
||||
#define CMDVISALANECR0 0x4894
|
||||
#define CMDVISALANECR1 0x4898
|
||||
#define CMDVISACONTROLCR 0x489c
|
||||
#define CMDCLKGATE 0x48a0
|
||||
#define CMDTIMINGCTRL 0x48a4
|
||||
|
||||
/* CH0-CLK-CTL */
|
||||
#define CCOBSCKEBBCTL 0x5800
|
||||
#define CCRCOMPIO 0x5804
|
||||
#define CCDLLTXCTL 0x5808
|
||||
#define CCDLLRXCTL 0x580c
|
||||
#define CCMDLLCTL 0x5810
|
||||
#define CCRCOMPODT 0x5814
|
||||
#define CCDLLPICODER0 0x5820
|
||||
#define CCDLLPICODER1 0x5824
|
||||
#define CCDDR3RESETCTL 0x5830
|
||||
#define CCCFGREG0 0x5838
|
||||
#define CCCFGREG1 0x5840
|
||||
#define CCPTRREG 0x5844
|
||||
#define CCCLKALIGNREG0 0x5850
|
||||
#define CCCLKALIGNREG1 0x5854
|
||||
#define CCCLKALIGNREG2 0x5858
|
||||
#define CCPMCONFIG0 0x585c
|
||||
#define CCPMDLYREG0 0x5860
|
||||
#define CCPMDLYREG1 0x5864
|
||||
#define CCPMDLYREG2 0x5868
|
||||
#define CCPMDLYREG3 0x586c
|
||||
#define CCPMDLYREG4 0x5870
|
||||
#define CCCLKALIGNSTS0 0x5874
|
||||
#define CCCLKALIGNSTS1 0x5878
|
||||
#define CCPMSTS0 0x587c
|
||||
#define CCPMSTS1 0x5880
|
||||
#define CCCOMPSLV1 0x5884
|
||||
#define CCCOMPSLV2 0x5888
|
||||
#define CCCOMPSLV3 0x588c
|
||||
#define CCBONUS0 0x5894
|
||||
#define CCBONUS1 0x5898
|
||||
#define CCVISALANECR0 0x589c
|
||||
#define CCVISALANECR1 0x58a0
|
||||
#define CCVISACONTROLCR 0x58a4
|
||||
#define CCCLKGATE 0x58a8
|
||||
#define CCTIMINGCTL 0x58ac
|
||||
|
||||
/* COMP */
|
||||
#define CMPCTRL 0x6800
|
||||
#define SOFTRSTCNTL 0x6804
|
||||
#define MSCNTR 0x6808
|
||||
#define NMSCNTRL 0x680c
|
||||
#define LATCH1CTL 0x6814
|
||||
#define COMPVISALANECR0 0x681c
|
||||
#define COMPVISALANECR1 0x6820
|
||||
#define COMPVISACONTROLCR 0x6824
|
||||
#define COMPBONUS0 0x6830
|
||||
#define TCOCNTCTRL 0x683c
|
||||
#define DQANAODTPUCTL 0x6840
|
||||
#define DQANAODTPDCTL 0x6844
|
||||
#define DQANADRVPUCTL 0x6848
|
||||
#define DQANADRVPDCTL 0x684c
|
||||
#define DQANADLYPUCTL 0x6850
|
||||
#define DQANADLYPDCTL 0x6854
|
||||
#define DQANATCOPUCTL 0x6858
|
||||
#define DQANATCOPDCTL 0x685c
|
||||
#define CMDANADRVPUCTL 0x6868
|
||||
#define CMDANADRVPDCTL 0x686c
|
||||
#define CMDANADLYPUCTL 0x6870
|
||||
#define CMDANADLYPDCTL 0x6874
|
||||
#define CLKANAODTPUCTL 0x6880
|
||||
#define CLKANAODTPDCTL 0x6884
|
||||
#define CLKANADRVPUCTL 0x6888
|
||||
#define CLKANADRVPDCTL 0x688c
|
||||
#define CLKANADLYPUCTL 0x6890
|
||||
#define CLKANADLYPDCTL 0x6894
|
||||
#define CLKANATCOPUCTL 0x6898
|
||||
#define CLKANATCOPDCTL 0x689c
|
||||
#define DQSANAODTPUCTL 0x68a0
|
||||
#define DQSANAODTPDCTL 0x68a4
|
||||
#define DQSANADRVPUCTL 0x68a8
|
||||
#define DQSANADRVPDCTL 0x68ac
|
||||
#define DQSANADLYPUCTL 0x68b0
|
||||
#define DQSANADLYPDCTL 0x68b4
|
||||
#define DQSANATCOPUCTL 0x68b8
|
||||
#define DQSANATCOPDCTL 0x68bc
|
||||
#define CTLANADRVPUCTL 0x68c8
|
||||
#define CTLANADRVPDCTL 0x68cc
|
||||
#define CTLANADLYPUCTL 0x68d0
|
||||
#define CTLANADLYPDCTL 0x68d4
|
||||
#define CHNLBUFSTATIC 0x68f0
|
||||
#define COMPOBSCNTRL 0x68f4
|
||||
#define COMPBUFFDBG0 0x68f8
|
||||
#define COMPBUFFDBG1 0x68fc
|
||||
#define CFGMISCCH0 0x6900
|
||||
#define COMPEN0CH0 0x6904
|
||||
#define COMPEN1CH0 0x6908
|
||||
#define COMPEN2CH0 0x690c
|
||||
#define STATLEGEN0CH0 0x6910
|
||||
#define STATLEGEN1CH0 0x6914
|
||||
#define DQVREFCH0 0x6918
|
||||
#define CMDVREFCH0 0x691c
|
||||
#define CLKVREFCH0 0x6920
|
||||
#define DQSVREFCH0 0x6924
|
||||
#define CTLVREFCH0 0x6928
|
||||
#define TCOVREFCH0 0x692c
|
||||
#define DLYSELCH0 0x6930
|
||||
#define TCODRAMBUFODTCH0 0x6934
|
||||
#define CCBUFODTCH0 0x6938
|
||||
#define RXOFFSETCH0 0x693c
|
||||
#define DQODTPUCTLCH0 0x6940
|
||||
#define DQODTPDCTLCH0 0x6944
|
||||
#define DQDRVPUCTLCH0 0x6948
|
||||
#define DQDRVPDCTLCH0 0x694c
|
||||
#define DQDLYPUCTLCH0 0x6950
|
||||
#define DQDLYPDCTLCH0 0x6954
|
||||
#define DQTCOPUCTLCH0 0x6958
|
||||
#define DQTCOPDCTLCH0 0x695c
|
||||
#define CMDDRVPUCTLCH0 0x6968
|
||||
#define CMDDRVPDCTLCH0 0x696c
|
||||
#define CMDDLYPUCTLCH0 0x6970
|
||||
#define CMDDLYPDCTLCH0 0x6974
|
||||
#define CLKODTPUCTLCH0 0x6980
|
||||
#define CLKODTPDCTLCH0 0x6984
|
||||
#define CLKDRVPUCTLCH0 0x6988
|
||||
#define CLKDRVPDCTLCH0 0x698c
|
||||
#define CLKDLYPUCTLCH0 0x6990
|
||||
#define CLKDLYPDCTLCH0 0x6994
|
||||
#define CLKTCOPUCTLCH0 0x6998
|
||||
#define CLKTCOPDCTLCH0 0x699c
|
||||
#define DQSODTPUCTLCH0 0x69a0
|
||||
#define DQSODTPDCTLCH0 0x69a4
|
||||
#define DQSDRVPUCTLCH0 0x69a8
|
||||
#define DQSDRVPDCTLCH0 0x69ac
|
||||
#define DQSDLYPUCTLCH0 0x69b0
|
||||
#define DQSDLYPDCTLCH0 0x69b4
|
||||
#define DQSTCOPUCTLCH0 0x69b8
|
||||
#define DQSTCOPDCTLCH0 0x69bc
|
||||
#define CTLDRVPUCTLCH0 0x69c8
|
||||
#define CTLDRVPDCTLCH0 0x69cc
|
||||
#define CTLDLYPUCTLCH0 0x69d0
|
||||
#define CTLDLYPDCTLCH0 0x69d4
|
||||
#define FNLUPDTCTLCH0 0x69f0
|
||||
|
||||
/* PLL */
|
||||
#define MPLLCTRL0 0x7800
|
||||
#define MPLLCTRL1 0x7808
|
||||
#define MPLLCSR0 0x7810
|
||||
#define MPLLCSR1 0x7814
|
||||
#define MPLLCSR2 0x7820
|
||||
#define MPLLDFT 0x7828
|
||||
#define MPLLMON0CTL 0x7830
|
||||
#define MPLLMON1CTL 0x7838
|
||||
#define MPLLMON2CTL 0x783c
|
||||
#define SFRTRIM 0x7850
|
||||
#define MPLLDFTOUT0 0x7858
|
||||
#define MPLLDFTOUT1 0x785c
|
||||
#define MASTERRSTN 0x7880
|
||||
#define PLLLOCKDEL 0x7884
|
||||
#define SFRDEL 0x7888
|
||||
#define CRUVISALANECR0 0x78f0
|
||||
#define CRUVISALANECR1 0x78f4
|
||||
#define CRUVISACONTROLCR 0x78f8
|
||||
#define IOSFVISALANECR0 0x78fc
|
||||
#define IOSFVISALANECR1 0x7900
|
||||
#define IOSFVISACONTROLCR 0x7904
|
||||
|
||||
/* END DDRIO Registers */
|
||||
|
||||
/* DRAM Specific Message Bus OpCodes */
|
||||
#define MSG_OP_DRAM_INIT 0x68
|
||||
#define MSG_OP_DRAM_WAKE 0xca
|
||||
|
||||
#define SAMPLE_SIZE 6
|
||||
|
||||
/* must be less than this number to enable early deadband */
|
||||
#define EARLY_DB 0x12
|
||||
/* must be greater than this number to enable late deadband */
|
||||
#define LATE_DB 0x34
|
||||
|
||||
#define CHX_REGS (11 * 4)
|
||||
#define FULL_CLK 128
|
||||
#define HALF_CLK 64
|
||||
#define QRTR_CLK 32
|
||||
|
||||
#define MCEIL(num, den) ((uint8_t)((num + den - 1) / den))
|
||||
#define MMAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define DEAD_LOOP() for (;;);
|
||||
|
||||
#define MIN_RDQS_EYE 10 /* in PI Codes */
|
||||
#define MIN_VREF_EYE 10 /* in VREF Codes */
|
||||
/* how many RDQS codes to jump while margining */
|
||||
#define RDQS_STEP 1
|
||||
/* how many VREF codes to jump while margining */
|
||||
#define VREF_STEP 1
|
||||
/* offset into "vref_codes[]" for minimum allowed VREF setting */
|
||||
#define VREF_MIN 0x00
|
||||
/* offset into "vref_codes[]" for maximum allowed VREF setting */
|
||||
#define VREF_MAX 0x3f
|
||||
#define RDQS_MIN 0x00 /* minimum RDQS delay value */
|
||||
#define RDQS_MAX 0x3f /* maximum RDQS delay value */
|
||||
|
||||
/* how many WDQ codes to jump while margining */
|
||||
#define WDQ_STEP 1
|
||||
|
||||
enum {
|
||||
B, /* BOTTOM VREF */
|
||||
T /* TOP VREF */
|
||||
};
|
||||
|
||||
enum {
|
||||
L, /* LEFT RDQS */
|
||||
R /* RIGHT RDQS */
|
||||
};
|
||||
|
||||
/* Memory Options */
|
||||
|
||||
/* enable STATIC timing settings for RCVN (BACKUP_MODE) */
|
||||
#undef BACKUP_RCVN
|
||||
/* enable STATIC timing settings for WDQS (BACKUP_MODE) */
|
||||
#undef BACKUP_WDQS
|
||||
/* enable STATIC timing settings for RDQS (BACKUP_MODE) */
|
||||
#undef BACKUP_RDQS
|
||||
/* enable STATIC timing settings for WDQ (BACKUP_MODE) */
|
||||
#undef BACKUP_WDQ
|
||||
/* enable *COMP overrides (BACKUP_MODE) */
|
||||
#undef BACKUP_COMPS
|
||||
/* enable the RD_TRAIN eye check */
|
||||
#undef RX_EYE_CHECK
|
||||
|
||||
/* enable Host to Memory Clock Alignment */
|
||||
#define HMC_TEST
|
||||
/* enable multi-rank support via rank2rank sharing */
|
||||
#define R2R_SHARING
|
||||
/* disable signals not used in 16bit mode of DDRIO */
|
||||
#define FORCE_16BIT_DDRIO
|
||||
|
||||
#define PLATFORM_ID 1
|
||||
|
||||
void clear_self_refresh(struct mrc_params *mrc_params);
|
||||
void prog_ddr_timing_control(struct mrc_params *mrc_params);
|
||||
void prog_decode_before_jedec(struct mrc_params *mrc_params);
|
||||
void perform_ddr_reset(struct mrc_params *mrc_params);
|
||||
void ddrphy_init(struct mrc_params *mrc_params);
|
||||
void perform_jedec_init(struct mrc_params *mrc_params);
|
||||
void set_ddr_init_complete(struct mrc_params *mrc_params);
|
||||
void restore_timings(struct mrc_params *mrc_params);
|
||||
void default_timings(struct mrc_params *mrc_params);
|
||||
void rcvn_cal(struct mrc_params *mrc_params);
|
||||
void wr_level(struct mrc_params *mrc_params);
|
||||
void prog_page_ctrl(struct mrc_params *mrc_params);
|
||||
void rd_train(struct mrc_params *mrc_params);
|
||||
void wr_train(struct mrc_params *mrc_params);
|
||||
void store_timings(struct mrc_params *mrc_params);
|
||||
void enable_scrambling(struct mrc_params *mrc_params);
|
||||
void prog_ddr_control(struct mrc_params *mrc_params);
|
||||
void prog_dra_drb(struct mrc_params *mrc_params);
|
||||
void perform_wake(struct mrc_params *mrc_params);
|
||||
void change_refresh_period(struct mrc_params *mrc_params);
|
||||
void set_auto_refresh(struct mrc_params *mrc_params);
|
||||
void ecc_enable(struct mrc_params *mrc_params);
|
||||
void memory_test(struct mrc_params *mrc_params);
|
||||
void lock_registers(struct mrc_params *mrc_params);
|
||||
|
||||
#endif /* _SMC_H_ */
|
||||
53
u-boot/arch/x86/cpu/queensbay/Kconfig
Normal file
53
u-boot/arch/x86/cpu/queensbay/Kconfig
Normal file
@@ -0,0 +1,53 @@
|
||||
#
|
||||
# Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
config INTEL_QUEENSBAY
|
||||
bool
|
||||
select HAVE_FSP
|
||||
select HAVE_CMC
|
||||
|
||||
if INTEL_QUEENSBAY
|
||||
|
||||
config HAVE_CMC
|
||||
bool "Add a Chipset Micro Code state machine binary"
|
||||
help
|
||||
Select this option to add a Chipset Micro Code state machine binary
|
||||
to the resulting U-Boot image. It is a 64K data block of machine
|
||||
specific code which must be put in the flash for the processor to
|
||||
access when powered up before system BIOS is executed.
|
||||
|
||||
config CMC_FILE
|
||||
string "Chipset Micro Code state machine filename"
|
||||
depends on HAVE_CMC
|
||||
default "cmc.bin"
|
||||
help
|
||||
The filename of the file to use as Chipset Micro Code state machine
|
||||
binary in the board directory.
|
||||
|
||||
config CMC_ADDR
|
||||
hex "Chipset Micro Code state machine binary location"
|
||||
depends on HAVE_CMC
|
||||
default 0xfffb0000
|
||||
help
|
||||
The location of the CMC binary is determined by a strap. It must be
|
||||
put in flash at a location matching the strap-determined base address.
|
||||
|
||||
The default base address of 0xfffb0000 indicates that the binary must
|
||||
be located at offset 0xb0000 from the beginning of a 1MB flash device.
|
||||
|
||||
config CPU_ADDR_BITS
|
||||
int
|
||||
default 32
|
||||
|
||||
config DISABLE_IGD
|
||||
bool "Disable Integrated Graphics Device (IGD)"
|
||||
help
|
||||
Disable the Integrated Graphics Device (IGD) so that it does not
|
||||
show in the PCI configuration space as a VGA disaplay controller.
|
||||
This gives a chance for U-Boot to run PCI/PCIe based graphics
|
||||
card's VGA BIOS and use that card for the graphics console.
|
||||
|
||||
endif
|
||||
8
u-boot/arch/x86/cpu/queensbay/Makefile
Normal file
8
u-boot/arch/x86/cpu/queensbay/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += fsp_configs.o irq.o
|
||||
obj-y += tnc.o topcliff.o
|
||||
20
u-boot/arch/x86/cpu/queensbay/fsp_configs.c
Normal file
20
u-boot/arch/x86/cpu/queensbay/fsp_configs.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Intel
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/fsp/fsp_support.h>
|
||||
|
||||
void update_fsp_configs(struct fsp_config_data *config,
|
||||
struct fspinit_rtbuf *rt_buf)
|
||||
{
|
||||
/* Initialize runtime buffer for fsp_init() */
|
||||
rt_buf->common.stack_top = config->common.stack_top - 32;
|
||||
rt_buf->common.boot_mode = config->common.boot_mode;
|
||||
rt_buf->common.upd_data = &config->fsp_upd;
|
||||
|
||||
/* Override any UPD setting if required */
|
||||
}
|
||||
65
u-boot/arch/x86/cpu/queensbay/irq.c
Normal file
65
u-boot/arch/x86/cpu/queensbay/irq.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
* Copyright (C) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/arch/device.h>
|
||||
#include <asm/arch/tnc.h>
|
||||
|
||||
int queensbay_irq_router_probe(struct udevice *dev)
|
||||
{
|
||||
struct tnc_rcba *rcba;
|
||||
u32 base;
|
||||
|
||||
dm_pci_read_config32(dev->parent, LPC_RCBA, &base);
|
||||
base &= ~MEM_BAR_EN;
|
||||
rcba = (struct tnc_rcba *)base;
|
||||
|
||||
/* Make sure all internal PCI devices are using INTA */
|
||||
writel(INTA, &rcba->d02ip);
|
||||
writel(INTA, &rcba->d03ip);
|
||||
writel(INTA, &rcba->d27ip);
|
||||
writel(INTA, &rcba->d31ip);
|
||||
writel(INTA, &rcba->d23ip);
|
||||
writel(INTA, &rcba->d24ip);
|
||||
writel(INTA, &rcba->d25ip);
|
||||
writel(INTA, &rcba->d26ip);
|
||||
|
||||
/*
|
||||
* Route TunnelCreek PCI device interrupt pin to PIRQ
|
||||
*
|
||||
* Since PCIe downstream ports received INTx are routed to PIRQ
|
||||
* A/B/C/D directly and not configurable, we have to route PCIe
|
||||
* root ports' INTx to PIRQ A/B/C/D as well. For other devices
|
||||
* on TunneCreek, route them to PIRQ E/F/G/H.
|
||||
*/
|
||||
writew(PIRQE, &rcba->d02ir);
|
||||
writew(PIRQF, &rcba->d03ir);
|
||||
writew(PIRQG, &rcba->d27ir);
|
||||
writew(PIRQH, &rcba->d31ir);
|
||||
writew(PIRQA, &rcba->d23ir);
|
||||
writew(PIRQB, &rcba->d24ir);
|
||||
writew(PIRQC, &rcba->d25ir);
|
||||
writew(PIRQD, &rcba->d26ir);
|
||||
|
||||
return irq_router_common_init(dev);
|
||||
}
|
||||
|
||||
static const struct udevice_id queensbay_irq_router_ids[] = {
|
||||
{ .compatible = "intel,queensbay-irq-router" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(queensbay_irq_router_drv) = {
|
||||
.name = "queensbay_intel_irq",
|
||||
.id = UCLASS_IRQ,
|
||||
.of_match = queensbay_irq_router_ids,
|
||||
.probe = queensbay_irq_router_probe,
|
||||
};
|
||||
117
u-boot/arch/x86/cpu/queensbay/tnc.c
Normal file
117
u-boot/arch/x86/cpu/queensbay/tnc.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <pci.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/arch/device.h>
|
||||
#include <asm/arch/tnc.h>
|
||||
#include <asm/fsp/fsp_support.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
static int __maybe_unused disable_igd(void)
|
||||
{
|
||||
struct udevice *igd, *sdvo;
|
||||
int ret;
|
||||
|
||||
ret = dm_pci_bus_find_bdf(TNC_IGD, &igd);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!igd)
|
||||
return 0;
|
||||
|
||||
ret = dm_pci_bus_find_bdf(TNC_SDVO, &sdvo);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!sdvo)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* According to Atom E6xx datasheet, setting VGA Disable (bit17)
|
||||
* of Graphics Controller register (offset 0x50) prevents IGD
|
||||
* (D2:F0) from reporting itself as a VGA display controller
|
||||
* class in the PCI configuration space, and should also prevent
|
||||
* it from responding to VGA legacy memory range and I/O addresses.
|
||||
*
|
||||
* However test result shows that with just VGA Disable bit set and
|
||||
* a PCIe graphics card connected to one of the PCIe controllers on
|
||||
* the E6xx, accessing the VGA legacy space still causes system hang.
|
||||
* After a number of attempts, it turns out besides VGA Disable bit,
|
||||
* the SDVO (D3:F0) device should be disabled to make it work.
|
||||
*
|
||||
* To simplify, use the Function Disable register (offset 0xc4)
|
||||
* to disable both IGD (D2:F0) and SDVO (D3:F0) devices. Now these
|
||||
* two devices will be completely disabled (invisible in the PCI
|
||||
* configuration space) unless a system reset is performed.
|
||||
*/
|
||||
dm_pci_write_config32(igd, IGD_FD, FUNC_DISABLE);
|
||||
dm_pci_write_config32(sdvo, IGD_FD, FUNC_DISABLE);
|
||||
|
||||
/*
|
||||
* After setting the function disable bit, IGD and SDVO devices will
|
||||
* disappear in the PCI configuration space. This however creates an
|
||||
* inconsistent state from a driver model PCI controller point of view,
|
||||
* as these two PCI devices are still attached to its parent's child
|
||||
* device list as maintained by the driver model. Some driver model PCI
|
||||
* APIs like dm_pci_find_class(), are referring to the list to speed up
|
||||
* the finding process instead of re-enumerating the whole PCI bus, so
|
||||
* it gets the stale cached data which is wrong.
|
||||
*
|
||||
* Note x86 PCI enueration normally happens twice, in pre-relocation
|
||||
* phase and post-relocation. One option might be to call disable_igd()
|
||||
* in one of the pre-relocation initialization hooks so that it gets
|
||||
* disabled in the first round, and when it comes to the second round
|
||||
* driver model PCI will construct a correct list. Unfortunately this
|
||||
* does not work as Intel FSP is used on this platform to perform low
|
||||
* level initialization, and fsp_init_phase_pci() is called only once
|
||||
* in the post-relocation phase. If we disable IGD and SDVO devices,
|
||||
* fsp_init_phase_pci() simply hangs and never returns.
|
||||
*
|
||||
* So the only option we have is to manually remove these two devices.
|
||||
*/
|
||||
ret = device_remove(igd);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = device_unbind(igd);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = device_remove(sdvo);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = device_unbind(sdvo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
post_code(POST_CPU_INIT);
|
||||
|
||||
ret = x86_cpu_init_f();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_early_init_r(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_DISABLE_IGD
|
||||
ret = disable_igd();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
20
u-boot/arch/x86/cpu/queensbay/topcliff.c
Normal file
20
u-boot/arch/x86/cpu/queensbay/topcliff.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mmc.h>
|
||||
#include <pci_ids.h>
|
||||
|
||||
static struct pci_device_id mmc_supported[] = {
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_0 },
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_1 },
|
||||
{},
|
||||
};
|
||||
|
||||
int cpu_mmc_init(bd_t *bis)
|
||||
{
|
||||
return pci_mmc_init("Topcliff SDHCI", mmc_supported);
|
||||
}
|
||||
22
u-boot/arch/x86/cpu/resetvec.S
Normal file
22
u-boot/arch/x86/cpu/resetvec.S
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* U-Boot - x86 Startup Code
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/* Reset vector, jumps to start16.S */
|
||||
|
||||
.extern start16
|
||||
|
||||
.section .resetvec, "ax"
|
||||
.code16
|
||||
reset_vector:
|
||||
cli
|
||||
cld
|
||||
jmp start16
|
||||
|
||||
.org 0xf
|
||||
nop
|
||||
217
u-boot/arch/x86/cpu/sipi_vector.S
Normal file
217
u-boot/arch/x86/cpu/sipi_vector.S
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Taken from coreboot file of the same name
|
||||
*/
|
||||
|
||||
/*
|
||||
* The SIPI vector is responsible for initializing the APs in the sytem. It
|
||||
* loads microcode, sets up MSRs, and enables caching before calling into
|
||||
* C code
|
||||
*/
|
||||
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/msr-index.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/sipi.h>
|
||||
|
||||
#define CODE_SEG (X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE)
|
||||
#define DATA_SEG (X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE)
|
||||
|
||||
/*
|
||||
* First we have the 16-bit section. Every AP process starts here.
|
||||
* The simple task is to load U-Boot's Global Descriptor Table (GDT) to allow
|
||||
* U-Boot's 32-bit code to become visible, then jump to ap_start.
|
||||
*
|
||||
* Note that this code is copied to RAM below 1MB in mp_init.c, and runs from
|
||||
* there, but the 32-bit code (ap_start and onwards) is part of U-Boot and
|
||||
* is therefore relocated to the top of RAM with other U-Boot code. This
|
||||
* means that for the 16-bit code we must write relocatable code, but for the
|
||||
* rest, we can do what we like.
|
||||
*/
|
||||
.text
|
||||
.code16
|
||||
.globl ap_start16
|
||||
ap_start16:
|
||||
cli
|
||||
xorl %eax, %eax
|
||||
movl %eax, %cr3 /* Invalidate TLB */
|
||||
|
||||
/* setup the data segment */
|
||||
movw %cs, %ax
|
||||
movw %ax, %ds
|
||||
|
||||
/* Use an address relative to the data segment for the GDT */
|
||||
movl $gdtaddr, %ebx
|
||||
subl $ap_start16, %ebx
|
||||
|
||||
data32 lgdt (%ebx)
|
||||
|
||||
movl %cr0, %eax
|
||||
andl $(~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE | \
|
||||
X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)), %eax
|
||||
orl $(X86_CR0_NW | X86_CR0_CD | X86_CR0_PE), %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
movl $ap_start_jmp, %eax
|
||||
subl $ap_start16, %eax
|
||||
movw %ax, %bp
|
||||
|
||||
/* Jump to ap_start within U-Boot */
|
||||
data32 cs ljmp *(%bp)
|
||||
|
||||
.align 4
|
||||
.globl sipi_params_16bit
|
||||
sipi_params_16bit:
|
||||
/* 48-bit far pointer */
|
||||
ap_start_jmp:
|
||||
.long 0 /* offset set to ap_start by U-Boot */
|
||||
.word CODE_SEG /* segment */
|
||||
|
||||
.word 0 /* padding */
|
||||
gdtaddr:
|
||||
.word 0 /* limit */
|
||||
.long 0 /* table */
|
||||
.word 0 /* unused */
|
||||
|
||||
.globl ap_start16_code_end
|
||||
ap_start16_code_end:
|
||||
|
||||
/*
|
||||
* Set up the special 'fs' segment for global_data. Then jump to ap_continue
|
||||
* to set up the AP.
|
||||
*/
|
||||
.globl ap_start
|
||||
ap_start:
|
||||
.code32
|
||||
movw $DATA_SEG, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %ss
|
||||
movw %ax, %gs
|
||||
|
||||
movw $(X86_GDT_ENTRY_32BIT_FS * X86_GDT_ENTRY_SIZE), %ax
|
||||
movw %ax, %fs
|
||||
|
||||
/* Load the Interrupt descriptor table */
|
||||
mov idt_ptr, %ebx
|
||||
lidt (%ebx)
|
||||
|
||||
/* Obtain cpu number */
|
||||
movl ap_count, %eax
|
||||
1:
|
||||
movl %eax, %ecx
|
||||
inc %ecx
|
||||
lock cmpxchg %ecx, ap_count
|
||||
jnz 1b
|
||||
|
||||
/* Setup stacks for each CPU */
|
||||
movl stack_size, %eax
|
||||
mul %ecx
|
||||
movl stack_top, %edx
|
||||
subl %eax, %edx
|
||||
mov %edx, %esp
|
||||
/* Save cpu number */
|
||||
mov %ecx, %esi
|
||||
|
||||
/* Determine if one should check microcode versions */
|
||||
mov microcode_ptr, %edi
|
||||
test %edi, %edi
|
||||
jz microcode_done /* Bypass if no microde exists */
|
||||
|
||||
/* Get the Microcode version */
|
||||
mov $1, %eax
|
||||
cpuid
|
||||
mov $MSR_IA32_UCODE_REV, %ecx
|
||||
rdmsr
|
||||
/* If something already loaded skip loading again */
|
||||
test %edx, %edx
|
||||
jnz microcode_done
|
||||
|
||||
/* Determine if parallel microcode loading is allowed */
|
||||
cmp $0xffffffff, microcode_lock
|
||||
je load_microcode
|
||||
|
||||
/* Protect microcode loading */
|
||||
lock_microcode:
|
||||
lock bts $0, microcode_lock
|
||||
jc lock_microcode
|
||||
|
||||
load_microcode:
|
||||
/* Load new microcode */
|
||||
mov $MSR_IA32_UCODE_WRITE, %ecx
|
||||
xor %edx, %edx
|
||||
mov %edi, %eax
|
||||
/*
|
||||
* The microcode pointer is passed in pointing to the header. Adjust
|
||||
* pointer to reflect the payload (header size is 48 bytes)
|
||||
*/
|
||||
add $UCODE_HEADER_LEN, %eax
|
||||
pusha
|
||||
wrmsr
|
||||
popa
|
||||
|
||||
/* Unconditionally unlock microcode loading */
|
||||
cmp $0xffffffff, microcode_lock
|
||||
je microcode_done
|
||||
|
||||
xor %eax, %eax
|
||||
mov %eax, microcode_lock
|
||||
|
||||
microcode_done:
|
||||
/*
|
||||
* Load MSRs. Each entry in the table consists of:
|
||||
* 0: index,
|
||||
* 4: value[31:0]
|
||||
* 8: value[63:32]
|
||||
* See struct saved_msr in mp_init.c.
|
||||
*/
|
||||
mov msr_table_ptr, %edi
|
||||
mov msr_count, %ebx
|
||||
test %ebx, %ebx
|
||||
jz 1f
|
||||
load_msr:
|
||||
mov (%edi), %ecx
|
||||
mov 4(%edi), %eax
|
||||
mov 8(%edi), %edx
|
||||
wrmsr
|
||||
add $12, %edi
|
||||
dec %ebx
|
||||
jnz load_msr
|
||||
|
||||
1:
|
||||
/* Enable caching */
|
||||
mov %cr0, %eax
|
||||
andl $(~(X86_CR0_CD | X86_CR0_NW)), %eax
|
||||
mov %eax, %cr0
|
||||
|
||||
/* c_handler(cpu_num) */
|
||||
movl %esi, %eax /* cpu_num */
|
||||
mov c_handler, %esi
|
||||
call *%esi
|
||||
|
||||
/* This matches struct sipi_param */
|
||||
.align 4
|
||||
.globl sipi_params
|
||||
sipi_params:
|
||||
idt_ptr:
|
||||
.long 0
|
||||
stack_top:
|
||||
.long 0
|
||||
stack_size:
|
||||
.long 0
|
||||
microcode_lock:
|
||||
.long 0
|
||||
microcode_ptr:
|
||||
.long 0
|
||||
msr_table_ptr:
|
||||
.long 0
|
||||
msr_count:
|
||||
.long 0
|
||||
c_handler:
|
||||
.long 0
|
||||
ap_count:
|
||||
.long 0
|
||||
302
u-boot/arch/x86/cpu/start.S
Normal file
302
u-boot/arch/x86/cpu/start.S
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* U-Boot - x86 Startup Code
|
||||
*
|
||||
* (C) Copyright 2008-2011
|
||||
* Graeme Russ, <graeme.russ@gmail.com>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <generated/generic-asm-offsets.h>
|
||||
#include <generated/asm-offsets.h>
|
||||
|
||||
/*
|
||||
* Define this to boot U-Boot from a 32-bit program which sets the GDT
|
||||
* differently. This can be used to boot directly from any stage of coreboot,
|
||||
* for example, bypassing the normal payload-loading feature.
|
||||
* This is only useful for development.
|
||||
*/
|
||||
#undef LOAD_FROM_32_BIT
|
||||
|
||||
.section .text
|
||||
.code32
|
||||
.globl _start
|
||||
.type _start, @function
|
||||
.globl _x86boot_start
|
||||
_x86boot_start:
|
||||
/*
|
||||
* This is the fail-safe 32-bit bootstrap entry point.
|
||||
*
|
||||
* This code is used when booting from another boot loader like
|
||||
* coreboot or EFI. So we repeat some of the same init found in
|
||||
* start16.
|
||||
*/
|
||||
cli
|
||||
cld
|
||||
|
||||
/* Turn off cache (this might require a 486-class CPU) */
|
||||
movl %cr0, %eax
|
||||
orl $(X86_CR0_NW | X86_CR0_CD), %eax
|
||||
movl %eax, %cr0
|
||||
wbinvd
|
||||
|
||||
/* Tell 32-bit code it is being entered from an in-RAM copy */
|
||||
movl $GD_FLG_WARM_BOOT, %ebx
|
||||
|
||||
/*
|
||||
* Zero the BIST (Built-In Self Test) value since we don't have it.
|
||||
* It must be 0 or the previous loader would have reported an error.
|
||||
*/
|
||||
movl $0, %ebp
|
||||
|
||||
jmp 1f
|
||||
|
||||
/* Add a way for tools to discover the _start entry point */
|
||||
.align 4
|
||||
.long 0x12345678
|
||||
_start:
|
||||
/*
|
||||
* This is the 32-bit cold-reset entry point, coming from start16.
|
||||
* Set %ebx to GD_FLG_COLD_BOOT to indicate this.
|
||||
*/
|
||||
movl $GD_FLG_COLD_BOOT, %ebx
|
||||
|
||||
/* Save BIST */
|
||||
movl %eax, %ebp
|
||||
1:
|
||||
|
||||
/* Save table pointer */
|
||||
movl %ecx, %esi
|
||||
|
||||
#ifdef LOAD_FROM_32_BIT
|
||||
lgdt gdt_ptr2
|
||||
#endif
|
||||
|
||||
/* Load the segement registers to match the GDT loaded in start16.S */
|
||||
movl $(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax
|
||||
movw %ax, %fs
|
||||
movw %ax, %ds
|
||||
movw %ax, %gs
|
||||
movw %ax, %es
|
||||
movw %ax, %ss
|
||||
|
||||
/* Clear the interrupt vectors */
|
||||
lidt blank_idt_ptr
|
||||
|
||||
/*
|
||||
* Critical early platform init - generally not used, we prefer init
|
||||
* to happen later when we have a console, in case something goes
|
||||
* wrong.
|
||||
*/
|
||||
jmp early_board_init
|
||||
.globl early_board_init_ret
|
||||
early_board_init_ret:
|
||||
post_code(POST_START)
|
||||
|
||||
/* Initialise Cache-As-RAM */
|
||||
jmp car_init
|
||||
.globl car_init_ret
|
||||
car_init_ret:
|
||||
#ifndef CONFIG_HAVE_FSP
|
||||
/*
|
||||
* We now have CONFIG_SYS_CAR_SIZE bytes of Cache-As-RAM (or SRAM,
|
||||
* or fully initialised SDRAM - we really don't care which)
|
||||
* starting at CONFIG_SYS_CAR_ADDR to be used as a temporary stack
|
||||
* and early malloc() area. The MRC requires some space at the top.
|
||||
*
|
||||
* Stack grows down from top of CAR. We have:
|
||||
*
|
||||
* top-> CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE
|
||||
* MRC area
|
||||
* global_data with x86 global descriptor table
|
||||
* early malloc area
|
||||
* stack
|
||||
* bottom-> CONFIG_SYS_CAR_ADDR
|
||||
*/
|
||||
movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %esp
|
||||
#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE
|
||||
subl $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %esp
|
||||
#endif
|
||||
#else
|
||||
/*
|
||||
* U-Boot enters here twice. For the first time it comes from
|
||||
* car_init_done() with esp points to a temporary stack and esi
|
||||
* set to zero. For the second time it comes from fsp_init_done()
|
||||
* with esi holding the HOB list address returned by the FSP.
|
||||
*/
|
||||
#endif
|
||||
/* Set up global data */
|
||||
mov %esp, %eax
|
||||
call board_init_f_alloc_reserve
|
||||
mov %eax, %esp
|
||||
call board_init_f_init_reserve
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART
|
||||
call debug_uart_init
|
||||
#endif
|
||||
|
||||
/* Get address of global_data */
|
||||
mov %fs:0, %edx
|
||||
#ifdef CONFIG_HAVE_FSP
|
||||
/* Store the HOB list if we have one */
|
||||
test %esi, %esi
|
||||
jz skip_hob
|
||||
movl %esi, GD_HOB_LIST(%edx)
|
||||
|
||||
/*
|
||||
* After fsp_init() returns, the stack has already been switched to a
|
||||
* place within system memory as defined by CONFIG_FSP_TEMP_RAM_ADDR.
|
||||
* Enlarge the size of malloc() pool before relocation since we have
|
||||
* plenty of memory now.
|
||||
*/
|
||||
subl $CONFIG_FSP_SYS_MALLOC_F_LEN, %esp
|
||||
movl %esp, GD_MALLOC_BASE(%edx)
|
||||
skip_hob:
|
||||
#else
|
||||
/* Store table pointer */
|
||||
movl %esi, GD_TABLE(%edx)
|
||||
#endif
|
||||
/* Store BIST */
|
||||
movl %ebp, GD_BIST(%edx)
|
||||
|
||||
/* Set parameter to board_init_f() to boot flags */
|
||||
post_code(POST_START_DONE)
|
||||
xorl %eax, %eax
|
||||
|
||||
/* Enter, U-Boot! */
|
||||
call board_init_f
|
||||
|
||||
/* indicate (lack of) progress */
|
||||
movw $0x85, %ax
|
||||
jmp die
|
||||
|
||||
.globl board_init_f_r_trampoline
|
||||
.type board_init_f_r_trampoline, @function
|
||||
board_init_f_r_trampoline:
|
||||
/*
|
||||
* SDRAM has been initialised, U-Boot code has been copied into
|
||||
* RAM, BSS has been cleared and relocation adjustments have been
|
||||
* made. It is now time to jump into the in-RAM copy of U-Boot
|
||||
*
|
||||
* %eax = Address of top of new stack
|
||||
*/
|
||||
|
||||
/* Stack grows down from top of SDRAM */
|
||||
movl %eax, %esp
|
||||
|
||||
/* See if we need to disable CAR */
|
||||
.weak car_uninit
|
||||
movl $car_uninit, %eax
|
||||
cmpl $0, %eax
|
||||
jz 1f
|
||||
|
||||
call car_uninit
|
||||
1:
|
||||
/* Re-enter U-Boot by calling board_init_f_r() */
|
||||
call board_init_f_r
|
||||
|
||||
die:
|
||||
hlt
|
||||
jmp die
|
||||
hlt
|
||||
|
||||
blank_idt_ptr:
|
||||
.word 0 /* limit */
|
||||
.long 0 /* base */
|
||||
|
||||
.p2align 2 /* force 4-byte alignment */
|
||||
|
||||
/* Add a multiboot header so U-Boot can be loaded by GRUB2 */
|
||||
multiboot_header:
|
||||
/* magic */
|
||||
.long 0x1badb002
|
||||
/* flags */
|
||||
.long (1 << 16)
|
||||
/* checksum */
|
||||
.long -0x1BADB002 - (1 << 16)
|
||||
/* header addr */
|
||||
.long multiboot_header - _x86boot_start + CONFIG_SYS_TEXT_BASE
|
||||
/* load addr */
|
||||
.long CONFIG_SYS_TEXT_BASE
|
||||
/* load end addr */
|
||||
.long 0
|
||||
/* bss end addr */
|
||||
.long 0
|
||||
/* entry addr */
|
||||
.long CONFIG_SYS_TEXT_BASE
|
||||
|
||||
#ifdef LOAD_FROM_32_BIT
|
||||
/*
|
||||
* The following Global Descriptor Table is just enough to get us into
|
||||
* 'Flat Protected Mode' - It will be discarded as soon as the final
|
||||
* GDT is setup in a safe location in RAM
|
||||
*/
|
||||
gdt_ptr2:
|
||||
.word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */
|
||||
.long gdt_rom2 /* base */
|
||||
|
||||
/* Some CPUs are picky about GDT alignment... */
|
||||
.align 16
|
||||
.globl gdt_rom2
|
||||
gdt_rom2:
|
||||
/*
|
||||
* The GDT table ...
|
||||
*
|
||||
* Selector Type
|
||||
* 0x00 NULL
|
||||
* 0x08 Unused
|
||||
* 0x10 32bit code
|
||||
* 0x18 32bit data/stack
|
||||
*/
|
||||
/* The NULL Desciptor - Mandatory */
|
||||
.word 0x0000 /* limit_low */
|
||||
.word 0x0000 /* base_low */
|
||||
.byte 0x00 /* base_middle */
|
||||
.byte 0x00 /* access */
|
||||
.byte 0x00 /* flags + limit_high */
|
||||
.byte 0x00 /* base_high */
|
||||
|
||||
/* Unused Desciptor - (matches Linux) */
|
||||
.word 0x0000 /* limit_low */
|
||||
.word 0x0000 /* base_low */
|
||||
.byte 0x00 /* base_middle */
|
||||
.byte 0x00 /* access */
|
||||
.byte 0x00 /* flags + limit_high */
|
||||
.byte 0x00 /* base_high */
|
||||
|
||||
/*
|
||||
* The Code Segment Descriptor:
|
||||
* - Base = 0x00000000
|
||||
* - Size = 4GB
|
||||
* - Access = Present, Ring 0, Exec (Code), Readable
|
||||
* - Flags = 4kB Granularity, 32-bit
|
||||
*/
|
||||
.word 0xffff /* limit_low */
|
||||
.word 0x0000 /* base_low */
|
||||
.byte 0x00 /* base_middle */
|
||||
.byte 0x9b /* access */
|
||||
.byte 0xcf /* flags + limit_high */
|
||||
.byte 0x00 /* base_high */
|
||||
|
||||
/*
|
||||
* The Data Segment Descriptor:
|
||||
* - Base = 0x00000000
|
||||
* - Size = 4GB
|
||||
* - Access = Present, Ring 0, Non-Exec (Data), Writable
|
||||
* - Flags = 4kB Granularity, 32-bit
|
||||
*/
|
||||
.word 0xffff /* limit_low */
|
||||
.word 0x0000 /* base_low */
|
||||
.byte 0x00 /* base_middle */
|
||||
.byte 0x93 /* access */
|
||||
.byte 0xcf /* flags + limit_high */
|
||||
.byte 0x00 /* base_high */
|
||||
#endif
|
||||
131
u-boot/arch/x86/cpu/start16.S
Normal file
131
u-boot/arch/x86/cpu/start16.S
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* U-Boot - x86 Startup Code
|
||||
*
|
||||
* (C) Copyright 2008-2011
|
||||
* Graeme Russ, <graeme.russ@gmail.com>
|
||||
*
|
||||
* (C) Copyright 2002,2003
|
||||
* Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/processor-flags.h>
|
||||
|
||||
#define BOOT_SEG 0xffff0000 /* linear segment of boot code */
|
||||
#define a32 .byte 0x67;
|
||||
#define o32 .byte 0x66;
|
||||
|
||||
.section .start16, "ax"
|
||||
.code16
|
||||
.globl start16
|
||||
start16:
|
||||
/* Save BIST */
|
||||
movl %eax, %ecx
|
||||
|
||||
/* Set the Cold Boot / Hard Reset flag */
|
||||
movl $GD_FLG_COLD_BOOT, %ebx
|
||||
|
||||
xorl %eax, %eax
|
||||
movl %eax, %cr3 /* Invalidate TLB */
|
||||
|
||||
/* Turn off cache (this might require a 486-class CPU) */
|
||||
movl %cr0, %eax
|
||||
orl $(X86_CR0_NW | X86_CR0_CD), %eax
|
||||
movl %eax, %cr0
|
||||
wbinvd
|
||||
|
||||
/* load the temporary Global Descriptor Table */
|
||||
o32 cs lidt idt_ptr
|
||||
o32 cs lgdt gdt_ptr
|
||||
|
||||
/* Now, we enter protected mode */
|
||||
movl %cr0, %eax
|
||||
orl $X86_CR0_PE, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Flush the prefetch queue */
|
||||
jmp ff
|
||||
ff:
|
||||
|
||||
/* Finally restore BIST and jump to the 32-bit initialization code */
|
||||
movw $code32start, %ax
|
||||
movw %ax, %bp
|
||||
movl %ecx, %eax
|
||||
o32 cs ljmp *(%bp)
|
||||
|
||||
/* 48-bit far pointer */
|
||||
code32start:
|
||||
.long _start /* offset */
|
||||
.word 0x10 /* segment */
|
||||
|
||||
idt_ptr:
|
||||
.word 0 /* limit */
|
||||
.long 0 /* base */
|
||||
|
||||
/*
|
||||
* The following Global Descriptor Table is just enough to get us into
|
||||
* 'Flat Protected Mode' - It will be discarded as soon as the final
|
||||
* GDT is setup in a safe location in RAM
|
||||
*/
|
||||
gdt_ptr:
|
||||
.word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */
|
||||
.long BOOT_SEG + gdt_rom /* base */
|
||||
|
||||
/* Some CPUs are picky about GDT alignment... */
|
||||
.align 16
|
||||
.globl gdt_rom
|
||||
gdt_rom:
|
||||
/*
|
||||
* The GDT table ...
|
||||
*
|
||||
* Selector Type
|
||||
* 0x00 NULL
|
||||
* 0x08 Unused
|
||||
* 0x10 32bit code
|
||||
* 0x18 32bit data/stack
|
||||
*/
|
||||
/* The NULL Desciptor - Mandatory */
|
||||
.word 0x0000 /* limit_low */
|
||||
.word 0x0000 /* base_low */
|
||||
.byte 0x00 /* base_middle */
|
||||
.byte 0x00 /* access */
|
||||
.byte 0x00 /* flags + limit_high */
|
||||
.byte 0x00 /* base_high */
|
||||
|
||||
/* Unused Desciptor - (matches Linux) */
|
||||
.word 0x0000 /* limit_low */
|
||||
.word 0x0000 /* base_low */
|
||||
.byte 0x00 /* base_middle */
|
||||
.byte 0x00 /* access */
|
||||
.byte 0x00 /* flags + limit_high */
|
||||
.byte 0x00 /* base_high */
|
||||
|
||||
/*
|
||||
* The Code Segment Descriptor:
|
||||
* - Base = 0x00000000
|
||||
* - Size = 4GB
|
||||
* - Access = Present, Ring 0, Exec (Code), Readable
|
||||
* - Flags = 4kB Granularity, 32-bit
|
||||
*/
|
||||
.word 0xffff /* limit_low */
|
||||
.word 0x0000 /* base_low */
|
||||
.byte 0x00 /* base_middle */
|
||||
.byte 0x9b /* access */
|
||||
.byte 0xcf /* flags + limit_high */
|
||||
.byte 0x00 /* base_high */
|
||||
|
||||
/*
|
||||
* The Data Segment Descriptor:
|
||||
* - Base = 0x00000000
|
||||
* - Size = 4GB
|
||||
* - Access = Present, Ring 0, Non-Exec (Data), Writable
|
||||
* - Flags = 4kB Granularity, 32-bit
|
||||
*/
|
||||
.word 0xffff /* limit_low */
|
||||
.word 0x0000 /* base_low */
|
||||
.byte 0x00 /* base_middle */
|
||||
.byte 0x93 /* access */
|
||||
.byte 0xcf /* flags + limit_high */
|
||||
.byte 0x00 /* base_high */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user