commit
f4e7e2d121
@ -0,0 +1,146 @@ |
||||
/*
|
||||
* Copyright (C) 2014 Google, Inc |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <errno.h> |
||||
#include <fdtdec.h> |
||||
#include <malloc.h> |
||||
#include <asm/lapic.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> |
||||
|
||||
void bd82x6x_pci_init(pci_dev_t dev) |
||||
{ |
||||
u16 reg16; |
||||
u8 reg8; |
||||
|
||||
debug("bd82x6x PCI init.\n"); |
||||
/* Enable Bus Master */ |
||||
reg16 = pci_read_config16(dev, PCI_COMMAND); |
||||
reg16 |= PCI_COMMAND_MASTER; |
||||
pci_write_config16(dev, PCI_COMMAND, reg16); |
||||
|
||||
/* This device has no interrupt */ |
||||
pci_write_config8(dev, INTR, 0xff); |
||||
|
||||
/* disable parity error response and SERR */ |
||||
reg16 = pci_read_config16(dev, BCTRL); |
||||
reg16 &= ~(1 << 0); |
||||
reg16 &= ~(1 << 1); |
||||
pci_write_config16(dev, BCTRL, reg16); |
||||
|
||||
/* Master Latency Count must be set to 0x04! */ |
||||
reg8 = pci_read_config8(dev, SMLT); |
||||
reg8 &= 0x07; |
||||
reg8 |= (0x04 << 3); |
||||
pci_write_config8(dev, SMLT, reg8); |
||||
|
||||
/* Will this improve throughput of bus masters? */ |
||||
pci_write_config8(dev, PCI_MIN_GNT, 0x06); |
||||
|
||||
/* Clear errors in status registers */ |
||||
reg16 = pci_read_config16(dev, PSTS); |
||||
/* reg16 |= 0xf900; */ |
||||
pci_write_config16(dev, PSTS, reg16); |
||||
|
||||
reg16 = pci_read_config16(dev, SECSTS); |
||||
/* reg16 |= 0xf900; */ |
||||
pci_write_config16(dev, SECSTS, reg16); |
||||
} |
||||
|
||||
#define PCI_BRIDGE_UPDATE_COMMAND |
||||
void bd82x6x_pci_dev_enable_resources(pci_dev_t dev) |
||||
{ |
||||
uint16_t command; |
||||
|
||||
command = pci_read_config16(dev, PCI_COMMAND); |
||||
command |= PCI_COMMAND_IO; |
||||
#ifdef PCI_BRIDGE_UPDATE_COMMAND |
||||
/*
|
||||
* If we write to PCI_COMMAND, on some systems this will cause the |
||||
* ROM and APICs to become invisible. |
||||
*/ |
||||
debug("%x cmd <- %02x\n", dev, command); |
||||
pci_write_config16(dev, PCI_COMMAND, command); |
||||
#else |
||||
printf("%s cmd <- %02x (NOT WRITTEN!)\n", dev_path(dev), command); |
||||
#endif |
||||
} |
||||
|
||||
void bd82x6x_pci_bus_enable_resources(pci_dev_t dev) |
||||
{ |
||||
uint16_t ctrl; |
||||
|
||||
ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL); |
||||
ctrl |= PCI_COMMAND_IO; |
||||
ctrl |= PCI_BRIDGE_CTL_VGA; |
||||
debug("%x bridge ctrl <- %04x\n", dev, ctrl); |
||||
pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); |
||||
|
||||
bd82x6x_pci_dev_enable_resources(dev); |
||||
} |
||||
|
||||
int bd82x6x_init_pci_devices(void) |
||||
{ |
||||
const void *blob = gd->fdt_blob; |
||||
struct pci_controller *hose; |
||||
struct x86_cpu_priv *cpu; |
||||
int sata_node, gma_node; |
||||
int ret; |
||||
|
||||
hose = pci_bus_to_hose(0); |
||||
lpc_enable(PCH_LPC_DEV); |
||||
lpc_init(hose, PCH_LPC_DEV); |
||||
sata_node = fdtdec_next_compatible(blob, 0, |
||||
COMPAT_INTEL_PANTHERPOINT_AHCI); |
||||
if (sata_node < 0) { |
||||
debug("%s: Cannot find SATA node\n", __func__); |
||||
return -EINVAL; |
||||
} |
||||
bd82x6x_sata_init(PCH_SATA_DEV, blob, sata_node); |
||||
bd82x6x_usb_ehci_init(PCH_EHCI1_DEV); |
||||
bd82x6x_usb_ehci_init(PCH_EHCI2_DEV); |
||||
|
||||
cpu = calloc(1, sizeof(*cpu)); |
||||
if (!cpu) |
||||
return -ENOMEM; |
||||
model_206ax_init(cpu); |
||||
|
||||
gma_node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_GMA); |
||||
if (gma_node < 0) { |
||||
debug("%s: Cannot find GMA node\n", __func__); |
||||
return -EINVAL; |
||||
} |
||||
ret = gma_func0_init(PCH_VIDEO_DEV, pci_bus_to_hose(0), blob, |
||||
gma_node); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int bd82x6x_init(void) |
||||
{ |
||||
const void *blob = gd->fdt_blob; |
||||
int sata_node; |
||||
|
||||
sata_node = fdtdec_next_compatible(blob, 0, |
||||
COMPAT_INTEL_PANTHERPOINT_AHCI); |
||||
if (sata_node < 0) { |
||||
debug("%s: Cannot find SATA node\n", __func__); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
bd82x6x_pci_init(PCH_DEV); |
||||
bd82x6x_sata_enable(PCH_SATA_DEV, blob, sata_node); |
||||
northbridge_enable(PCH_DEV); |
||||
northbridge_init(PCH_DEV); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,756 @@ |
||||
/*
|
||||
* 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 <errno.h> |
||||
#include <fdtdec.h> |
||||
#include <pci_rom.h> |
||||
#include <asm/io.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) |
||||
{ |
||||
u32 reg32; |
||||
|
||||
debug("GT Power Management Init, silicon = %#x\n", |
||||
bridge_silicon_revision()); |
||||
|
||||
if (bridge_silicon_revision() < 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 ((bridge_silicon_revision() & 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 (bridge_silicon_revision() >= 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 ((bridge_silicon_revision() & 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 (bridge_silicon_revision() >= SNB_STEP_D1) |
||||
reg32 |= (1 << 20); |
||||
gtt_write(gtt_bar, 0xa180, reg32); |
||||
|
||||
/* 6a: for SnB step D2+ only */ |
||||
if (((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) && |
||||
(bridge_silicon_revision() >= 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 ((bridge_silicon_revision() & 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 ((bridge_silicon_revision() & 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(void *gtt_bar, const void *blob, int node) |
||||
{ |
||||
u32 reg32, cycle_delay; |
||||
|
||||
debug("GT Power Management Init (post VBIOS)\n"); |
||||
|
||||
/* 15: Deassert Force Wake */ |
||||
if (bridge_silicon_revision() < 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; |
||||
} |
||||
|
||||
int gma_func0_init(pci_dev_t dev, struct pci_controller *hose, |
||||
const void *blob, int node) |
||||
{ |
||||
void *gtt_bar; |
||||
u32 reg32; |
||||
int ret; |
||||
|
||||
/* IGD needs to be Bus Master */ |
||||
reg32 = pci_read_config32(dev, PCI_COMMAND); |
||||
reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; |
||||
pci_write_config32(dev, PCI_COMMAND, reg32); |
||||
|
||||
gtt_bar = (void *)pci_read_bar32(pci_bus_to_hose(0), dev, 0); |
||||
debug("GT bar %p\n", gtt_bar); |
||||
ret = gma_pm_init_pre_vbios(gtt_bar); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
ret = pci_run_vga_bios(dev, int15_handler, false); |
||||
|
||||
/* Post VBIOS init */ |
||||
ret = gma_pm_init_post_vbios(gtt_bar, blob, node); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
return 0; |
||||
} |
@ -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 |
@ -0,0 +1,514 @@ |
||||
/*
|
||||
* 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 <fdtdec.h> |
||||
#include <malloc.h> |
||||
#include <asm/acpi.h> |
||||
#include <asm/cpu.h> |
||||
#include <asm/lapic.h> |
||||
#include <asm/lapic_def.h> |
||||
#include <asm/msr.h> |
||||
#include <asm/mtrr.h> |
||||
#include <asm/processor.h> |
||||
#include <asm/speedstep.h> |
||||
#include <asm/turbo.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(void) |
||||
{ |
||||
int tcc_offset; |
||||
msr_t msr; |
||||
int node; |
||||
|
||||
/* Find pointer to CPU configuration */ |
||||
node = fdtdec_next_compatible(gd->fdt_blob, 0, |
||||
COMPAT_INTEL_MODEL_206AX); |
||||
if (node < 0) |
||||
return -ENOENT; |
||||
tcc_offset = fdtdec_get_int(gd->fdt_blob, node, "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(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 |
||||
|
||||
/*
|
||||
* Initialize any extra cores/threads in this package. |
||||
*/ |
||||
static int intel_cores_init(struct x86_cpu_priv *cpu) |
||||
{ |
||||
struct cpuid_result result; |
||||
unsigned threads_per_package, threads_per_core, i; |
||||
|
||||
/* Logical processors (threads) per core */ |
||||
result = cpuid_ext(0xb, 0); |
||||
threads_per_core = result.ebx & 0xffff; |
||||
|
||||
/* Logical processors (threads) per package */ |
||||
result = cpuid_ext(0xb, 1); |
||||
threads_per_package = result.ebx & 0xffff; |
||||
|
||||
debug("CPU: %u has %u cores, %u threads per core\n", |
||||
cpu->apic_id, threads_per_package / threads_per_core, |
||||
threads_per_core); |
||||
|
||||
for (i = 1; i < threads_per_package; ++i) { |
||||
struct x86_cpu_priv *new_cpu; |
||||
|
||||
new_cpu = calloc(1, sizeof(*new_cpu)); |
||||
if (!new_cpu) |
||||
return -ENOMEM; |
||||
|
||||
new_cpu->apic_id = cpu->apic_id + i; |
||||
|
||||
/* Update APIC ID if no hyperthreading */ |
||||
if (threads_per_core == 1) |
||||
new_cpu->apic_id <<= 1; |
||||
|
||||
debug("CPU: %u has core %u\n", cpu->apic_id, new_cpu->apic_id); |
||||
|
||||
#if CONFIG_SMP && CONFIG_MAX_CPUS > 1 |
||||
/* Start the new cpu */ |
||||
if (!start_cpu(new_cpu)) { |
||||
/* Record the error in cpu? */ |
||||
printk(BIOS_ERR, "CPU %u would not start!\n", |
||||
new_cpu->apic_id); |
||||
new_cpu->start_err = 1; |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int model_206ax_init(struct x86_cpu_priv *cpu) |
||||
{ |
||||
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 |
||||
|
||||
/* Setup MTRRs based on physical address size */ |
||||
#if 0 /* TODO: Implement this */
|
||||
struct cpuid_result cpuid_regs; |
||||
|
||||
cpuid_regs = cpuid(0x80000008); |
||||
x86_setup_fixed_mtrrs(); |
||||
x86_setup_var_mtrrs(cpuid_regs.eax & 0xff, 2); |
||||
x86_mtrr_check(); |
||||
#endif |
||||
|
||||
#if CONFIG_USBDEBUG |
||||
set_ehci_debug(ehci_debug_addr); |
||||
#endif |
||||
|
||||
/* Enable the local cpu apics */ |
||||
enable_lapic_tpr(); |
||||
lapic_setup(); |
||||
|
||||
/* 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(); |
||||
if (ret) |
||||
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(); |
||||
|
||||
/* Start up extra cores */ |
||||
intel_cores_init(cpu); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,188 @@ |
||||
/*
|
||||
* 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 <asm/msr.h> |
||||
#include <asm/acpi.h> |
||||
#include <asm/cpu.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> |
||||
|
||||
static int bridge_revision_id = -1; |
||||
|
||||
int bridge_silicon_revision(void) |
||||
{ |
||||
if (bridge_revision_id < 0) { |
||||
struct cpuid_result result; |
||||
uint8_t stepping, bridge_id; |
||||
pci_dev_t dev; |
||||
|
||||
result = cpuid(1); |
||||
stepping = result.eax & 0xf; |
||||
dev = PCI_BDF(0, 0, 0); |
||||
bridge_id = pci_read_config16(dev, PCI_DEVICE_ID) & 0xf0; |
||||
bridge_revision_id = bridge_id | stepping; |
||||
} |
||||
|
||||
return bridge_revision_id; |
||||
} |
||||
|
||||
/*
|
||||
* 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(u32 *base, u32 *len) |
||||
{ |
||||
pci_dev_t dev = PCI_BDF(0, 0, 0); |
||||
u32 pciexbar_reg; |
||||
|
||||
*base = 0; |
||||
*len = 0; |
||||
|
||||
pciexbar_reg = pci_read_config32(dev, PCIEXBAR); |
||||
|
||||
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(pci_dev_t dev, int index) |
||||
{ |
||||
u32 pcie_config_base, pcie_config_size; |
||||
|
||||
if (get_pcie_bar(&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(pci_dev_t dev) |
||||
{ |
||||
/* Clear error status bits */ |
||||
writel(0xffffffff, DMIBAR_REG(0x1c4)); |
||||
writel(0xffffffff, DMIBAR_REG(0x1d0)); |
||||
|
||||
/* Steps prior to DMI ASPM */ |
||||
if ((bridge_silicon_revision() & 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 (bridge_silicon_revision() >= SNB_STEP_D0) { |
||||
setbits_le32(DMIBAR_REG(0x1f8), 1 << 16); |
||||
} else if (bridge_silicon_revision() >= 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 ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) |
||||
setbits_le32(DMIBAR_REG(0xd04), 1 << 4); |
||||
|
||||
setbits_le32(DMIBAR_REG(0x88), (1 << 1) | (1 << 0)); |
||||
} |
||||
|
||||
void northbridge_init(pci_dev_t dev) |
||||
{ |
||||
u32 bridge_type; |
||||
|
||||
add_fixed_resources(dev, 6); |
||||
northbridge_dmi_init(dev); |
||||
|
||||
bridge_type = readl(MCHBAR_REG(0x5f10)); |
||||
bridge_type &= ~0xff; |
||||
|
||||
if ((bridge_silicon_revision() & 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)); |
||||
} |
||||
|
||||
void northbridge_enable(pci_dev_t dev) |
||||
{ |
||||
#if CONFIG_HAVE_ACPI_RESUME |
||||
switch (pci_read_config32(dev, SKPAD)) { |
||||
case 0xcafebabe: |
||||
debug("Normal boot.\n"); |
||||
apci_set_slp_type(0); |
||||
break; |
||||
case 0xcafed00d: |
||||
debug("S3 Resume.\n"); |
||||
apci_set_slp_type(3); |
||||
break; |
||||
default: |
||||
debug("Unknown boot method, assuming normal.\n"); |
||||
apci_set_slp_type(0); |
||||
break; |
||||
} |
||||
#endif |
||||
} |
@ -0,0 +1,123 @@ |
||||
/*
|
||||
* From Coreboot |
||||
* Copyright (C) 2008-2009 coresystems GmbH |
||||
* Copyright (C) 2012 The Chromium OS Authors. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/pci.h> |
||||
#include <asm/arch/pch.h> |
||||
|
||||
static int pch_revision_id = -1; |
||||
static int pch_type = -1; |
||||
|
||||
int pch_silicon_revision(void) |
||||
{ |
||||
pci_dev_t dev; |
||||
|
||||
dev = PCH_LPC_DEV; |
||||
|
||||
if (pch_revision_id < 0) |
||||
pch_revision_id = pci_read_config8(dev, PCI_REVISION_ID); |
||||
return pch_revision_id; |
||||
} |
||||
|
||||
int pch_silicon_type(void) |
||||
{ |
||||
pci_dev_t dev; |
||||
|
||||
dev = PCH_LPC_DEV; |
||||
|
||||
if (pch_type < 0) |
||||
pch_type = pci_read_config8(dev, PCI_DEVICE_ID + 1); |
||||
return pch_type; |
||||
} |
||||
|
||||
int pch_silicon_supported(int type, int rev) |
||||
{ |
||||
int cur_type = pch_silicon_type(); |
||||
int cur_rev = pch_silicon_revision(); |
||||
|
||||
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(u32 address, u32 andvalue, u32 orvalue) |
||||
{ |
||||
u32 data; |
||||
|
||||
/* Set the address */ |
||||
writel(address, RCB_REG(IOBPIRI)); |
||||
|
||||
/* READ OPCODE */ |
||||
if (pch_silicon_supported(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(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; |
||||
} |
@ -0,0 +1,225 @@ |
||||
/*
|
||||
* From Coreboot |
||||
* Copyright (C) 2008-2009 coresystems GmbH |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <fdtdec.h> |
||||
#include <asm/io.h> |
||||
#include <asm/pci.h> |
||||
#include <asm/arch/pch.h> |
||||
#include <asm/arch/bd82x6x.h> |
||||
|
||||
static inline u32 sir_read(pci_dev_t dev, int idx) |
||||
{ |
||||
pci_write_config32(dev, SATA_SIRI, idx); |
||||
return pci_read_config32(dev, SATA_SIRD); |
||||
} |
||||
|
||||
static inline void sir_write(pci_dev_t dev, int idx, u32 value) |
||||
{ |
||||
pci_write_config32(dev, SATA_SIRI, idx); |
||||
pci_write_config32(dev, SATA_SIRD, value); |
||||
} |
||||
|
||||
static void common_sata_init(pci_dev_t 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; |
||||
pci_write_config32(dev, IDE_CONFIG, reg32); |
||||
|
||||
/* Port enable */ |
||||
reg16 = pci_read_config16(dev, 0x92); |
||||
reg16 &= ~0x3f; |
||||
reg16 |= port_map; |
||||
pci_write_config16(dev, 0x92, reg16); |
||||
|
||||
/* SATA Initialization register */ |
||||
port_map &= 0xff; |
||||
pci_write_config32(dev, 0x94, ((port_map ^ 0x3f) << 24) | 0x183); |
||||
} |
||||
|
||||
void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node) |
||||
{ |
||||
unsigned int port_map, speed_support, port_tx; |
||||
struct pci_controller *hose = pci_bus_to_hose(0); |
||||
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); |
||||
|
||||
/* Enable BARs */ |
||||
pci_write_config16(dev, PCI_COMMAND, 0x0007); |
||||
|
||||
mode = fdt_getprop(blob, node, "intel,sata-mode", NULL); |
||||
if (!mode || !strcmp(mode, "ahci")) { |
||||
u32 abar; |
||||
|
||||
debug("SATA: Controller in AHCI mode\n"); |
||||
|
||||
/* Set Interrupt Line, Interrupt Pin is set by D31IP.PIP */ |
||||
pci_write_config8(dev, INTR_LN, 0x0a); |
||||
|
||||
/* Set timings */ |
||||
pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | |
||||
IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | |
||||
IDE_PPE0 | IDE_IE0 | IDE_TIME0); |
||||
pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | |
||||
IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); |
||||
|
||||
/* Sync DMA */ |
||||
pci_write_config16(dev, IDE_SDMA_CNT, IDE_PSDE0); |
||||
pci_write_config16(dev, IDE_SDMA_TIM, 0x0001); |
||||
|
||||
common_sata_init(dev, 0x8000 | port_map); |
||||
|
||||
/* Initialize AHCI memory-mapped space */ |
||||
abar = pci_read_bar32(hose, 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 */ |
||||
pci_write_bar32(hose, dev, 5, 0x00000000); |
||||
/* And without AHCI BAR no memory decoding */ |
||||
reg16 = pci_read_config16(dev, PCI_COMMAND); |
||||
reg16 &= ~PCI_COMMAND_MEMORY; |
||||
pci_write_config16(dev, PCI_COMMAND, reg16); |
||||
|
||||
pci_write_config8(dev, 0x09, 0x80); |
||||
|
||||
/* Set timings */ |
||||
pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | |
||||
IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); |
||||
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 */ |
||||
pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0); |
||||
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 */ |
||||
pci_write_bar32(hose, dev, 5, 0x00000000); |
||||
|
||||
/* And without AHCI BAR no memory decoding */ |
||||
reg16 = pci_read_config16(dev, PCI_COMMAND); |
||||
reg16 &= ~PCI_COMMAND_MEMORY; |
||||
pci_write_config16(dev, PCI_COMMAND, reg16); |
||||
|
||||
/*
|
||||
* Native mode capable on both primary and secondary (0xa) |
||||
* OR'ed with enabled (0x50) = 0xf |
||||
*/ |
||||
pci_write_config8(dev, 0x09, 0x8f); |
||||
|
||||
/* Set Interrupt Line */ |
||||
/* Interrupt Pin is set by D31IP.PIP */ |
||||
pci_write_config8(dev, INTR_LN, 0xff); |
||||
|
||||
/* Set timings */ |
||||
pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | |
||||
IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | |
||||
IDE_PPE0 | IDE_IE0 | IDE_TIME0); |
||||
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 */ |
||||
pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0 | IDE_PSDE0); |
||||
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(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(SATA_IOBP_SP1G3IR, 0, port_tx); |
||||
|
||||
/* Additional Programming Requirements */ |
||||
sir_write(dev, 0x04, 0x00001600); |
||||
sir_write(dev, 0x28, 0xa0000033); |
||||
reg32 = sir_read(dev, 0x54); |
||||
reg32 &= 0xff000000; |
||||
reg32 |= 0x5555aa; |
||||
sir_write(dev, 0x54, reg32); |
||||
sir_write(dev, 0x64, 0xcccc8484); |
||||
reg32 = sir_read(dev, 0x68); |
||||
reg32 &= 0xffff0000; |
||||
reg32 |= 0xcccc; |
||||
sir_write(dev, 0x68, reg32); |
||||
reg32 = sir_read(dev, 0x78); |
||||
reg32 &= 0x0000ffff; |
||||
reg32 |= 0x88880000; |
||||
sir_write(dev, 0x78, reg32); |
||||
sir_write(dev, 0x84, 0x001c7000); |
||||
sir_write(dev, 0x88, 0x88338822); |
||||
sir_write(dev, 0xa0, 0x001c7000); |
||||
sir_write(dev, 0xc4, 0x0c0c0c0c); |
||||
sir_write(dev, 0xc8, 0x0c0c0c0c); |
||||
sir_write(dev, 0xd4, 0x10000000); |
||||
|
||||
pch_iobp_update(0xea004001, 0x3fffffff, 0xc0000000); |
||||
pch_iobp_update(0xea00408a, 0xfffffcff, 0x00000100); |
||||
} |
||||
|
||||
void bd82x6x_sata_enable(pci_dev_t dev, const void *blob, int node) |
||||
{ |
||||
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; |
||||
pci_write_config16(dev, 0x90, map); |
||||
} |
@ -0,0 +1,29 @@ |
||||
/*
|
||||
* From Coreboot |
||||
* Copyright (C) 2008-2009 coresystems GmbH |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/pci.h> |
||||
#include <asm/arch/pch.h> |
||||
|
||||
void bd82x6x_usb_ehci_init(pci_dev_t dev) |
||||
{ |
||||
u32 reg32; |
||||
|
||||
/* Disable Wake on Disconnect in RMH */ |
||||
reg32 = readl(RCB_REG(0x35b0)); |
||||
reg32 |= 0x22; |
||||
writel(reg32, RCB_REG(0x35b0)); |
||||
|
||||
debug("EHCI: Setting up controller.. "); |
||||
reg32 = pci_read_config32(dev, PCI_COMMAND); |
||||
reg32 |= PCI_COMMAND_MASTER; |
||||
/* reg32 |= PCI_COMMAND_SERR; */ |
||||
pci_write_config32(dev, PCI_COMMAND, reg32); |
||||
|
||||
debug("done.\n"); |
||||
} |
@ -0,0 +1,32 @@ |
||||
/*
|
||||
* From Coreboot |
||||
* Copyright (C) 2008-2009 coresystems GmbH |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/pci.h> |
||||
#include <asm/arch/pch.h> |
||||
|
||||
void bd82x6x_usb_xhci_init(pci_dev_t dev) |
||||
{ |
||||
u32 reg32; |
||||
|
||||
debug("XHCI: Setting up controller.. "); |
||||
|
||||
/* lock overcurrent map */ |
||||
reg32 = pci_read_config32(dev, 0x44); |
||||
reg32 |= 1; |
||||
pci_write_config32(dev, 0x44, reg32); |
||||
|
||||
/* Enable clock gating */ |
||||
reg32 = pci_read_config32(dev, 0x40); |
||||
reg32 &= ~((1 << 20) | (1 << 21)); |
||||
reg32 |= (1 << 19) | (1 << 18) | (1 << 17); |
||||
reg32 |= (1 << 10) | (1 << 9) | (1 << 8); |
||||
reg32 |= (1 << 31); /* lock */ |
||||
pci_write_config32(dev, 0x40, reg32); |
||||
|
||||
debug("done.\n"); |
||||
} |
@ -0,0 +1,57 @@ |
||||
/*
|
||||
* 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/msr.h> |
||||
#include <asm/io.h> |
||||
#include <asm/lapic.h> |
||||
#include <asm/post.h> |
||||
|
||||
void lapic_setup(void) |
||||
{ |
||||
#if NEED_LAPIC == 1 |
||||
/* 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_around(LAPIC_TASKPRI, |
||||
lapic_read_around(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); |
||||
|
||||
/* Put the local apic in virtual wire mode */ |
||||
lapic_write_around(LAPIC_SPIV, (lapic_read_around(LAPIC_SPIV) & |
||||
~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); |
||||
lapic_write_around(LAPIC_LVT0, (lapic_read_around(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_around(LAPIC_LVT1, (lapic_read_around(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()); |
||||
#else /* !NEED_LLAPIC */ |
||||
/* Only Pentium Pro and later have those MSR stuff */ |
||||
debug("Disabling local apic: "); |
||||
disable_lapic(); |
||||
#endif /* !NEED_LAPIC */ |
||||
debug("done.\n"); |
||||
post_code(POST_LAPIC); |
||||
} |
@ -0,0 +1,98 @@ |
||||
/*
|
||||
* From Coreboot file of the same name |
||||
* |
||||
* Copyright (C) 2011 The Chromium Authors. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/cpu.h> |
||||
#include <asm/msr.h> |
||||
#include <asm/processor.h> |
||||
#include <asm/turbo.h> |
||||
|
||||
#if CONFIG_CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED |
||||
static inline int get_global_turbo_state(void) |
||||
{ |
||||
return TURBO_UNKNOWN; |
||||
} |
||||
|
||||
static inline void set_global_turbo_state(int state) |
||||
{ |
||||
} |
||||
#else |
||||
static int g_turbo_state = TURBO_UNKNOWN; |
||||
|
||||
static inline int get_global_turbo_state(void) |
||||
{ |
||||
return g_turbo_state; |
||||
} |
||||
|
||||
static inline void set_global_turbo_state(int state) |
||||
{ |
||||
g_turbo_state = state; |
||||
} |
||||
#endif |
||||
|
||||
static const char *const turbo_state_desc[] = { |
||||
[TURBO_UNKNOWN] = "unknown", |
||||
[TURBO_UNAVAILABLE] = "unavailable", |
||||
[TURBO_DISABLED] = "available but hidden", |
||||
[TURBO_ENABLED] = "available and visible" |
||||
}; |
||||
|
||||
/*
|
||||
* Determine the current state of Turbo and cache it for later. |
||||
* Turbo is a package level config so it does not need to be |
||||
* enabled on every core. |
||||
*/ |
||||
int turbo_get_state(void) |
||||
{ |
||||
struct cpuid_result cpuid_regs; |
||||
int turbo_en, turbo_cap; |
||||
msr_t msr; |
||||
int turbo_state = get_global_turbo_state(); |
||||
|
||||
/* Return cached state if available */ |
||||
if (turbo_state != TURBO_UNKNOWN) |
||||
return turbo_state; |
||||
|
||||
cpuid_regs = cpuid(CPUID_LEAF_PM); |
||||
turbo_cap = !!(cpuid_regs.eax & PM_CAP_TURBO_MODE); |
||||
|
||||
msr = msr_read(MSR_IA32_MISC_ENABLES); |
||||
turbo_en = !(msr.hi & H_MISC_DISABLE_TURBO); |
||||
|
||||
if (!turbo_cap && turbo_en) { |
||||
/* Unavailable */ |
||||
turbo_state = TURBO_UNAVAILABLE; |
||||
} else if (!turbo_cap && !turbo_en) { |
||||
/* Available but disabled */ |
||||
turbo_state = TURBO_DISABLED; |
||||
} else if (turbo_cap && turbo_en) { |
||||
/* Available */ |
||||
turbo_state = TURBO_ENABLED; |
||||
} |
||||
|
||||
set_global_turbo_state(turbo_state); |
||||
debug("Turbo is %s\n", turbo_state_desc[turbo_state]); |
||||
return turbo_state; |
||||
} |
||||
|
||||
void turbo_enable(void) |
||||
{ |
||||
msr_t msr; |
||||
|
||||
/* Only possible if turbo is available but hidden */ |
||||
if (turbo_get_state() == TURBO_DISABLED) { |
||||
/* Clear Turbo Disable bit in Misc Enables */ |
||||
msr = msr_read(MSR_IA32_MISC_ENABLES); |
||||
msr.hi &= ~H_MISC_DISABLE_TURBO; |
||||
msr_write(MSR_IA32_MISC_ENABLES, msr); |
||||
|
||||
/* Update cached turbo state */ |
||||
set_global_turbo_state(TURBO_ENABLED); |
||||
debug("Turbo has been enabled\n"); |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
/*
|
||||
* From coreboot |
||||
* |
||||
* Copyright (C) 2004 SUSE LINUX AG |
||||
* Copyright (C) 2004 Nick Barker |
||||
* Copyright (C) 2008-2009 coresystems GmbH |
||||
* (Written by Stefan Reinauer <stepan@coresystems.de>) |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#ifndef __ASM_ACPI_H |
||||
#define __ASM_ACPI_H |
||||
|
||||
#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */ |
||||
#define ACPI_TABLE_CREATOR "U-BootAC" /* Must be exactly 8 bytes long! */ |
||||
#define OEM_ID "U-Boot" /* Must be exactly 6 bytes long! */ |
||||
#define ASLC "U-Bo" /* Must be exactly 4 bytes long! */ |
||||
|
||||
/* 0 = S0, 1 = S1 ...*/ |
||||
int acpi_get_slp_type(void); |
||||
void apci_set_slp_type(int type); |
||||
|
||||
#endif |
@ -0,0 +1,23 @@ |
||||
/*
|
||||
* Copyright (C) 2014 Google, Inc |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _ASM_ARCH_BD82X6X_H |
||||
#define _ASM_ARCH_BD82X6X_H |
||||
|
||||
void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node); |
||||
void bd82x6x_sata_enable(pci_dev_t dev, const void *blob, int node); |
||||
void bd82x6x_pci_init(pci_dev_t dev); |
||||
void bd82x6x_usb_ehci_init(pci_dev_t dev); |
||||
void bd82x6x_usb_xhci_init(pci_dev_t dev); |
||||
int bd82x6x_init_pci_devices(void); |
||||
int gma_func0_init(pci_dev_t dev, struct pci_controller *hose, |
||||
const void *blob, int node); |
||||
int bd82x6x_init(void); |
||||
|
||||
struct x86_cpu_priv; |
||||
int model_206ax_init(struct x86_cpu_priv *cpu); |
||||
|
||||
#endif |
@ -0,0 +1,38 @@ |
||||
/*
|
||||
* From coreboot file of the same name |
||||
* |
||||
* Copyright (C) 2010 coresystems GmbH |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#ifndef __ASM_IOAPIC_H |
||||
#define __ASM_IOAPIC_H |
||||
|
||||
#define IO_APIC_ADDR 0xfec00000 |
||||
#define IO_APIC_INDEX IO_APIC_ADDR |
||||
#define IO_APIC_DATA (IO_APIC_ADDR + 0x10) |
||||
#define IO_APIC_INTERRUPTS 24 |
||||
|
||||
#define ALL (0xff << 24) |
||||
#define NONE 0 |
||||
#define DISABLED (1 << 16) |
||||
#define ENABLED (0 << 16) |
||||
#define TRIGGER_EDGE (0 << 15) |
||||
#define TRIGGER_LEVEL (1 << 15) |
||||
#define POLARITY_HIGH (0 << 13) |
||||
#define POLARITY_LOW (1 << 13) |
||||
#define PHYSICAL_DEST (0 << 11) |
||||
#define LOGICAL_DEST (1 << 11) |
||||
#define ExtINT (7 << 8) |
||||
#define NMI (4 << 8) |
||||
#define SMI (2 << 8) |
||||
#define INT (1 << 8) |
||||
|
||||
u32 io_apic_read(u32 ioapic_base, u32 reg); |
||||
void io_apic_write(u32 ioapic_base, u32 reg, u32 value); |
||||
void set_ioapic_id(u32 ioapic_base, u8 ioapic_id); |
||||
void setup_ioapic(u32 ioapic_base, u8 ioapic_id); |
||||
void clear_ioapic(u32 ioapic_base); |
||||
|
||||
#endif |
@ -0,0 +1,89 @@ |
||||
/*
|
||||
* From Coreboot file of same name |
||||
* |
||||
* Copyright (C) 2007-2009 coresystems GmbH |
||||
* 2012 secunet Security Networks AG |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#ifndef _ASM_SPEEDSTEP_H |
||||
#define _ASM_SPEEDSTEP_H |
||||
|
||||
/* Magic value used to locate speedstep configuration in the device tree */ |
||||
#define SPEEDSTEP_APIC_MAGIC 0xACAC |
||||
|
||||
/* MWAIT coordination I/O base address. This must match
|
||||
* the \_PR_.CPU0 PM base address. |
||||
*/ |
||||
#define PMB0_BASE 0x510 |
||||
|
||||
/* PMB1: I/O port that triggers SMI once cores are in the same state.
|
||||
* See CSM Trigger, at PMG_CST_CONFIG_CONTROL[6:4] |
||||
*/ |
||||
#define PMB1_BASE 0x800 |
||||
|
||||
struct sst_state { |
||||
uint8_t dynfsb:1; /* whether this is SLFM */ |
||||
uint8_t nonint:1; /* add .5 to ratio */ |
||||
uint8_t ratio:6; |
||||
uint8_t vid; |
||||
uint8_t is_turbo; |
||||
uint8_t is_slfm; |
||||
uint32_t power; |
||||
}; |
||||
#define SPEEDSTEP_RATIO_SHIFT 8 |
||||
#define SPEEDSTEP_RATIO_DYNFSB_SHIFT (7 + SPEEDSTEP_RATIO_SHIFT) |
||||
#define SPEEDSTEP_RATIO_DYNFSB (1 << SPEEDSTEP_RATIO_DYNFSB_SHIFT) |
||||
#define SPEEDSTEP_RATIO_NONINT_SHIFT (6 + SPEEDSTEP_RATIO_SHIFT) |
||||
#define SPEEDSTEP_RATIO_NONINT (1 << SPEEDSTEP_RATIO_NONINT_SHIFT) |
||||
#define SPEEDSTEP_RATIO_VALUE_MASK (0x1f << SPEEDSTEP_RATIO_SHIFT) |
||||
#define SPEEDSTEP_VID_MASK 0x3f |
||||
#define SPEEDSTEP_STATE_FROM_MSR(val, mask) ((struct sst_state){ \ |
||||
0, /* dynfsb won't be read. */ \
|
||||
((val & mask) & SPEEDSTEP_RATIO_NONINT) ? 1 : 0, \
|
||||
(((val & mask) & SPEEDSTEP_RATIO_VALUE_MASK) \
|
||||
>> SPEEDSTEP_RATIO_SHIFT), \
|
||||
(val & mask) & SPEEDSTEP_VID_MASK, \
|
||||
0, /* not turbo by default */ \
|
||||
0, /* not slfm by default */ \
|
||||
0 /* power is hardcoded in software. */ \
|
||||
}) |
||||
#define SPEEDSTEP_ENCODE_STATE(state) ( \ |
||||
((uint16_t)(state).dynfsb << SPEEDSTEP_RATIO_DYNFSB_SHIFT) | \
|
||||
((uint16_t)(state).nonint << SPEEDSTEP_RATIO_NONINT_SHIFT) | \
|
||||
((uint16_t)(state).ratio << SPEEDSTEP_RATIO_SHIFT) | \
|
||||
((uint16_t)(state).vid & SPEEDSTEP_VID_MASK)) |
||||
#define SPEEDSTEP_DOUBLE_RATIO(state) ( \ |
||||
((uint8_t)(state).ratio * 2) + (state).nonint) |
||||
|
||||
struct sst_params { |
||||
struct sst_state slfm; |
||||
struct sst_state min; |
||||
struct sst_state max; |
||||
struct sst_state turbo; |
||||
}; |
||||
|
||||
/* Looking at core2's spec, the highest normal bus ratio for an eist enabled
|
||||
processor is 14, the lowest is always 6. This makes 5 states with the |
||||
minimal step width of 2. With turbo mode and super LFM we have at most 7. */ |
||||
#define SPEEDSTEP_MAX_NORMAL_STATES 5 |
||||
#define SPEEDSTEP_MAX_STATES (SPEEDSTEP_MAX_NORMAL_STATES + 2) |
||||
struct sst_table { |
||||
/* Table of p-states for EMTTM and ACPI by decreasing performance. */ |
||||
struct sst_state states[SPEEDSTEP_MAX_STATES]; |
||||
int num_states; |
||||
}; |
||||
|
||||
void speedstep_gen_pstates(struct sst_table *); |
||||
|
||||
#define SPEEDSTEP_MAX_POWER_YONAH 31000 |
||||
#define SPEEDSTEP_MIN_POWER_YONAH 13100 |
||||
#define SPEEDSTEP_MAX_POWER_MEROM 35000 |
||||
#define SPEEDSTEP_MIN_POWER_MEROM 25000 |
||||
#define SPEEDSTEP_SLFM_POWER_MEROM 12000 |
||||
#define SPEEDSTEP_MAX_POWER_PENRYN 35000 |
||||
#define SPEEDSTEP_MIN_POWER_PENRYN 15000 |
||||
#define SPEEDSTEP_SLFM_POWER_PENRYN 12000 |
||||
|
||||
#endif |
@ -0,0 +1,31 @@ |
||||
/*
|
||||
* From coreboot file of the same name |
||||
* |
||||
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#ifndef _ASM_TURBO_H |
||||
#define _ASM_TURBO_H |
||||
|
||||
#define CPUID_LEAF_PM 6 |
||||
#define PM_CAP_TURBO_MODE (1 << 1) |
||||
|
||||
#define MSR_IA32_MISC_ENABLES 0x1a0 |
||||
#define H_MISC_DISABLE_TURBO (1 << 6) |
||||
|
||||
enum { |
||||
TURBO_UNKNOWN, |
||||
TURBO_UNAVAILABLE, |
||||
TURBO_DISABLED, |
||||
TURBO_ENABLED, |
||||
}; |
||||
|
||||
/* Return current turbo state */ |
||||
int turbo_get_state(void); |
||||
|
||||
/* Enable turbo */ |
||||
void turbo_enable(void); |
||||
|
||||
#endif |
@ -0,0 +1,347 @@ |
||||
/*
|
||||
* From Coreboot file device/oprom/realmode/x86.c |
||||
* |
||||
* Copyright (C) 2007 Advanced Micro Devices, Inc. |
||||
* Copyright (C) 2009-2010 coresystems GmbH |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
#include <common.h> |
||||
#include <bios_emul.h> |
||||
#include <vbe.h> |
||||
#include <asm/cache.h> |
||||
#include <asm/processor.h> |
||||
#include <asm/i8259.h> |
||||
#include <asm/io.h> |
||||
#include <asm/post.h> |
||||
#include "bios.h" |
||||
|
||||
/* Interrupt handlers for each interrupt the ROM can call */ |
||||
static int (*int_handler[256])(void); |
||||
|
||||
/* to have a common register file for interrupt handlers */ |
||||
X86EMU_sysEnv _X86EMU_env; |
||||
|
||||
asmlinkage void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, |
||||
u32 esi, u32 edi); |
||||
|
||||
asmlinkage void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, |
||||
u32 edx, u32 esi, u32 edi); |
||||
|
||||
static void setup_realmode_code(void) |
||||
{ |
||||
memcpy((void *)REALMODE_BASE, &asm_realmode_code, |
||||
asm_realmode_code_size); |
||||
|
||||
/* Ensure the global pointers are relocated properly. */ |
||||
realmode_call = PTR_TO_REAL_MODE(asm_realmode_call); |
||||
realmode_interrupt = PTR_TO_REAL_MODE(__realmode_interrupt); |
||||
|
||||
debug("Real mode stub @%x: %d bytes\n", REALMODE_BASE, |
||||
asm_realmode_code_size); |
||||
} |
||||
|
||||
static void setup_rombios(void) |
||||
{ |
||||
const char date[] = "06/11/99"; |
||||
memcpy((void *)0xffff5, &date, 8); |
||||
|
||||
const char ident[] = "PCI_ISA"; |
||||
memcpy((void *)0xfffd9, &ident, 7); |
||||
|
||||
/* system model: IBM-AT */ |
||||
writeb(0xfc, 0xffffe); |
||||
} |
||||
|
||||
static int int_exception_handler(void) |
||||
{ |
||||
/* compatibility shim */ |
||||
struct eregs reg_info = { |
||||
.eax = M.x86.R_EAX, |
||||
.ecx = M.x86.R_ECX, |
||||
.edx = M.x86.R_EDX, |
||||
.ebx = M.x86.R_EBX, |
||||
.esp = M.x86.R_ESP, |
||||
.ebp = M.x86.R_EBP, |
||||
.esi = M.x86.R_ESI, |
||||
.edi = M.x86.R_EDI, |
||||
.vector = M.x86.intno, |
||||
.error_code = 0, |
||||
.eip = M.x86.R_EIP, |
||||
.cs = M.x86.R_CS, |
||||
.eflags = M.x86.R_EFLG |
||||
}; |
||||
struct eregs *regs = ®_info; |
||||
|
||||
debug("Oops, exception %d while executing option rom\n", regs->vector); |
||||
cpu_hlt(); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int int_unknown_handler(void) |
||||
{ |
||||
debug("Unsupported software interrupt #0x%x eax 0x%x\n", |
||||
M.x86.intno, M.x86.R_EAX); |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
/* setup interrupt handlers for mainboard */ |
||||
void bios_set_interrupt_handler(int intnum, int (*int_func)(void)) |
||||
{ |
||||
int_handler[intnum] = int_func; |
||||
} |
||||
|
||||
static void setup_interrupt_handlers(void) |
||||
{ |
||||
int i; |
||||
|
||||
/*
|
||||
* The first 16 int_handler functions are not BIOS services, |
||||
* but the CPU-generated exceptions ("hardware interrupts") |
||||
*/ |
||||
for (i = 0; i < 0x10; i++) |
||||
int_handler[i] = &int_exception_handler; |
||||
|
||||
/* Mark all other int_handler calls as unknown first */ |
||||
for (i = 0x10; i < 0x100; i++) { |
||||
/* Skip if bios_set_interrupt_handler() isn't called first */ |
||||
if (int_handler[i]) |
||||
continue; |
||||
|
||||
/*
|
||||
* Now set the default functions that are actually needed |
||||
* to initialize the option roms. The board may override |
||||
* these with bios_set_interrupt_handler() |
||||
*/ |
||||
switch (i) { |
||||
case 0x10: |
||||
int_handler[0x10] = &int10_handler; |
||||
break; |
||||
case 0x12: |
||||
int_handler[0x12] = &int12_handler; |
||||
break; |
||||
case 0x16: |
||||
int_handler[0x16] = &int16_handler; |
||||
break; |
||||
case 0x1a: |
||||
int_handler[0x1a] = &int1a_handler; |
||||
break; |
||||
default: |
||||
int_handler[i] = &int_unknown_handler; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void write_idt_stub(void *target, u8 intnum) |
||||
{ |
||||
unsigned char *codeptr; |
||||
|
||||
codeptr = (unsigned char *)target; |
||||
memcpy(codeptr, &__idt_handler, __idt_handler_size); |
||||
codeptr[3] = intnum; /* modify int# in the code stub. */ |
||||
} |
||||
|
||||
static void setup_realmode_idt(void) |
||||
{ |
||||
struct realmode_idt *idts = NULL; |
||||
int i; |
||||
|
||||
/*
|
||||
* Copy IDT stub code for each interrupt. This might seem wasteful |
||||
* but it is really simple |
||||
*/ |
||||
for (i = 0; i < 256; i++) { |
||||
idts[i].cs = 0; |
||||
idts[i].offset = 0x1000 + (i * __idt_handler_size); |
||||
write_idt_stub((void *)((u32)idts[i].offset), i); |
||||
} |
||||
|
||||
/*
|
||||
* Many option ROMs use the hard coded interrupt entry points in the |
||||
* system bios. So install them at the known locations. |
||||
*/ |
||||
|
||||
/* int42 is the relocated int10 */ |
||||
write_idt_stub((void *)0xff065, 0x42); |
||||
/* BIOS Int 11 Handler F000:F84D */ |
||||
write_idt_stub((void *)0xff84d, 0x11); |
||||
/* BIOS Int 12 Handler F000:F841 */ |
||||
write_idt_stub((void *)0xff841, 0x12); |
||||
/* BIOS Int 13 Handler F000:EC59 */ |
||||
write_idt_stub((void *)0xfec59, 0x13); |
||||
/* BIOS Int 14 Handler F000:E739 */ |
||||
write_idt_stub((void *)0xfe739, 0x14); |
||||
/* BIOS Int 15 Handler F000:F859 */ |
||||
write_idt_stub((void *)0xff859, 0x15); |
||||
/* BIOS Int 16 Handler F000:E82E */ |
||||
write_idt_stub((void *)0xfe82e, 0x16); |
||||
/* BIOS Int 17 Handler F000:EFD2 */ |
||||
write_idt_stub((void *)0xfefd2, 0x17); |
||||
/* ROM BIOS Int 1A Handler F000:FE6E */ |
||||
write_idt_stub((void *)0xffe6e, 0x1a); |
||||
} |
||||
|
||||
static u8 vbe_get_mode_info(struct vbe_mode_info *mi) |
||||
{ |
||||
u16 buffer_seg; |
||||
u16 buffer_adr; |
||||
char *buffer; |
||||
|
||||
debug("VBE: Getting information about VESA mode %04x\n", |
||||
mi->video_mode); |
||||
buffer = PTR_TO_REAL_MODE(asm_realmode_buffer); |
||||
buffer_seg = (((unsigned long)buffer) >> 4) & 0xff00; |
||||
buffer_adr = ((unsigned long)buffer) & 0xffff; |
||||
|
||||
realmode_interrupt(0x10, VESA_GET_MODE_INFO, 0x0000, mi->video_mode, |
||||
0x0000, buffer_seg, buffer_adr); |
||||
memcpy(mi->mode_info_block, buffer, sizeof(struct vbe_mode_info)); |
||||
mi->valid = true; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static u8 vbe_set_mode(struct vbe_mode_info *mi) |
||||
{ |
||||
debug("VBE: Setting VESA mode %#04x\n", mi->video_mode); |
||||
/* request linear framebuffer mode */ |
||||
mi->video_mode |= (1 << 14); |
||||
/* request clearing of framebuffer */ |
||||
mi->video_mode &= ~(1 << 15); |
||||
realmode_interrupt(0x10, VESA_SET_MODE, mi->video_mode, |
||||
0x0000, 0x0000, 0x0000, 0x0000); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void vbe_set_graphics(int vesa_mode, struct vbe_mode_info *mode_info) |
||||
{ |
||||
unsigned char *framebuffer; |
||||
|
||||
mode_info->video_mode = (1 << 14) | vesa_mode; |
||||
vbe_get_mode_info(mode_info); |
||||
|
||||
framebuffer = (unsigned char *)mode_info->vesa.phys_base_ptr; |
||||
debug("VBE: resolution: %dx%d@%d\n", |
||||
le16_to_cpu(mode_info->vesa.x_resolution), |
||||
le16_to_cpu(mode_info->vesa.y_resolution), |
||||
mode_info->vesa.bits_per_pixel); |
||||
debug("VBE: framebuffer: %p\n", framebuffer); |
||||
if (!framebuffer) { |
||||
debug("VBE: Mode does not support linear framebuffer\n"); |
||||
return; |
||||
} |
||||
|
||||
vbe_set_mode(mode_info); |
||||
} |
||||
|
||||
void bios_run_on_x86(pci_dev_t pcidev, unsigned long addr, int vesa_mode, |
||||
struct vbe_mode_info *mode_info) |
||||
{ |
||||
u32 num_dev; |
||||
|
||||
num_dev = PCI_BUS(pcidev) << 8 | PCI_DEV(pcidev) << 3 | |
||||
PCI_FUNC(pcidev); |
||||
|
||||
/* Needed to avoid exceptions in some ROMs */ |
||||
interrupt_init(); |
||||
|
||||
/* Set up some legacy information in the F segment */ |
||||
setup_rombios(); |
||||
|
||||
/* Set up C interrupt handlers */ |
||||
setup_interrupt_handlers(); |
||||
|
||||
/* Set up real-mode IDT */ |
||||
setup_realmode_idt(); |
||||
|
||||
/* Make sure the code is placed. */ |
||||
setup_realmode_code(); |
||||
|
||||
disable_caches(); |
||||
debug("Calling Option ROM at %lx, pci device %#x...", addr, num_dev); |
||||
|
||||
/* Option ROM entry point is at OPROM start + 3 */ |
||||
realmode_call(addr + 0x0003, num_dev, 0xffff, 0x0000, 0xffff, 0x0, |
||||
0x0); |
||||
debug("done\n"); |
||||
|
||||
if (vesa_mode != -1) |
||||
vbe_set_graphics(vesa_mode, mode_info); |
||||
} |
||||
|
||||
asmlinkage int interrupt_handler(u32 intnumber, u32 gsfs, u32 dses, |
||||
u32 edi, u32 esi, u32 ebp, u32 esp, |
||||
u32 ebx, u32 edx, u32 ecx, u32 eax, |
||||
u32 cs_ip, u16 stackflags) |
||||
{ |
||||
u32 ip; |
||||
u32 cs; |
||||
u32 flags; |
||||
int ret = 0; |
||||
|
||||
ip = cs_ip & 0xffff; |
||||
cs = cs_ip >> 16; |
||||
flags = stackflags; |
||||
|
||||
#ifdef CONFIG_REALMODE_DEBUG |
||||
debug("oprom: INT# 0x%x\n", intnumber); |
||||
debug("oprom: eax: %08x ebx: %08x ecx: %08x edx: %08x\n", |
||||
eax, ebx, ecx, edx); |
||||
debug("oprom: ebp: %08x esp: %08x edi: %08x esi: %08x\n", |
||||
ebp, esp, edi, esi); |
||||
debug("oprom: ip: %04x cs: %04x flags: %08x\n", |
||||
ip, cs, flags); |
||||
debug("oprom: stackflags = %04x\n", stackflags); |
||||
#endif |
||||
|
||||
/*
|
||||
* Fetch arguments from the stack and put them to a place |
||||
* suitable for the interrupt handlers |
||||
*/ |
||||
M.x86.R_EAX = eax; |
||||
M.x86.R_ECX = ecx; |
||||
M.x86.R_EDX = edx; |
||||
M.x86.R_EBX = ebx; |
||||
M.x86.R_ESP = esp; |
||||
M.x86.R_EBP = ebp; |
||||
M.x86.R_ESI = esi; |
||||
M.x86.R_EDI = edi; |
||||
M.x86.intno = intnumber; |
||||
M.x86.R_EIP = ip; |
||||
M.x86.R_CS = cs; |
||||
M.x86.R_EFLG = flags; |
||||
|
||||
/* Call the interrupt handler for this interrupt number */ |
||||
ret = int_handler[intnumber](); |
||||
|
||||
/*
|
||||
* This code is quite strange... |
||||
* |
||||
* Put registers back on the stack. The assembler code will pop them |
||||
* later. We force (volatile!) changing the values of the parameters |
||||
* of this function. We know that they stay alive on the stack after |
||||
* we leave this function. |
||||
*/ |
||||
*(volatile u32 *)&eax = M.x86.R_EAX; |
||||
*(volatile u32 *)&ecx = M.x86.R_ECX; |
||||
*(volatile u32 *)&edx = M.x86.R_EDX; |
||||
*(volatile u32 *)&ebx = M.x86.R_EBX; |
||||
*(volatile u32 *)&esi = M.x86.R_ESI; |
||||
*(volatile u32 *)&edi = M.x86.R_EDI; |
||||
flags = M.x86.R_EFLG; |
||||
|
||||
/* Pass success or error back to our caller via the CARRY flag */ |
||||
if (ret) { |
||||
flags &= ~1; /* no error: clear carry */ |
||||
} else { |
||||
debug("int%02x call returned error\n", intnumber); |
||||
flags |= 1; /* error: set carry */ |
||||
} |
||||
*(volatile u16 *)&stackflags = flags; |
||||
|
||||
return ret; |
||||
} |
@ -0,0 +1,98 @@ |
||||
/*
|
||||
* From Coreboot file device/oprom/realmode/x86.h |
||||
* |
||||
* Copyright (C) 2007 Advanced Micro Devices, Inc. |
||||
* Copyright (C) 2009-2010 coresystems GmbH |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#ifndef _X86_LIB_BIOS_H |
||||
#define _X86_LIB_BIOS_H |
||||
|
||||
#define REALMODE_BASE 0x600 |
||||
|
||||
#ifdef __ASSEMBLY__ |
||||
|
||||
#define PTR_TO_REAL_MODE(x) (x - asm_realmode_code + REALMODE_BASE) |
||||
|
||||
#else |
||||
|
||||
/* Convert a symbol address to our real mode area */ |
||||
#define PTR_TO_REAL_MODE(sym)\ |
||||
(void *)(REALMODE_BASE + ((char *)&(sym) - (char *)&asm_realmode_code)) |
||||
|
||||
/*
|
||||
* The following symbols cannot be used directly. They need to be fixed up |
||||
* to point to the correct address location after the code has been copied |
||||
* to REALMODE_BASE. Absolute symbols are not used because those symbols are |
||||
* relocated by U-Boot. |
||||
*/ |
||||
extern unsigned char asm_realmode_call, __realmode_interrupt; |
||||
extern unsigned char asm_realmode_buffer; |
||||
|
||||
#define DOWNTO8(A) \ |
||||
union { \
|
||||
struct { \
|
||||
union { \
|
||||
struct { \
|
||||
uint8_t A##l; \
|
||||
uint8_t A##h; \
|
||||
} __packed; \
|
||||
uint16_t A##x; \
|
||||
} __packed; \
|
||||
uint16_t h##A##x; \
|
||||
} __packed; \
|
||||
uint32_t e##A##x; \
|
||||
} __packed; |
||||
|
||||
#define DOWNTO16(A) \ |
||||
union { \
|
||||
struct { \
|
||||
uint16_t A; \
|
||||
uint16_t h##A; \
|
||||
} __packed; \
|
||||
uint32_t e##A; \
|
||||
} __packed; |
||||
|
||||
struct eregs { |
||||
DOWNTO8(a); |
||||
DOWNTO8(c); |
||||
DOWNTO8(d); |
||||
DOWNTO8(b); |
||||
DOWNTO16(sp); |
||||
DOWNTO16(bp); |
||||
DOWNTO16(si); |
||||
DOWNTO16(di); |
||||
uint32_t vector; |
||||
uint32_t error_code; |
||||
uint32_t eip; |
||||
uint32_t cs; |
||||
uint32_t eflags; |
||||
}; |
||||
|
||||
struct realmode_idt { |
||||
u16 offset, cs; |
||||
}; |
||||
|
||||
void x86_exception(struct eregs *info); |
||||
|
||||
/* From x86_asm.S */ |
||||
extern unsigned char __idt_handler; |
||||
extern unsigned int __idt_handler_size; |
||||
extern unsigned char asm_realmode_code; |
||||
extern unsigned int asm_realmode_code_size; |
||||
|
||||
asmlinkage void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, |
||||
u32 esi, u32 edi); |
||||
|
||||
asmlinkage void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, |
||||
u32 edx, u32 esi, u32 edi); |
||||
|
||||
int int10_handler(void); |
||||
int int12_handler(void); |
||||
int int16_handler(void); |
||||
int int1a_handler(void); |
||||
#endif /*__ASSEMBLY__ */ |
||||
|
||||
#endif |
@ -0,0 +1,281 @@ |
||||
/* |
||||
* From coreboot x86_asm.S, cleaned up substantially |
||||
* |
||||
* Copyright (C) 2009-2010 coresystems GmbH |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#include <asm/processor.h> |
||||
#include <asm/processor-flags.h> |
||||
#include "bios.h" |
||||
|
||||
#define SEG(segment) $segment * X86_GDT_ENTRY_SIZE |
||||
|
||||
/* |
||||
* This is the interrupt handler stub code. It gets copied to the IDT and |
||||
* to some fixed addresses in the F segment. Before the code can used, |
||||
* it gets patched up by the C function copying it: byte 3 (the $0 in |
||||
* movb $0, %al) is overwritten with the interrupt numbers. |
||||
*/ |
||||
|
||||
.code16 |
||||
.globl __idt_handler
|
||||
__idt_handler: |
||||
pushal |
||||
movb $0, %al /* This instruction gets modified */ |
||||
ljmp $0, $__interrupt_handler_16bit |
||||
.globl __idt_handler_size
|
||||
__idt_handler_size: |
||||
.long . - __idt_handler |
||||
|
||||
.macro setup_registers
|
||||
/* initial register values */ |
||||
movl 44(%ebp), %eax |
||||
movl %eax, __registers + 0 /* eax */ |
||||
movl 48(%ebp), %eax |
||||
movl %eax, __registers + 4 /* ebx */ |
||||
movl 52(%ebp), %eax |
||||
movl %eax, __registers + 8 /* ecx */ |
||||
movl 56(%ebp), %eax |
||||
movl %eax, __registers + 12 /* edx */ |
||||
movl 60(%ebp), %eax |
||||
movl %eax, __registers + 16 /* esi */ |
||||
movl 64(%ebp), %eax |
||||
movl %eax, __registers + 20 /* edi */ |
||||
.endm |
||||
|
||||
.macro enter_real_mode
|
||||
/* Activate the right segment descriptor real mode. */ |
||||
ljmp SEG(X86_GDT_ENTRY_16BIT_CS), $PTR_TO_REAL_MODE(1f) |
||||
1: |
||||
.code16 |
||||
/* |
||||
* Load the segment registers with properly configured segment |
||||
* descriptors. They will retain these configurations (limits, |
||||
* writability, etc.) once protected mode is turned off. |
||||
*/ |
||||
mov SEG(X86_GDT_ENTRY_16BIT_DS), %ax |
||||
mov %ax, %ds |
||||
mov %ax, %es |
||||
mov %ax, %fs |
||||
mov %ax, %gs |
||||
mov %ax, %ss |
||||
|
||||
/* Turn off protection */ |
||||
movl %cr0, %eax |
||||
andl $~X86_CR0_PE, %eax |
||||
movl %eax, %cr0 |
||||
|
||||
/* Now really going into real mode */ |
||||
ljmp $0, $PTR_TO_REAL_MODE(1f) |
||||
1: |
||||
/* |
||||
* Set up a stack: Put the stack at the end of page zero. That way |
||||
* we can easily share it between real and protected, since the |
||||
* 16-bit ESP at segment 0 will work for any case. |
||||
*/ |
||||
mov $0x0, %ax |
||||
mov %ax, %ss |
||||
|
||||
/* Load 16 bit IDT */ |
||||
xor %ax, %ax |
||||
mov %ax, %ds |
||||
lidt __realmode_idt |
||||
|
||||
.endm |
||||
|
||||
.macro prepare_for_irom
|
||||
movl $0x1000, %eax |
||||
movl %eax, %esp |
||||
|
||||
/* Initialise registers for option rom lcall */ |
||||
movl __registers + 0, %eax |
||||
movl __registers + 4, %ebx |
||||
movl __registers + 8, %ecx |
||||
movl __registers + 12, %edx |
||||
movl __registers + 16, %esi |
||||
movl __registers + 20, %edi |
||||
|
||||
/* Set all segments to 0x0000, ds to 0x0040 */ |
||||
push %ax |
||||
xor %ax, %ax |
||||
mov %ax, %es |
||||
mov %ax, %fs |
||||
mov %ax, %gs |
||||
mov SEG(X86_GDT_ENTRY_16BIT_FLAT_DS), %ax |
||||
mov %ax, %ds |
||||
pop %ax |
||||
|
||||
.endm |
||||
|
||||
.macro enter_protected_mode
|
||||
/* Go back to protected mode */ |
||||
movl %cr0, %eax |
||||
orl $X86_CR0_PE, %eax |
||||
movl %eax, %cr0 |
||||
|
||||
/* Now that we are in protected mode jump to a 32 bit code segment */ |
||||
data32 ljmp SEG(X86_GDT_ENTRY_32BIT_CS), $PTR_TO_REAL_MODE(1f) |
||||
1: |
||||
.code32 |
||||
mov SEG(X86_GDT_ENTRY_32BIT_DS), %ax |
||||
mov %ax, %ds |
||||
mov %ax, %es |
||||
mov %ax, %gs |
||||
mov %ax, %ss |
||||
mov SEG(X86_GDT_ENTRY_32BIT_FS), %ax |
||||
mov %ax, %fs |
||||
|
||||
/* restore proper idt */ |
||||
lidt idt_ptr |
||||
.endm |
||||
|
||||
/* |
||||
* In order to be independent of U-Boot's position in RAM we relocate a part |
||||
* of the code to the first megabyte of RAM, so the CPU can use it in |
||||
* real-mode. This code lives at asm_realmode_code. |
||||
*/ |
||||
.globl asm_realmode_code
|
||||
asm_realmode_code: |
||||
|
||||
/* Realmode IDT pointer structure. */ |
||||
__realmode_idt = PTR_TO_REAL_MODE(.) |
||||
.word 1023 /* 16 bit limit */ |
||||
.long 0 /* 24 bit base */ |
||||
.word 0
|
||||
|
||||
/* Preserve old stack */ |
||||
__stack = PTR_TO_REAL_MODE(.) |
||||
.long 0
|
||||
|
||||
/* Register store for realmode_call and realmode_interrupt */ |
||||
__registers = PTR_TO_REAL_MODE(.) |
||||
.long 0 /* 0 - EAX */ |
||||
.long 0 /* 4 - EBX */ |
||||
.long 0 /* 8 - ECX */ |
||||
.long 0 /* 12 - EDX */ |
||||
.long 0 /* 16 - ESI */ |
||||
.long 0 /* 20 - EDI */ |
||||
|
||||
/* 256 byte buffer, used by int10 */ |
||||
.globl asm_realmode_buffer
|
||||
asm_realmode_buffer: |
||||
.skip 256
|
||||
|
||||
.code32 |
||||
.globl asm_realmode_call
|
||||
asm_realmode_call: |
||||
/* save all registers to the stack */ |
||||
pusha |
||||
pushf |
||||
movl %esp, __stack |
||||
movl %esp, %ebp |
||||
|
||||
/* |
||||
* This function is called with regparm=0 and we have to skip the |
||||
* 36 bytes from pushf+pusha. Hence start at 40. |
||||
* Set up our call instruction. |
||||
*/ |
||||
movl 40(%ebp), %eax |
||||
mov %ax, __lcall_instr + 1 |
||||
andl $0xffff0000, %eax |
||||
shrl $4, %eax |
||||
mov %ax, __lcall_instr + 3 |
||||
|
||||
wbinvd |
||||
|
||||
setup_registers |
||||
enter_real_mode |
||||
prepare_for_irom |
||||
|
||||
__lcall_instr = PTR_TO_REAL_MODE(.) |
||||
.byte 0x9a
|
||||
.word 0x0000, 0x0000 |
||||
|
||||
enter_protected_mode |
||||
|
||||
/* restore stack pointer, eflags and register values and exit */ |
||||
movl __stack, %esp |
||||
popf |
||||
popa |
||||
ret |
||||
|
||||
.globl __realmode_interrupt
|
||||
__realmode_interrupt: |
||||
/* save all registers to the stack and store the stack pointer */ |
||||
pusha |
||||
pushf |
||||
movl %esp, __stack |
||||
movl %esp, %ebp |
||||
|
||||
/* |
||||
* This function is called with regparm=0 and we have to skip the |
||||
* 36 bytes from pushf+pusha. Hence start at 40. |
||||
* Prepare interrupt calling code. |
||||
*/ |
||||
movl 40(%ebp), %eax |
||||
movb %al, __intXX_instr + 1 /* intno */ |
||||
|
||||
setup_registers |
||||
enter_real_mode |
||||
prepare_for_irom |
||||
|
||||
__intXX_instr = PTR_TO_REAL_MODE(.) |
||||
.byte 0xcd, 0x00 /* This becomes intXX */ |
||||
|
||||
enter_protected_mode |
||||
|
||||
/* restore stack pointer, eflags and register values and exit */ |
||||
movl __stack, %esp |
||||
popf |
||||
popa |
||||
ret |
||||
|
||||
/* |
||||
* This is the 16-bit interrupt entry point called by the IDT stub code. |
||||
* |
||||
* Before this code code is called, %eax is pushed to the stack, and the |
||||
* interrupt number is loaded into %al. On return this function cleans up |
||||
* for its caller. |
||||
*/ |
||||
.code16 |
||||
__interrupt_handler_16bit = PTR_TO_REAL_MODE(.) |
||||
push %ds |
||||
push %es |
||||
push %fs |
||||
push %gs |
||||
|
||||
/* Clear DF to not break ABI assumptions */ |
||||
cld |
||||
|
||||
/* |
||||
* Clean up the interrupt number. We could do this in the stub, but |
||||
* it would cost two more bytes per stub entry. |
||||
*/ |
||||
andl $0xff, %eax |
||||
pushl %eax /* ... and make it the first parameter */ |
||||
|
||||
enter_protected_mode |
||||
|
||||
/* Call the C interrupt handler */ |
||||
movl $interrupt_handler, %eax |
||||
call *%eax |
||||
|
||||
enter_real_mode |
||||
|
||||
/* |
||||
* Restore all registers, including those manipulated by the C |
||||
* handler |
||||
*/ |
||||
popl %eax |
||||
pop %gs |
||||
pop %fs |
||||
pop %es |
||||
pop %ds |
||||
popal |
||||
iret |
||||
|
||||
.globl asm_realmode_code_size
|
||||
asm_realmode_code_size: |
||||
.long . - asm_realmode_code |
@ -0,0 +1,217 @@ |
||||
/*
|
||||
* From Coreboot |
||||
* |
||||
* Copyright (C) 2001 Ronald G. Minnich |
||||
* Copyright (C) 2005 Nick.Barker9@btinternet.com |
||||
* Copyright (C) 2007-2009 coresystems GmbH |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/pci.h> |
||||
#include "bios_emul.h" |
||||
|
||||
/* errors go in AH. Just set these up so that word assigns will work */ |
||||
enum { |
||||
PCIBIOS_SUCCESSFUL = 0x0000, |
||||
PCIBIOS_UNSUPPORTED = 0x8100, |
||||
PCIBIOS_BADVENDOR = 0x8300, |
||||
PCIBIOS_NODEV = 0x8600, |
||||
PCIBIOS_BADREG = 0x8700 |
||||
}; |
||||
|
||||
int int10_handler(void) |
||||
{ |
||||
static u8 cursor_row, cursor_col; |
||||
int res = 0; |
||||
|
||||
switch ((M.x86.R_EAX & 0xff00) >> 8) { |
||||
case 0x01: /* Set cursor shape */ |
||||
res = 1; |
||||
break; |
||||
case 0x02: /* Set cursor position */ |
||||
if (cursor_row != ((M.x86.R_EDX >> 8) & 0xff) || |
||||
cursor_col >= (M.x86.R_EDX & 0xff)) { |
||||
debug("\n"); |
||||
} |
||||
cursor_row = (M.x86.R_EDX >> 8) & 0xff; |
||||
cursor_col = M.x86.R_EDX & 0xff; |
||||
res = 1; |
||||
break; |
||||
case 0x03: /* Get cursor position */ |
||||
M.x86.R_EAX &= 0x00ff; |
||||
M.x86.R_ECX = 0x0607; |
||||
M.x86.R_EDX = (cursor_row << 8) | cursor_col; |
||||
res = 1; |
||||
break; |
||||
case 0x06: /* Scroll up */ |
||||
debug("\n"); |
||||
res = 1; |
||||
break; |
||||
case 0x08: /* Get Character and Mode at Cursor Position */ |
||||
M.x86.R_EAX = 0x0f00 | 'A'; /* White on black 'A' */ |
||||
res = 1; |
||||
break; |
||||
case 0x09: /* Write Character and attribute */ |
||||
case 0x0e: /* Write Character */ |
||||
debug("%c", M.x86.R_EAX & 0xff); |
||||
res = 1; |
||||
break; |
||||
case 0x0f: /* Get video mode */ |
||||
M.x86.R_EAX = 0x5002; /*80 x 25 */ |
||||
M.x86.R_EBX &= 0x00ff; |
||||
res = 1; |
||||
break; |
||||
default: |
||||
printf("Unknown INT10 function %04x\n", M.x86.R_EAX & 0xffff); |
||||
break; |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
int int12_handler(void) |
||||
{ |
||||
M.x86.R_EAX = 64 * 1024; |
||||
return 1; |
||||
} |
||||
|
||||
int int16_handler(void) |
||||
{ |
||||
int res = 0; |
||||
|
||||
switch ((M.x86.R_EAX & 0xff00) >> 8) { |
||||
case 0x00: /* Check for Keystroke */ |
||||
M.x86.R_EAX = 0x6120; /* Space Bar, Space */ |
||||
res = 1; |
||||
break; |
||||
case 0x01: /* Check for Keystroke */ |
||||
M.x86.R_EFLG |= 1 << 6; /* Zero Flag set (no key available) */ |
||||
res = 1; |
||||
break; |
||||
default: |
||||
printf("Unknown INT16 function %04x\n", M.x86.R_EAX & 0xffff); |
||||
|
||||
break; |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
#define PCI_CONFIG_SPACE_TYPE1 (1 << 0) |
||||
#define PCI_SPECIAL_CYCLE_TYPE1 (1 << 4) |
||||
|
||||
int int1a_handler(void) |
||||
{ |
||||
unsigned short func = (unsigned short)M.x86.R_EAX; |
||||
int retval = 1; |
||||
unsigned short devid, vendorid, devfn; |
||||
/* Use short to get rid of gabage in upper half of 32-bit register */ |
||||
short devindex; |
||||
unsigned char bus; |
||||
pci_dev_t dev; |
||||
u32 dword; |
||||
u16 word; |
||||
u8 byte, reg; |
||||
|
||||
switch (func) { |
||||
case 0xb101: /* PCIBIOS Check */ |
||||
M.x86.R_EDX = 0x20494350; /* ' ICP' */ |
||||
M.x86.R_EAX &= 0xffff0000; /* Clear AH / AL */ |
||||
M.x86.R_EAX |= PCI_CONFIG_SPACE_TYPE1 | |
||||
PCI_SPECIAL_CYCLE_TYPE1; |
||||
/*
|
||||
* last bus in the system. Hard code to 255 for now. |
||||
* dev_enumerate() does not seem to tell us (publically) |
||||
*/ |
||||
M.x86.R_ECX = 0xff; |
||||
M.x86.R_EDI = 0x00000000; /* protected mode entry */ |
||||
retval = 1; |
||||
break; |
||||
case 0xb102: /* Find Device */ |
||||
devid = M.x86.R_ECX; |
||||
vendorid = M.x86.R_EDX; |
||||
devindex = M.x86.R_ESI; |
||||
dev = pci_find_device(vendorid, devid, devindex); |
||||
if (dev != -1) { |
||||
unsigned short busdevfn; |
||||
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ |
||||
M.x86.R_EAX |= PCIBIOS_SUCCESSFUL; |
||||
/*
|
||||
* busnum is an unsigned char; |
||||
* devfn is an int, so we mask it off. |
||||
*/ |
||||
busdevfn = (PCI_BUS(dev) << 8) | PCI_DEV(dev) << 3 | |
||||
PCI_FUNC(dev); |
||||
debug("0x%x: return 0x%x\n", func, busdevfn); |
||||
M.x86.R_EBX = busdevfn; |
||||
retval = 1; |
||||
} else { |
||||
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ |
||||
M.x86.R_EAX |= PCIBIOS_NODEV; |
||||
retval = 0; |
||||
} |
||||
break; |
||||
case 0xb10a: /* Read Config Dword */ |
||||
case 0xb109: /* Read Config Word */ |
||||
case 0xb108: /* Read Config Byte */ |
||||
case 0xb10d: /* Write Config Dword */ |
||||
case 0xb10c: /* Write Config Word */ |
||||
case 0xb10b: /* Write Config Byte */ |
||||
devfn = M.x86.R_EBX & 0xff; |
||||
bus = M.x86.R_EBX >> 8; |
||||
reg = M.x86.R_EDI; |
||||
dev = PCI_BDF(bus, devfn >> 3, devfn & 7); |
||||
if (!dev) { |
||||
debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, |
||||
bus, devfn); |
||||
/* Or are we supposed to return PCIBIOS_NODEV? */ |
||||
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ |
||||
M.x86.R_EAX |= PCIBIOS_BADREG; |
||||
retval = 0; |
||||
return retval; |
||||
} |
||||
switch (func) { |
||||
case 0xb108: /* Read Config Byte */ |
||||
byte = pci_read_config8(dev, reg); |
||||
M.x86.R_ECX = byte; |
||||
break; |
||||
case 0xb109: /* Read Config Word */ |
||||
word = pci_read_config16(dev, reg); |
||||
M.x86.R_ECX = word; |
||||
break; |
||||
case 0xb10a: /* Read Config Dword */ |
||||
dword = pci_read_config32(dev, reg); |
||||
M.x86.R_ECX = dword; |
||||
break; |
||||
case 0xb10b: /* Write Config Byte */ |
||||
byte = M.x86.R_ECX; |
||||
pci_write_config8(dev, reg, byte); |
||||
break; |
||||
case 0xb10c: /* Write Config Word */ |
||||
word = M.x86.R_ECX; |
||||
pci_write_config16(dev, reg, word); |
||||
break; |
||||
case 0xb10d: /* Write Config Dword */ |
||||
dword = M.x86.R_ECX; |
||||
pci_write_config32(dev, reg, dword); |
||||
break; |
||||
} |
||||
|
||||
#ifdef CONFIG_REALMODE_DEBUG |
||||
debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", func, |
||||
bus, devfn, reg, M.x86.R_ECX); |
||||
#endif |
||||
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ |
||||
M.x86.R_EAX |= PCIBIOS_SUCCESSFUL; |
||||
retval = 1; |
||||
break; |
||||
default: |
||||
printf("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func); |
||||
M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ |
||||
M.x86.R_EAX |= PCIBIOS_UNSUPPORTED; |
||||
retval = 0; |
||||
break; |
||||
} |
||||
|
||||
return retval; |
||||
} |
@ -0,0 +1,26 @@ |
||||
Intel Pantherpoint SATA Device Binding |
||||
====================================== |
||||
|
||||
The device tree node which describes the operation of the Intel Pantherpoint |
||||
SATA device is as follows: |
||||
|
||||
Required properties : |
||||
- compatible = "intel,pantherpoint-ahci" |
||||
- intel,sata-mode : string, one of: |
||||
"ahci" : Use AHCI mode (default) |
||||
"combined" : Use combined IDE + legacy mode |
||||
"plain-ide" : Use plain IDE mode |
||||
- intel,sata-port-map : Which SATA ports are enabled, bit 0=enable first port, |
||||
bit 1=enable second port, etc. |
||||
- intel,sata-port0-gen3-tx : Value for the IOBP_SP0G3IR register |
||||
- intel,sata-port1-gen3-tx : Value for the IOBP_SP1G3IR register |
||||
|
||||
Example |
||||
------- |
||||
|
||||
sata { |
||||
compatible = "intel,pantherpoint-ahci"; |
||||
intel,sata-mode = "ahci"; |
||||
intel,sata-port-map = <1>; |
||||
intel,sata-port0-gen3-tx = <0x00880a7f>; |
||||
}; |
@ -0,0 +1,40 @@ |
||||
Intel GMA Bindings |
||||
================== |
||||
|
||||
This is the Intel Graphics Media Accelerator. This binding supports selection |
||||
of display parameters only. |
||||
|
||||
|
||||
Required properties: |
||||
- compatible : "intel,gma"; |
||||
|
||||
Optional properties: |
||||
- intel,dp-hotplug : values for digital port hotplug, one cell per value for |
||||
ports B, C and D |
||||
- intel,panel-port-select : output port to use: 0=LVDS 1=DP_B 2=DP_C 3=DP_D |
||||
- intel,panel-power-cycle-delay : T4 time sequence (6 = 500ms) |
||||
|
||||
The following delays are in units of 0.1ms: |
||||
- intel,panel-power-up-delay : T1+T2 time sequence |
||||
- intel,panel-power-down-delay : T3 time sequence |
||||
- intel,panel-power-backlight-on-delay : T5 time sequence |
||||
- intel,panel-power-backlight-off-delay : Tx time sequence |
||||
|
||||
- intel,cpu-backlight : Value for CPU Backlight PWM |
||||
- intel,pch-backlight : Value for PCH Backlight PWM |
||||
|
||||
Example |
||||
------- |
||||
|
||||
gma { |
||||
compatible = "intel,gma"; |
||||
intel,dp_hotplug = <0 0 0x06>; |
||||
intel,panel-port-select = <1>; |
||||
intel,panel-power-cycle-delay = <6>; |
||||
intel,panel-power-up-delay = <2000>; |
||||
intel,panel-power-down-delay = <500>; |
||||
intel,panel-power-backlight-on-delay = <2000>; |
||||
intel,panel-power-backlight-off-delay = <2000>; |
||||
intel,cpu-backlight = <0x00000200>; |
||||
intel,pch-backlight = <0x04000000>; |
||||
}; |
@ -0,0 +1,278 @@ |
||||
/*
|
||||
* Copyright (C) 2014 Google, Inc |
||||
* |
||||
* From coreboot, originally based on the Linux kernel (drivers/pci/pci.c). |
||||
* |
||||
* Modifications are: |
||||
* Copyright (C) 2003-2004 Linux Networx |
||||
* (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx) |
||||
* Copyright (C) 2003-2006 Ronald G. Minnich <rminnich@gmail.com> |
||||
* Copyright (C) 2004-2005 Li-Ta Lo <ollie@lanl.gov> |
||||
* Copyright (C) 2005-2006 Tyan |
||||
* (Written by Yinghai Lu <yhlu@tyan.com> for Tyan) |
||||
* Copyright (C) 2005-2009 coresystems GmbH |
||||
* (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH) |
||||
* |
||||
* PCI Bus Services, see include/linux/pci.h for further explanation. |
||||
* |
||||
* Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, |
||||
* David Mosberger-Tang |
||||
* |
||||
* Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz> |
||||
|
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <bios_emul.h> |
||||
#include <errno.h> |
||||
#include <malloc.h> |
||||
#include <pci.h> |
||||
#include <pci_rom.h> |
||||
#include <vbe.h> |
||||
#include <video_fb.h> |
||||
|
||||
#ifdef CONFIG_HAVE_ACPI_RESUME |
||||
#include <asm/acpi.h> |
||||
#endif |
||||
|
||||
__weak bool board_should_run_oprom(pci_dev_t dev) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
static bool should_load_oprom(pci_dev_t dev) |
||||
{ |
||||
#ifdef CONFIG_HAVE_ACPI_RESUME |
||||
if (acpi_get_slp_type() == 3) |
||||
return false; |
||||
#endif |
||||
if (IS_ENABLED(CONFIG_ALWAYS_LOAD_OPROM)) |
||||
return 1; |
||||
if (board_should_run_oprom(dev)) |
||||
return 1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
__weak uint32_t board_map_oprom_vendev(uint32_t vendev) |
||||
{ |
||||
return vendev; |
||||
} |
||||
|
||||
static int pci_rom_probe(pci_dev_t dev, uint class, |
||||
struct pci_rom_header **hdrp) |
||||
{ |
||||
struct pci_rom_header *rom_header; |
||||
struct pci_rom_data *rom_data; |
||||
u16 vendor, device; |
||||
u32 vendev; |
||||
u32 mapped_vendev; |
||||
u32 rom_address; |
||||
|
||||
pci_read_config_word(dev, PCI_VENDOR_ID, &vendor); |
||||
pci_read_config_word(dev, PCI_DEVICE_ID, &device); |
||||
vendev = vendor << 16 | device; |
||||
mapped_vendev = board_map_oprom_vendev(vendev); |
||||
if (vendev != mapped_vendev) |
||||
debug("Device ID mapped to %#08x\n", mapped_vendev); |
||||
|
||||
#ifdef CONFIG_X86_OPTION_ROM_ADDR |
||||
rom_address = CONFIG_X86_OPTION_ROM_ADDR; |
||||
#else |
||||
pci_write_config_dword(dev, PCI_ROM_ADDRESS, (u32)PCI_ROM_ADDRESS_MASK); |
||||
pci_read_config_dword(dev, PCI_ROM_ADDRESS, &rom_address); |
||||
if (rom_address == 0x00000000 || rom_address == 0xffffffff) { |
||||
debug("%s: rom_address=%x\n", __func__, rom_address); |
||||
return -ENOENT; |
||||
} |
||||
|
||||
/* Enable expansion ROM address decoding. */ |
||||
pci_write_config_dword(dev, PCI_ROM_ADDRESS, |
||||
rom_address | PCI_ROM_ADDRESS_ENABLE); |
||||
#endif |
||||
debug("Option ROM address %x\n", rom_address); |
||||
rom_header = (struct pci_rom_header *)rom_address; |
||||
|
||||
debug("PCI expansion ROM, signature %#04x, INIT size %#04x, data ptr %#04x\n", |
||||
le32_to_cpu(rom_header->signature), |
||||
rom_header->size * 512, le32_to_cpu(rom_header->data)); |
||||
|
||||
if (le32_to_cpu(rom_header->signature) != PCI_ROM_HDR) { |
||||
printf("Incorrect expansion ROM header signature %04x\n", |
||||
le32_to_cpu(rom_header->signature)); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
rom_data = (((void *)rom_header) + le32_to_cpu(rom_header->data)); |
||||
|
||||
debug("PCI ROM image, vendor ID %04x, device ID %04x,\n", |
||||
rom_data->vendor, rom_data->device); |
||||
|
||||
/* If the device id is mapped, a mismatch is expected */ |
||||
if ((vendor != rom_data->vendor || device != rom_data->device) && |
||||
(vendev == mapped_vendev)) { |
||||
printf("ID mismatch: vendor ID %04x, device ID %04x\n", |
||||
rom_data->vendor, rom_data->device); |
||||
return -EPERM; |
||||
} |
||||
|
||||
debug("PCI ROM image, Class Code %04x%02x, Code Type %02x\n", |
||||
rom_data->class_hi, rom_data->class_lo, rom_data->type); |
||||
|
||||
if (class != ((rom_data->class_hi << 8) | rom_data->class_lo)) { |
||||
debug("Class Code mismatch ROM %08x, dev %08x\n", |
||||
(rom_data->class_hi << 8) | rom_data->class_lo, |
||||
class); |
||||
} |
||||
*hdrp = rom_header; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int pci_rom_load(uint16_t class, struct pci_rom_header *rom_header, |
||||
struct pci_rom_header **ram_headerp) |
||||
{ |
||||
struct pci_rom_data *rom_data; |
||||
unsigned int rom_size; |
||||
unsigned int image_size = 0; |
||||
void *target; |
||||
|
||||
do { |
||||
/* Get next image, until we see an x86 version */ |
||||
rom_header = (struct pci_rom_header *)((void *)rom_header + |
||||
image_size); |
||||
|
||||
rom_data = (struct pci_rom_data *)((void *)rom_header + |
||||
le32_to_cpu(rom_header->data)); |
||||
|
||||
image_size = le32_to_cpu(rom_data->ilen) * 512; |
||||
} while ((rom_data->type != 0) && (rom_data->indicator != 0)); |
||||
|
||||
if (rom_data->type != 0) |
||||
return -EACCES; |
||||
|
||||
rom_size = rom_header->size * 512; |
||||
|
||||
target = (void *)PCI_VGA_RAM_IMAGE_START; |
||||
if (target != rom_header) { |
||||
debug("Copying VGA ROM Image from %p to %p, 0x%x bytes\n", |
||||
rom_header, target, rom_size); |
||||
memcpy(target, rom_header, rom_size); |
||||
if (memcmp(target, rom_header, rom_size)) { |
||||
printf("VGA ROM copy failed\n"); |
||||
return -EFAULT; |
||||
} |
||||
} |
||||
*ram_headerp = target; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static struct vbe_mode_info mode_info; |
||||
|
||||
int vbe_get_video_info(struct graphic_device *gdev) |
||||
{ |
||||
#ifdef CONFIG_FRAMEBUFFER_SET_VESA_MODE |
||||
struct vesa_mode_info *vesa = &mode_info.vesa; |
||||
|
||||
gdev->winSizeX = vesa->x_resolution; |
||||
gdev->winSizeY = vesa->y_resolution; |
||||
|
||||
gdev->plnSizeX = vesa->x_resolution; |
||||
gdev->plnSizeY = vesa->y_resolution; |
||||
|
||||
gdev->gdfBytesPP = vesa->bits_per_pixel / 8; |
||||
|
||||
switch (vesa->bits_per_pixel) { |
||||
case 24: |
||||
gdev->gdfIndex = GDF_32BIT_X888RGB; |
||||
break; |
||||
case 16: |
||||
gdev->gdfIndex = GDF_16BIT_565RGB; |
||||
break; |
||||
default: |
||||
gdev->gdfIndex = GDF__8BIT_INDEX; |
||||
break; |
||||
} |
||||
|
||||
gdev->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS; |
||||
gdev->pciBase = vesa->phys_base_ptr; |
||||
|
||||
gdev->frameAdrs = vesa->phys_base_ptr; |
||||
gdev->memSize = vesa->bytes_per_scanline * vesa->y_resolution; |
||||
|
||||
gdev->vprBase = vesa->phys_base_ptr; |
||||
gdev->cprBase = vesa->phys_base_ptr; |
||||
|
||||
return 0; |
||||
#else |
||||
return -ENOSYS; |
||||
#endif |
||||
} |
||||
|
||||
int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), bool emulate) |
||||
{ |
||||
struct pci_rom_header *rom, *ram; |
||||
int vesa_mode = -1; |
||||
uint16_t class; |
||||
int ret; |
||||
|
||||
/* Only execute VGA ROMs */ |
||||
pci_read_config_word(dev, PCI_CLASS_DEVICE, &class); |
||||
if ((class ^ PCI_CLASS_DISPLAY_VGA) & 0xff00) { |
||||
debug("%s: Class %#x, should be %#x\n", __func__, class, |
||||
PCI_CLASS_DISPLAY_VGA); |
||||
return -ENODEV; |
||||
} |
||||
|
||||
if (!should_load_oprom(dev)) |
||||
return -ENXIO; |
||||
|
||||
ret = pci_rom_probe(dev, class, &rom); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
ret = pci_rom_load(class, rom, &ram); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
if (!board_should_run_oprom(dev)) |
||||
return -ENXIO; |
||||
|
||||
#if defined(CONFIG_FRAMEBUFFER_SET_VESA_MODE) && \ |
||||
defined(CONFIG_FRAMEBUFFER_VESA_MODE) |
||||
vesa_mode = CONFIG_FRAMEBUFFER_VESA_MODE; |
||||
#endif |
||||
debug("Selected vesa mode %d\b", vesa_mode); |
||||
if (emulate) { |
||||
#ifdef CONFIG_BIOSEMU |
||||
BE_VGAInfo *info; |
||||
|
||||
ret = biosemu_setup(dev, &info); |
||||
if (ret) |
||||
return ret; |
||||
biosemu_set_interrupt_handler(0x15, int15_handler); |
||||
ret = biosemu_run(dev, (uchar *)ram, 1 << 16, info, true, |
||||
vesa_mode, &mode_info); |
||||
if (ret) |
||||
return ret; |
||||
#else |
||||
printf("BIOS emulation not available - see CONFIG_BIOSEMU\n"); |
||||
return -ENOSYS; |
||||
#endif |
||||
} else { |
||||
#ifdef CONFIG_X86 |
||||
bios_set_interrupt_handler(0x15, int15_handler); |
||||
|
||||
bios_run_on_x86(dev, (unsigned long)ram, vesa_mode, |
||||
&mode_info); |
||||
#else |
||||
printf("BIOS native execution is only available on x86\n"); |
||||
return -ENOSYS; |
||||
#endif |
||||
} |
||||
debug("Final vesa mode %d\n", mode_info.video_mode); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,37 @@ |
||||
/*
|
||||
* |
||||
* Vesa frame buffer driver for x86 |
||||
* |
||||
* Copyright (C) 2014 Google, Inc |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <video_fb.h> |
||||
#include <vbe.h> |
||||
#include "videomodes.h" |
||||
|
||||
/*
|
||||
* The Graphic Device |
||||
*/ |
||||
GraphicDevice ctfb; |
||||
|
||||
void *video_hw_init(void) |
||||
{ |
||||
GraphicDevice *gdev = &ctfb; |
||||
int bits_per_pixel; |
||||
|
||||
printf("Video: "); |
||||
if (vbe_get_video_info(gdev)) { |
||||
printf("No video mode configured\n"); |
||||
return NULL; |
||||
} |
||||
|
||||
bits_per_pixel = gdev->gdfBytesPP * 8; |
||||
sprintf(gdev->modeIdent, "%dx%dx%d", gdev->winSizeX, gdev->winSizeY, |
||||
bits_per_pixel); |
||||
printf("%s\n", gdev->modeIdent); |
||||
|
||||
return (void *)gdev; |
||||
} |
@ -0,0 +1,66 @@ |
||||
/*
|
||||
* Copyright (C) 1996-1999 SciTech Software, Inc. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#ifndef _BIOS_EMUL_H |
||||
#define _BIOS_EMUL_H |
||||
|
||||
/* Include the register header directly here */ |
||||
#include "../drivers/bios_emulator/include/x86emu/regs.h" |
||||
#include <pci.h> |
||||
|
||||
/****************************************************************************
|
||||
REMARKS: |
||||
Data structure used to describe the details for the BIOS emulator system |
||||
environment as used by the X86 emulator library. |
||||
|
||||
HEADER: |
||||
biosemu.h |
||||
|
||||
MEMBERS: |
||||
vgaInfo - VGA BIOS information structure |
||||
biosmem_base - Base of the BIOS image |
||||
biosmem_limit - Limit of the BIOS image |
||||
busmem_base - Base of the VGA bus memory |
||||
****************************************************************************/ |
||||
typedef struct { |
||||
int function; |
||||
int device; |
||||
int bus; |
||||
u32 VendorID; |
||||
u32 DeviceID; |
||||
pci_dev_t pcidev; |
||||
void *BIOSImage; |
||||
u32 BIOSImageLen; |
||||
u8 LowMem[1536]; |
||||
} BE_VGAInfo; |
||||
|
||||
struct vbe_mode_info; |
||||
|
||||
int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo, int cleanUp); |
||||
|
||||
/* Run a BIOS ROM natively (only supported on x86 machines) */ |
||||
void bios_run_on_x86(pci_dev_t pcidev, unsigned long addr, int vesa_mode, |
||||
struct vbe_mode_info *mode_info); |
||||
|
||||
/**
|
||||
* bios_set_interrupt_handler() - Install an interrupt handler for the BIOS |
||||
* |
||||
* This installs an interrupt handler that the BIOS will call when needed. |
||||
* |
||||
* @intnum: Interrupt number to install a handler for |
||||
* @int_handler_func: Function to call to handle interrupt |
||||
*/ |
||||
void bios_set_interrupt_handler(int intnum, int (*int_handler_func)(void)); |
||||
|
||||
void biosemu_set_interrupt_handler(int intnum, int (*int_func)(void)); |
||||
|
||||
int biosemu_setup(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo); |
||||
|
||||
int biosemu_run(pci_dev_t pcidev, uchar *bios_rom, int bios_len, |
||||
BE_VGAInfo *vga_info, int clean_up, int vesa_mode, |
||||
struct vbe_mode_info *mode_info); |
||||
|
||||
#endif |
@ -0,0 +1,58 @@ |
||||
/*
|
||||
* From coreboot file of same name |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _PCI_ROM_H |
||||
#define _PCI_ROM_H |
||||
|
||||
#define PCI_ROM_HDR 0xaa55 |
||||
#define PCI_VGA_RAM_IMAGE_START 0xc0000 |
||||
|
||||
struct pci_rom_header { |
||||
uint16_t signature; |
||||
uint8_t size; |
||||
uint8_t init[3]; |
||||
uint8_t reserved[0x12]; |
||||
uint16_t data; |
||||
}; |
||||
|
||||
struct pci_rom_data { |
||||
uint32_t signature; |
||||
uint16_t vendor; |
||||
uint16_t device; |
||||
uint16_t reserved_1; |
||||
uint16_t dlen; |
||||
uint8_t drevision; |
||||
uint8_t class_lo; |
||||
uint16_t class_hi; |
||||
uint16_t ilen; |
||||
uint16_t irevision; |
||||
uint8_t type; |
||||
uint8_t indicator; |
||||
uint16_t reserved_2; |
||||
}; |
||||
|
||||
/**
|
||||
* pci_run_vga_bios() - Run the VGA BIOS in an x86 PC |
||||
* |
||||
* @dev: Video device containing the BIOS |
||||
* @int15_handler: Function to call to handle int 0x15 |
||||
* @emulate: true to use the x86 emulator, false to run native |
||||
*/ |
||||
int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), bool emulate); |
||||
|
||||
/**
|
||||
* board_map_oprom_vendev() - map several PCI IDs to the one the ROM expects |
||||
* |
||||
* 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. |
||||
* |
||||
* @vendev: Vendor and device for the video device |
||||
* @return standard vendor and device expected by the ROM |
||||
*/ |
||||
uint32_t board_map_oprom_vendev(uint32_t vendev); |
||||
|
||||
#endif |
@ -0,0 +1,103 @@ |
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation |
||||
* Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net> |
||||
* All rights reserved. |
||||
* |
||||
* SPDX-License-Identifier: BSD-2-Clause |
||||
* |
||||
* Contributors: |
||||
* IBM Corporation - initial implementation |
||||
*****************************************************************************/ |
||||
#ifndef _VBE_H |
||||
#define _VBE_H |
||||
|
||||
/* these structs are for input from and output to OF */ |
||||
struct __packed screen_info { |
||||
u8 display_type; /* 0=NONE, 1= analog, 2=digital */ |
||||
u16 screen_width; |
||||
u16 screen_height; |
||||
/* bytes per line in framebuffer, may be more than screen_width */ |
||||
u16 screen_linebytes; |
||||
u8 color_depth; /* color depth in bits per pixel */ |
||||
u32 framebuffer_address; |
||||
u8 edid_block_zero[128]; |
||||
}; |
||||
|
||||
struct __packed screen_info_input { |
||||
u8 signature[4]; |
||||
u16 size_reserved; |
||||
u8 monitor_number; |
||||
u16 max_screen_width; |
||||
u8 color_depth; |
||||
}; |
||||
|
||||
/* these structs only store the required a subset of the VBE-defined fields */ |
||||
struct __packed vbe_info { |
||||
char signature[4]; |
||||
u16 version; |
||||
u8 *oem_string_ptr; |
||||
u32 capabilities; |
||||
u16 video_mode_list[256]; |
||||
u16 total_memory; |
||||
}; |
||||
|
||||
struct __packed vesa_mode_info { |
||||
u16 mode_attributes; /* 00 */ |
||||
u8 win_a_attributes; /* 02 */ |
||||
u8 win_b_attributes; /* 03 */ |
||||
u16 win_granularity; /* 04 */ |
||||
u16 win_size; /* 06 */ |
||||
u16 win_a_segment; /* 08 */ |
||||
u16 win_b_segment; /* 0a */ |
||||
u32 win_func_ptr; /* 0c */ |
||||
u16 bytes_per_scanline; /* 10 */ |
||||
u16 x_resolution; /* 12 */ |
||||
u16 y_resolution; /* 14 */ |
||||
u8 x_charsize; /* 16 */ |
||||
u8 y_charsize; /* 17 */ |
||||
u8 number_of_planes; /* 18 */ |
||||
u8 bits_per_pixel; /* 19 */ |
||||
u8 number_of_banks; /* 20 */ |
||||
u8 memory_model; /* 21 */ |
||||
u8 bank_size; /* 22 */ |
||||
u8 number_of_image_pages; /* 23 */ |
||||
u8 reserved_page; |
||||
u8 red_mask_size; |
||||
u8 red_mask_pos; |
||||
u8 green_mask_size; |
||||
u8 green_mask_pos; |
||||
u8 blue_mask_size; |
||||
u8 blue_mask_pos; |
||||
u8 reserved_mask_size; |
||||
u8 reserved_mask_pos; |
||||
u8 direct_color_mode_info; |
||||
u32 phys_base_ptr; |
||||
u32 offscreen_mem_offset; |
||||
u16 offscreen_mem_size; |
||||
u8 reserved[206]; |
||||
}; |
||||
|
||||
struct vbe_mode_info { |
||||
u16 video_mode; |
||||
bool valid; |
||||
union { |
||||
struct vesa_mode_info vesa; |
||||
u8 mode_info_block[256]; |
||||
}; |
||||
}; |
||||
|
||||
struct vbe_ddc_info { |
||||
u8 port_number; /* i.e. monitor number */ |
||||
u8 edid_transfer_time; |
||||
u8 ddc_level; |
||||
u8 edid_block_zero[128]; |
||||
}; |
||||
|
||||
#define VESA_GET_INFO 0x4f00 |
||||
#define VESA_GET_MODE_INFO 0x4f01 |
||||
#define VESA_SET_MODE 0x4f02 |
||||
|
||||
struct graphic_device; |
||||
int vbe_get_video_info(struct graphic_device *gdev); |
||||
|
||||
#endif |
Loading…
Reference in new issue