GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# From Coreboot src/northbridge/intel/sandybridge/Kconfig
|
||||
#
|
||||
# Copyright (C) 2010 Google Inc.
|
||||
#
|
||||
|
||||
config NORTHBRIDGE_INTEL_IVYBRIDGE
|
||||
bool
|
||||
select CACHE_MRC_BIN if HAVE_MRC
|
||||
imply HAVE_INTEL_ME
|
||||
imply ENABLE_MRC_CACHE
|
||||
imply AHCI_PCI
|
||||
imply ICH_SPI
|
||||
imply INTEL_ICH6_GPIO
|
||||
imply PINCTRL_ICH6
|
||||
imply SCSI
|
||||
imply SCSI_AHCI
|
||||
imply SPI_FLASH
|
||||
imply USB
|
||||
imply USB_EHCI_HCD
|
||||
imply USB_XHCI_HCD
|
||||
imply VIDEO_VESA
|
||||
imply SOUND_IVYBRIDGE
|
||||
|
||||
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
|
||||
@@ -0,0 +1,21 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Copyright (c) 2014 Google, Inc
|
||||
|
||||
ifdef CONFIG_HAVE_FSP
|
||||
obj-y += fsp_configs.o ivybridge.o
|
||||
else
|
||||
obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += cpu.o
|
||||
obj-y += early_me.o
|
||||
obj-y += lpc.o
|
||||
obj-y += northbridge.o
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
obj-y += sata.o
|
||||
endif
|
||||
obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += sdram.o
|
||||
ifndef CONFIG_$(SPL_)X86_32BIT_INIT
|
||||
obj-y += sdram_nop.o
|
||||
endif
|
||||
endif
|
||||
obj-y += model_206ax.o
|
||||
obj-y += bd82x6x.o
|
||||
@@ -0,0 +1,272 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2014 Google, Inc
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <pch.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/model_206ax.h>
|
||||
#include <asm/arch/pch.h>
|
||||
#include <asm/arch/sandybridge.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define GPIO_BASE 0x48
|
||||
#define BIOS_CTRL 0xdc
|
||||
|
||||
#define RCBA_AUDIO_CONFIG 0x2030
|
||||
#define RCBA_AUDIO_CONFIG_HDA BIT(31)
|
||||
#define RCBA_AUDIO_CONFIG_MASK 0xfe
|
||||
|
||||
#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)
|
||||
{
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return 0;
|
||||
|
||||
/* Cause the SATA device to do its init */
|
||||
uclass_first_device(UCLASS_AHCI, &dev);
|
||||
|
||||
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 int bd82x6x_ioctl(struct udevice *dev, enum pch_req_t req, void *data,
|
||||
int size)
|
||||
{
|
||||
u32 rcba, val;
|
||||
|
||||
switch (req) {
|
||||
case PCH_REQ_HDA_CONFIG:
|
||||
dm_pci_read_config32(dev, PCH_RCBA, &rcba);
|
||||
val = readl(rcba + RCBA_AUDIO_CONFIG);
|
||||
if (!(val & RCBA_AUDIO_CONFIG_HDA))
|
||||
return -ENOENT;
|
||||
|
||||
return val & RCBA_AUDIO_CONFIG_MASK;
|
||||
case PCH_REQ_PMBASE_INFO: {
|
||||
struct pch_pmbase_info *pm = data;
|
||||
int ret;
|
||||
|
||||
/* Find the base address of the powermanagement registers */
|
||||
ret = dm_pci_read_config16(dev, 0x40, &pm->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
pm->base &= 0xfffe;
|
||||
pm->gpio0_en_ofs = GPE0_EN;
|
||||
pm->pm1_sts_ofs = PM1_STS;
|
||||
pm->pm1_cnt_ofs = PM1_CNT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
.ioctl = bd82x6x_ioctl,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
@@ -0,0 +1,204 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.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 checkcpu() 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 checkcpu(void)
|
||||
{
|
||||
enum pei_boot_mode_t boot_mode = PEI_BOOT_NONE;
|
||||
struct udevice *dev, *lpc;
|
||||
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) {
|
||||
debug("%s: cpu_common_init() failed\n", __func__);
|
||||
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) {
|
||||
debug("%s: Failed to get I2C (ret=%d)\n", __func__, 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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
char processor_name[CPU_MAX_NAME_LEN];
|
||||
const char *name;
|
||||
|
||||
/* 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(PCH_LPC_DEV, LPC_EN, COMA_LPC_EN, PCI_SIZE_16);
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* From Coreboot src/southbridge/intel/bd82x6x/early_me.c
|
||||
*
|
||||
* Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <sysreset.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);
|
||||
sysreset_walk_halt(SYSRESET_COLD);
|
||||
break;
|
||||
case ME_HFS_ACK_PWR_CYCLE:
|
||||
/* Power cycle reset */
|
||||
set_global_reset(dev, 0);
|
||||
sysreset_walk_halt(SYSRESET_COLD);
|
||||
break;
|
||||
case ME_HFS_ACK_GBL_RESET:
|
||||
/* Global reset */
|
||||
set_global_reset(dev, 1);
|
||||
sysreset_walk_halt(SYSRESET_COLD);
|
||||
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 },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(syscon_intel_me) = {
|
||||
.name = "intel_me_syscon",
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = ivybridge_syscon_ids,
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fdtdec.h>
|
||||
#include <asm/fsp1/fsp_support.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void fsp_update_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;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
post_code(POST_CPU_INIT);
|
||||
|
||||
return x86_cpu_init_f();
|
||||
}
|
||||
@@ -0,0 +1,529 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* From coreboot southbridge/intel/bd82x6x/lpc.c
|
||||
*
|
||||
* Copyright (C) 2008-2009 coresystems GmbH
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#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, dev_of_offset(pch),
|
||||
"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, dev_of_offset(pch),
|
||||
"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 = dev_of_offset(pch);
|
||||
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(fdtdec_get_int(blob, node, "intel,gpe0-enable", 0),
|
||||
(ulong)pmbase + GPE0_EN);
|
||||
writew(fdtdec_get_int(blob, node, "intel,alt-gp-smi-enable", 0),
|
||||
(ulong)pmbase + ALT_GP_SMI_EN);
|
||||
|
||||
/* 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, ~0U, 1 << 31);
|
||||
pch_iobp_update(pch, 0xeb004000, ~0U, 1 << 7);
|
||||
pch_iobp_update(pch, 0xec007f07, ~0U, 1 << 31);
|
||||
pch_iobp_update(pch, 0xec004000, ~0U, 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;
|
||||
|
||||
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);
|
||||
|
||||
/* 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,
|
||||
};
|
||||
@@ -0,0 +1,452 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* From Coreboot file of same name
|
||||
*
|
||||
* Copyright (C) 2007-2009 coresystems GmbH
|
||||
* Copyright (C) 2011 The Chromium Authors
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu_common.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/model_206ax.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
bool cpu_ivybridge_config_tdp_levels(void)
|
||||
{
|
||||
struct cpuid_result result;
|
||||
|
||||
/* Minimum CPU revision */
|
||||
result = cpuid(1);
|
||||
if (result.eax < IVB_CONFIG_TDP_MIN_CPUID)
|
||||
return false;
|
||||
|
||||
return cpu_config_tdp_levels();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_ivybridge_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 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;
|
||||
uint ratio;
|
||||
|
||||
/* Check for configurable TDP option */
|
||||
if (cpu_ivybridge_config_tdp_levels()) {
|
||||
/* Set to nominal TDP ratio */
|
||||
msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
|
||||
ratio = msr.lo & 0xff;
|
||||
} else {
|
||||
/* Platform Info bits 15:8 give max ratio */
|
||||
msr = msr_read(MSR_PLATFORM_INFO);
|
||||
ratio = (msr.lo & 0xff00) >> 8;
|
||||
}
|
||||
cpu_set_perf_control(ratio);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int model_206ax_init(struct udevice *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Clear out pending MCEs */
|
||||
configure_mca();
|
||||
|
||||
/* 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 = cpu_configure_thermal_target(dev);
|
||||
if (ret) {
|
||||
debug("Cannot set thermal target\n");
|
||||
if (ret != -ENOENT)
|
||||
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)
|
||||
{
|
||||
return cpu_intel_get_info(info, INTEL_BCLK_MHZ);
|
||||
|
||||
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,
|
||||
.get_vendor = cpu_x86_get_vendor,
|
||||
};
|
||||
|
||||
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,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -0,0 +1,261 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* From Coreboot northbridge/intel/sandybridge/northbridge.c
|
||||
*
|
||||
* Copyright (C) 2007-2009 coresystems GmbH
|
||||
* Copyright (C) 2011 The Chromium Authors
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_ivybridge_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* sandybridge_init_iommu() - Set up IOMMU so that azalia can be used
|
||||
*
|
||||
* It is not obvious where these values come from. They may be undocumented.
|
||||
*/
|
||||
static void sandybridge_init_iommu(struct udevice *dev)
|
||||
{
|
||||
u32 capid0_a;
|
||||
|
||||
dm_pci_read_config32(dev, 0xe4, &capid0_a);
|
||||
if (capid0_a & (1 << 23)) {
|
||||
log_debug("capid0_a not needed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup BARs */
|
||||
writel(IOMMU_BASE1 >> 32, MCHBAR_REG(0x5404));
|
||||
writel(IOMMU_BASE1 | 1, MCHBAR_REG(0x5400));
|
||||
writel(IOMMU_BASE2 >> 32, MCHBAR_REG(0x5414));
|
||||
writel(IOMMU_BASE2 | 1, MCHBAR_REG(0x5410));
|
||||
|
||||
/* lock policies */
|
||||
writel(0x80000000, IOMMU_BASE1 + 0xff0);
|
||||
|
||||
/* Enable azalia sound */
|
||||
writel(0x20000000, IOMMU_BASE2 + 0xff0);
|
||||
writel(0xa0000000, IOMMU_BASE2 + 0xff0);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* Setup IOMMU BARs */
|
||||
sandybridge_init_iommu(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,
|
||||
};
|
||||
@@ -0,0 +1,257 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* From Coreboot
|
||||
* Copyright (C) 2008-2009 coresystems GmbH
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <ahci.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>
|
||||
|
||||
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(dev);
|
||||
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")) {
|
||||
ulong 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: %08lx\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(dev);
|
||||
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_bind(struct udevice *dev)
|
||||
{
|
||||
struct udevice *scsi_dev;
|
||||
int ret;
|
||||
|
||||
if (gd->flags & GD_FLG_RELOC) {
|
||||
ret = ahci_bind_scsi(dev, &scsi_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = ahci_probe_scsi_pci(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
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,
|
||||
.bind = bd82x6x_sata_bind,
|
||||
.probe = bd82x6x_sata_probe,
|
||||
};
|
||||
@@ -0,0 +1,559 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <init.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <rtc.h>
|
||||
#include <spi.h>
|
||||
#include <spi_flash.h>
|
||||
#include <syscon.h>
|
||||
#include <sysreset.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);
|
||||
}
|
||||
|
||||
int dram_init_banksize(void)
|
||||
{
|
||||
mrc_common_dram_init_banksize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
debug("%s: Could not locate SPD (ret=%d)\n", __func__, 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;
|
||||
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;
|
||||
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;
|
||||
|
||||
/* GTT Graphics Stolen Memory Size (GGMS) */
|
||||
uma_size = ((ggc >> 8) & 0x3) * 1024ULL;
|
||||
tomk -= uma_size;
|
||||
uma_memory_base = tomk * 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;
|
||||
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;
|
||||
|
||||
/* We need the pinctrl set up early */
|
||||
ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev);
|
||||
if (ret) {
|
||||
debug("%s: Could not get pinconf (ret=%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev);
|
||||
if (ret) {
|
||||
debug("%s: Could not get northbridge (ret=%d)\n", __func__,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev);
|
||||
if (ret) {
|
||||
debug("%s: Could not get ME (ret=%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
ret = copy_spd(dev, pei_data);
|
||||
if (ret) {
|
||||
debug("%s: Could not get SPD (ret=%d)\n", __func__, 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");
|
||||
sysreset_walk_halt(SYSRESET_COLD);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
debug("%s: Could not init ME (ret=%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
ret = intel_early_me_uma_size(me_dev);
|
||||
if (ret < 0) {
|
||||
debug("%s: Could not get UMA size (ret=%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mrc_common_init(dev, pei_data, false);
|
||||
if (ret) {
|
||||
debug("%s: mrc_common_init() failed (ret=%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdram_find(dev);
|
||||
if (ret) {
|
||||
debug("%s: sdram_find() failed (ret=%d)\n", __func__, 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;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
gd->ram_size = 1ULL << 31;
|
||||
gd->bd->bi_dram[0].start = 0;
|
||||
gd->bd->bi_dram[0].size = gd->ram_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user