util: Import autoport with Haswell patches
This is a copy of coreboot's autoport utility, with a patch applied to support Haswell/Lynx Point platforms. That patch is currently in review on coreboot's Gerrit. https://review.coreboot.org/c/coreboot/+/30890 Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>9020nri
parent
c578fe56c3
commit
8cba237086
|
@ -0,0 +1,67 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
type azalia struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i azalia) Scan(ctx Context, addr PCIDevData) {
|
||||||
|
az := Create(ctx, "hda_verb.c")
|
||||||
|
defer az.Close()
|
||||||
|
|
||||||
|
Add_gpl(az)
|
||||||
|
az.WriteString(
|
||||||
|
`#include <device/azalia_device.h>
|
||||||
|
|
||||||
|
const u32 cim_verb_data[] = {
|
||||||
|
`)
|
||||||
|
|
||||||
|
for _, codec := range ctx.InfoSource.GetAzaliaCodecs() {
|
||||||
|
fmt.Fprintf(az, "\t0x%08x,\t/* Codec Vendor / Device ID: %s */\n",
|
||||||
|
codec.VendorID, codec.Name)
|
||||||
|
fmt.Fprintf(az, "\t0x%08x,\t/* Subsystem ID */\n",
|
||||||
|
codec.SubsystemID)
|
||||||
|
fmt.Fprintf(az, "\t%d,\t\t/* Number of 4 dword sets */\n",
|
||||||
|
len(codec.PinConfig)+1)
|
||||||
|
fmt.Fprintf(az, "\tAZALIA_SUBVENDOR(%d, 0x%08x),\n",
|
||||||
|
codec.CodecNo, codec.SubsystemID)
|
||||||
|
|
||||||
|
keys := []int{}
|
||||||
|
for nid, _ := range codec.PinConfig {
|
||||||
|
keys = append(keys, nid)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Ints(keys)
|
||||||
|
|
||||||
|
for _, nid := range keys {
|
||||||
|
fmt.Fprintf(az, "\tAZALIA_PIN_CFG(%d, 0x%02x, 0x%08x),\n",
|
||||||
|
codec.CodecNo, nid, codec.PinConfig[nid])
|
||||||
|
}
|
||||||
|
az.WriteString("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
az.WriteString(
|
||||||
|
`};
|
||||||
|
|
||||||
|
const u32 pc_beep_verbs[0] = {};
|
||||||
|
|
||||||
|
AZALIA_ARRAY_SIZES;
|
||||||
|
`)
|
||||||
|
|
||||||
|
PutPCIDev(addr, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
/* I82801GX/I945 */
|
||||||
|
RegisterPCI(0x8086, 0x27d8, azalia{})
|
||||||
|
/* BD82X6X/sandybridge */
|
||||||
|
RegisterPCI(0x8086, 0x1c20, azalia{})
|
||||||
|
/* C216/ivybridge */
|
||||||
|
RegisterPCI(0x8086, 0x1e20, azalia{})
|
||||||
|
/* Lynx Point */
|
||||||
|
RegisterPCI(0x8086, 0x8c20, azalia{})
|
||||||
|
RegisterPCI(0x8086, 0x9c20, azalia{})
|
||||||
|
}
|
|
@ -0,0 +1,337 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type bd82x6x struct {
|
||||||
|
variant string
|
||||||
|
node *DevTreeNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsPCIeHotplug(ctx Context, port int) bool {
|
||||||
|
portDev, ok := PCIMap[PCIAddr{Bus: 0, Dev: 0x1c, Func: port}]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return (portDev.ConfigDump[0xdb] & (1 << 6)) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ich9GetFlashSize(ctx Context) {
|
||||||
|
inteltool := ctx.InfoSource.GetInteltool()
|
||||||
|
switch (inteltool.RCBA[0x3410] >> 10) & 3 {
|
||||||
|
/* SPI. All boards I've seen with sandy/ivy use SPI. */
|
||||||
|
case 3:
|
||||||
|
ROMProtocol = "SPI"
|
||||||
|
highflkb := uint32(0)
|
||||||
|
for reg := uint16(0); reg < 5; reg++ {
|
||||||
|
fl := (inteltool.RCBA[0x3854+4*reg] >> 16) & 0x1fff
|
||||||
|
flkb := (fl + 1) << 2
|
||||||
|
if flkb > highflkb {
|
||||||
|
highflkb = flkb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ROMSizeKB = int(highflkb)
|
||||||
|
/* Shared with ME. Flashrom is unable to handle it. */
|
||||||
|
FlashROMSupport = "n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b bd82x6x) GetGPIOHeader() string {
|
||||||
|
return "southbridge/intel/bd82x6x/pch.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b bd82x6x) EnableGPE(in int) {
|
||||||
|
b.node.Registers[fmt.Sprintf("gpi%d_routing", in)] = "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b bd82x6x) EncodeGPE(in int) int {
|
||||||
|
return in + 0x10
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b bd82x6x) DecodeGPE(in int) int {
|
||||||
|
return in - 0x10
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b bd82x6x) NeedRouteGPIOManually() {
|
||||||
|
b.node.Comment += ", FIXME: set gpiX_routing for EC support"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b bd82x6x) Scan(ctx Context, addr PCIDevData) {
|
||||||
|
|
||||||
|
SouthBridge = &b
|
||||||
|
|
||||||
|
inteltool := ctx.InfoSource.GetInteltool()
|
||||||
|
GPIO(ctx, inteltool)
|
||||||
|
|
||||||
|
KconfigBool["SOUTHBRIDGE_INTEL_"+b.variant] = true
|
||||||
|
KconfigBool["SERIRQ_CONTINUOUS_MODE"] = true
|
||||||
|
KconfigInt["USBDEBUG_HCD_INDEX"] = 2
|
||||||
|
KconfigComment["USBDEBUG_HCD_INDEX"] = "FIXME: check this"
|
||||||
|
dmi := ctx.InfoSource.GetDMI()
|
||||||
|
if dmi.Vendor == "LENOVO" {
|
||||||
|
KconfigInt["DRAM_RESET_GATE_GPIO"] = 10
|
||||||
|
} else {
|
||||||
|
KconfigInt["DRAM_RESET_GATE_GPIO"] = 60
|
||||||
|
}
|
||||||
|
KconfigComment["DRAM_RESET_GATE_GPIO"] = "FIXME: check this"
|
||||||
|
|
||||||
|
ich9GetFlashSize(ctx)
|
||||||
|
|
||||||
|
DSDTDefines = append(DSDTDefines,
|
||||||
|
DSDTDefine{
|
||||||
|
Key: "BRIGHTNESS_UP",
|
||||||
|
Value: "\\_SB.PCI0.GFX0.INCB",
|
||||||
|
},
|
||||||
|
DSDTDefine{
|
||||||
|
Key: "BRIGHTNESS_DOWN",
|
||||||
|
Value: "\\_SB.PCI0.GFX0.DECB",
|
||||||
|
})
|
||||||
|
|
||||||
|
/* SPI init */
|
||||||
|
MainboardIncludes = append(MainboardIncludes, "southbridge/intel/bd82x6x/pch.h")
|
||||||
|
|
||||||
|
FADT := ctx.InfoSource.GetACPI()["FACP"]
|
||||||
|
|
||||||
|
pcieHotplugMap := "{ "
|
||||||
|
|
||||||
|
for port := 0; port < 7; port++ {
|
||||||
|
if IsPCIeHotplug(ctx, port) {
|
||||||
|
pcieHotplugMap += "1, "
|
||||||
|
} else {
|
||||||
|
pcieHotplugMap += "0, "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsPCIeHotplug(ctx, 7) {
|
||||||
|
pcieHotplugMap += "1 }"
|
||||||
|
} else {
|
||||||
|
pcieHotplugMap += "0 }"
|
||||||
|
}
|
||||||
|
|
||||||
|
cur := DevTreeNode{
|
||||||
|
Chip: "southbridge/intel/bd82x6x",
|
||||||
|
Comment: "Intel Series 6 Cougar Point PCH",
|
||||||
|
|
||||||
|
Registers: map[string]string{
|
||||||
|
"sata_interface_speed_support": "0x3",
|
||||||
|
"gen1_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x84:0x88]),
|
||||||
|
"gen2_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x88:0x8c]),
|
||||||
|
"gen3_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x8c:0x90]),
|
||||||
|
"gen4_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x90:0x94]),
|
||||||
|
"pcie_port_coalesce": "1",
|
||||||
|
"pcie_hotplug_map": pcieHotplugMap,
|
||||||
|
|
||||||
|
"sata_port_map": fmt.Sprintf("0x%x", PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 2}].ConfigDump[0x92]&0x3f),
|
||||||
|
|
||||||
|
"docking_supported": (FormatBool((FADT[113] & (1 << 1)) != 0)),
|
||||||
|
"spi_uvscc": fmt.Sprintf("0x%x", inteltool.RCBA[0x38c8]),
|
||||||
|
"spi_lvscc": fmt.Sprintf("0x%x", inteltool.RCBA[0x38c4]&^(1<<23)),
|
||||||
|
},
|
||||||
|
PCISlots: []PCISlot{
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x14, Func: 0}, writeEmpty: false, alias: "xhci", additionalComment: "USB 3.0 Controller"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 0}, writeEmpty: true, alias: "mei1", additionalComment: "Management Engine Interface 1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 1}, writeEmpty: true, alias: "mei2", additionalComment: "Management Engine Interface 2"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 2}, writeEmpty: true, alias: "me_ide_r", additionalComment: "Management Engine IDE-R"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 3}, writeEmpty: true, alias: "me_kt", additionalComment: "Management Engine KT"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x19, Func: 0}, writeEmpty: true, alias: "gbe", additionalComment: "Intel Gigabit Ethernet"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1a, Func: 0}, writeEmpty: true, alias: "ehci2", additionalComment: "USB2 EHCI #2"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1b, Func: 0}, writeEmpty: true, alias: "hda", additionalComment: "High Definition Audio"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 0}, writeEmpty: true, alias: "pcie_rp1", additionalComment: "PCIe Port #1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 1}, writeEmpty: true, alias: "pcie_rp2", additionalComment: "PCIe Port #2"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 2}, writeEmpty: true, alias: "pcie_rp3", additionalComment: "PCIe Port #3"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 3}, writeEmpty: true, alias: "pcie_rp4", additionalComment: "PCIe Port #4"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 4}, writeEmpty: true, alias: "pcie_rp5", additionalComment: "PCIe Port #5"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 5}, writeEmpty: true, alias: "pcie_rp6", additionalComment: "PCIe Port #6"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 6}, writeEmpty: true, alias: "pcie_rp7", additionalComment: "PCIe Port #7"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 7}, writeEmpty: true, alias: "pcie_rp8", additionalComment: "PCIe Port #8"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1d, Func: 0}, writeEmpty: true, alias: "ehci1", additionalComment: "USB2 EHCI #1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1e, Func: 0}, writeEmpty: true, alias: "pci_bridge", additionalComment: "PCI bridge"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 0}, writeEmpty: true, alias: "lpc", additionalComment: "LPC bridge"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 2}, writeEmpty: true, alias: "sata1", additionalComment: "SATA Controller 1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 3}, writeEmpty: true, alias: "smbus", additionalComment: "SMBus"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 5}, writeEmpty: true, alias: "sata2", additionalComment: "SATA Controller 2"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 6}, writeEmpty: true, alias: "thermal", additionalComment: "Thermal"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b.node = &cur
|
||||||
|
|
||||||
|
xhciDev, ok := PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}]
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
cur.Registers["xhci_switchable_ports"] = FormatHexLE32(xhciDev.ConfigDump[0xd4:0xd8])
|
||||||
|
cur.Registers["superspeed_capable_ports"] = FormatHexLE32(xhciDev.ConfigDump[0xdc:0xe0])
|
||||||
|
cur.Registers["xhci_overcurrent_mapping"] = FormatHexLE32(xhciDev.ConfigDump[0xc0:0xc4])
|
||||||
|
}
|
||||||
|
|
||||||
|
PutPCIChip(addr, cur)
|
||||||
|
PutPCIDevParent(addr, "", "lpc")
|
||||||
|
|
||||||
|
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||||
|
File: "southbridge/intel/common/acpi/platform.asl",
|
||||||
|
})
|
||||||
|
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||||
|
File: "southbridge/intel/bd82x6x/acpi/globalnvs.asl",
|
||||||
|
})
|
||||||
|
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||||
|
File: "southbridge/intel/common/acpi/sleepstates.asl",
|
||||||
|
})
|
||||||
|
DSDTPCI0Includes = append(DSDTPCI0Includes, DSDTInclude{
|
||||||
|
File: "southbridge/intel/bd82x6x/acpi/pch.asl",
|
||||||
|
})
|
||||||
|
|
||||||
|
AddBootBlockFile("early_init.c", "")
|
||||||
|
AddROMStageFile("early_init.c", "")
|
||||||
|
|
||||||
|
sb := Create(ctx, "early_init.c")
|
||||||
|
defer sb.Close()
|
||||||
|
Add_gpl(sb)
|
||||||
|
|
||||||
|
sb.WriteString(`
|
||||||
|
#include <bootblock_common.h>
|
||||||
|
#include <device/pci_ops.h>
|
||||||
|
#include <northbridge/intel/sandybridge/raminit_native.h>
|
||||||
|
#include <southbridge/intel/bd82x6x/pch.h>
|
||||||
|
|
||||||
|
`)
|
||||||
|
sb.WriteString("const struct southbridge_usb_port mainboard_usb_ports[] = {\n")
|
||||||
|
|
||||||
|
currentMap := map[uint32]int{
|
||||||
|
0x20000153: 0,
|
||||||
|
0x20000f57: 1,
|
||||||
|
0x2000055b: 2,
|
||||||
|
0x20000f51: 3,
|
||||||
|
0x2000094a: 4,
|
||||||
|
0x2000035f: 5,
|
||||||
|
0x20000f53: 6,
|
||||||
|
0x20000357: 7,
|
||||||
|
0x20000353: 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
for port := uint(0); port < 14; port++ {
|
||||||
|
var pinmask uint32
|
||||||
|
OCPin := -1
|
||||||
|
if port < 8 {
|
||||||
|
pinmask = inteltool.RCBA[0x35a0]
|
||||||
|
} else {
|
||||||
|
pinmask = inteltool.RCBA[0x35a4]
|
||||||
|
}
|
||||||
|
for pin := uint(0); pin < 4; pin++ {
|
||||||
|
if ((pinmask >> ((port % 8) + 8*pin)) & 1) != 0 {
|
||||||
|
OCPin = int(pin)
|
||||||
|
if port >= 8 {
|
||||||
|
OCPin += 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current, ok := currentMap[inteltool.RCBA[uint16(0x3500+4*port)]]
|
||||||
|
comment := ""
|
||||||
|
if !ok {
|
||||||
|
comment = fmt.Sprintf("// FIXME: Unknown current: RCBA(0x%x)=0x%x", 0x3500+4*port, uint16(0x3500+4*port))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(sb, "\t{ %d, %d, %d }, %s\n",
|
||||||
|
((inteltool.RCBA[0x359c]>>port)&1)^1,
|
||||||
|
current,
|
||||||
|
OCPin,
|
||||||
|
comment)
|
||||||
|
}
|
||||||
|
sb.WriteString("};\n")
|
||||||
|
|
||||||
|
guessedMap := GuessSPDMap(ctx)
|
||||||
|
|
||||||
|
sb.WriteString(`
|
||||||
|
void bootblock_mainboard_early_init(void)
|
||||||
|
{
|
||||||
|
`)
|
||||||
|
RestorePCI16Simple(sb, addr, 0x82)
|
||||||
|
|
||||||
|
RestorePCI16Simple(sb, addr, 0x80)
|
||||||
|
|
||||||
|
sb.WriteString(`}
|
||||||
|
|
||||||
|
/* FIXME: Put proper SPD map here. */
|
||||||
|
void mainboard_get_spd(spd_raw_data *spd, bool id_only)
|
||||||
|
{
|
||||||
|
`)
|
||||||
|
for i, spd := range guessedMap {
|
||||||
|
fmt.Fprintf(sb, "\tread_spd(&spd[%d], 0x%02x, id_only);\n", i, spd)
|
||||||
|
}
|
||||||
|
sb.WriteString("}\n")
|
||||||
|
|
||||||
|
gnvs := Create(ctx, "acpi_tables.c")
|
||||||
|
defer gnvs.Close()
|
||||||
|
|
||||||
|
Add_gpl(gnvs)
|
||||||
|
gnvs.WriteString(`#include <acpi/acpi_gnvs.h>
|
||||||
|
#include <soc/nvs.h>
|
||||||
|
|
||||||
|
/* FIXME: check this function. */
|
||||||
|
void mainboard_fill_gnvs(struct global_nvs *gnvs)
|
||||||
|
{
|
||||||
|
/* The lid is open by default. */
|
||||||
|
gnvs->lids = 1;
|
||||||
|
|
||||||
|
/* Temperature at which OS will shutdown */
|
||||||
|
gnvs->tcrt = 100;
|
||||||
|
/* Temperature at which OS will throttle CPU */
|
||||||
|
gnvs->tpsv = 90;
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
/* BD82X6X LPC */
|
||||||
|
for id := 0x1c40; id <= 0x1c5f; id++ {
|
||||||
|
RegisterPCI(0x8086, uint16(id), bd82x6x{variant: "BD82X6X"})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C216 LPC */
|
||||||
|
for id := 0x1e41; id <= 0x1e5f; id++ {
|
||||||
|
RegisterPCI(0x8086, uint16(id), bd82x6x{variant: "C216"})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PCIe bridge */
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x1c10, 0x1c12, 0x1c14, 0x1c16,
|
||||||
|
0x1c18, 0x1c1a, 0x1c1c, 0x1c1e,
|
||||||
|
0x1e10, 0x1e12, 0x1e14, 0x1e16,
|
||||||
|
0x1e18, 0x1e1a, 0x1e1c, 0x1e1e,
|
||||||
|
0x1e25, 0x244e, 0x2448,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SMBus controller */
|
||||||
|
RegisterPCI(0x8086, 0x1c22, GenericPCI{MissingParent: "smbus"})
|
||||||
|
RegisterPCI(0x8086, 0x1e22, GenericPCI{MissingParent: "smbus"})
|
||||||
|
|
||||||
|
/* SATA */
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x1c00, 0x1c01, 0x1c02, 0x1c03,
|
||||||
|
0x1e00, 0x1e01, 0x1e02, 0x1e03,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EHCI */
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x1c26, 0x1c2d, 0x1e26, 0x1e2d,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XHCI */
|
||||||
|
RegisterPCI(0x8086, 0x1e31, GenericPCI{})
|
||||||
|
|
||||||
|
/* ME and children */
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x1c3a, 0x1c3b, 0x1c3c, 0x1c3d,
|
||||||
|
0x1e3a, 0x1e3b, 0x1e3c, 0x1e3d,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ethernet */
|
||||||
|
RegisterPCI(0x8086, 0x1502, GenericPCI{})
|
||||||
|
RegisterPCI(0x8086, 0x1503, GenericPCI{})
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Automated porting coreboot to Sandy Bridge/Ivy Bridge platforms `Go`
|
|
@ -0,0 +1,91 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func FIXMEEC(ctx Context) {
|
||||||
|
ap := Create(ctx, "acpi/platform.asl")
|
||||||
|
defer ap.Close()
|
||||||
|
|
||||||
|
hasKeyboard := ctx.InfoSource.HasPS2()
|
||||||
|
|
||||||
|
sbGPE := GuessECGPE(ctx)
|
||||||
|
var GPEUnsure bool
|
||||||
|
if sbGPE < 0 {
|
||||||
|
sbGPE = SouthBridge.EncodeGPE(1)
|
||||||
|
GPEUnsure = true
|
||||||
|
SouthBridge.NeedRouteGPIOManually()
|
||||||
|
} else {
|
||||||
|
GPEUnsure = false
|
||||||
|
SouthBridge.EnableGPE(SouthBridge.DecodeGPE(sbGPE))
|
||||||
|
}
|
||||||
|
|
||||||
|
Add_gpl(ap)
|
||||||
|
ap.WriteString(
|
||||||
|
`Method(_WAK, 1)
|
||||||
|
{
|
||||||
|
/* FIXME: EC support */
|
||||||
|
Return(Package() {0, 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
Method(_PTS,1)
|
||||||
|
{
|
||||||
|
/* FIXME: EC support */
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
ecs := ctx.InfoSource.GetEC()
|
||||||
|
MainboardIncludes = append(MainboardIncludes, "ec/acpi/ec.h")
|
||||||
|
MainboardIncludes = append(MainboardIncludes, "console/console.h")
|
||||||
|
|
||||||
|
MainboardInit +=
|
||||||
|
` /* FIXME: trim this down or remove if necessary */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const u8 dmp[256] = {`
|
||||||
|
for i := 0; i < 0x100; i++ {
|
||||||
|
if (i & 0xf) == 0 {
|
||||||
|
MainboardInit += fmt.Sprintf("\n\t\t\t/* %02x */ ", i)
|
||||||
|
}
|
||||||
|
MainboardInit += fmt.Sprintf("0x%02x,", ecs[i])
|
||||||
|
if (i & 0xf) != 0xf {
|
||||||
|
MainboardInit += " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MainboardInit += "\n\t\t};\n"
|
||||||
|
MainboardInit += `
|
||||||
|
printk(BIOS_DEBUG, "Replaying EC dump ...");
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
ec_write (i, dmp[i]);
|
||||||
|
printk(BIOS_DEBUG, "done\n");
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
KconfigBool["EC_ACPI"] = true
|
||||||
|
si := Create(ctx, "acpi/superio.asl")
|
||||||
|
defer si.Close()
|
||||||
|
|
||||||
|
if hasKeyboard {
|
||||||
|
Add_gpl(si)
|
||||||
|
si.WriteString("#include <drivers/pc80/pc/ps2_controller.asl>\n")
|
||||||
|
MainboardInit += fmt.Sprintf("\tpc_keyboard_init(NO_AUX_DEVICE);\n")
|
||||||
|
MainboardIncludes = append(MainboardIncludes, "pc80/keyboard.h")
|
||||||
|
}
|
||||||
|
|
||||||
|
ec := Create(ctx, "acpi/ec.asl")
|
||||||
|
defer ec.Close()
|
||||||
|
|
||||||
|
Add_gpl(ec)
|
||||||
|
ec.WriteString(`Device(EC)
|
||||||
|
{
|
||||||
|
Name (_HID, EISAID("PNP0C09"))
|
||||||
|
Name (_UID, 0)
|
||||||
|
`)
|
||||||
|
if GPEUnsure {
|
||||||
|
ec.WriteString("\t/* FIXME: Set GPE */\n")
|
||||||
|
ec.WriteString("\t/* Name (_GPE, ?) */\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(ec, "\tName (_GPE, %d)\n", sbGPE)
|
||||||
|
}
|
||||||
|
ec.WriteString("/* FIXME: EC support */\n")
|
||||||
|
ec.WriteString("}\n")
|
||||||
|
}
|
|
@ -0,0 +1,245 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func LenovoEC(ctx Context) {
|
||||||
|
ap := Create(ctx, "acpi/platform.asl")
|
||||||
|
defer ap.Close()
|
||||||
|
|
||||||
|
wakeGPE := 13
|
||||||
|
|
||||||
|
sbGPE := GuessECGPE(ctx)
|
||||||
|
var GPE int
|
||||||
|
var GPEUnsure bool
|
||||||
|
if sbGPE < 0 {
|
||||||
|
sbGPE = SouthBridge.EncodeGPE(1)
|
||||||
|
GPE = 1
|
||||||
|
GPEUnsure = true
|
||||||
|
SouthBridge.NeedRouteGPIOManually()
|
||||||
|
} else {
|
||||||
|
GPE = SouthBridge.DecodeGPE(sbGPE)
|
||||||
|
GPEUnsure = false
|
||||||
|
}
|
||||||
|
|
||||||
|
SouthBridge.EnableGPE(wakeGPE)
|
||||||
|
SouthBridge.EnableGPE(GPE)
|
||||||
|
|
||||||
|
GPEDefine := DSDTDefine{
|
||||||
|
Key: "THINKPAD_EC_GPE",
|
||||||
|
}
|
||||||
|
|
||||||
|
GPEDefine.Value = fmt.Sprintf("%d", sbGPE)
|
||||||
|
if GPEUnsure {
|
||||||
|
GPEDefine.Comment = "FIXME: Check this"
|
||||||
|
}
|
||||||
|
|
||||||
|
DSDTDefines = append(DSDTDefines,
|
||||||
|
DSDTDefine{
|
||||||
|
Key: "EC_LENOVO_H8_ME_WORKAROUND",
|
||||||
|
Value: "1",
|
||||||
|
}, GPEDefine)
|
||||||
|
|
||||||
|
Add_gpl(ap)
|
||||||
|
ap.WriteString(
|
||||||
|
`Method(_WAK, 1)
|
||||||
|
{
|
||||||
|
/* ME may not be up yet. */
|
||||||
|
Store(0, \_TZ.MEB1)
|
||||||
|
Store(0, \_TZ.MEB2)
|
||||||
|
Return(Package() {0, 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
Method(_PTS,1)
|
||||||
|
{
|
||||||
|
\_SB.PCI0.LPCB.EC.RADI(0)
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
si := Create(ctx, "acpi/superio.asl")
|
||||||
|
defer si.Close()
|
||||||
|
|
||||||
|
Add_gpl(si)
|
||||||
|
si.WriteString("#include <drivers/pc80/pc/ps2_controller.asl>\n")
|
||||||
|
|
||||||
|
/* FIXME:XX Move this to ec/lenovo. */
|
||||||
|
smi := Create(ctx, "smihandler.c")
|
||||||
|
defer smi.Close()
|
||||||
|
|
||||||
|
AddSMMFile("smihandler.c", "")
|
||||||
|
|
||||||
|
Add_gpl(smi)
|
||||||
|
smi.WriteString(
|
||||||
|
`#include <arch/io.h>
|
||||||
|
#include <console/console.h>
|
||||||
|
#include <cpu/x86/smm.h>
|
||||||
|
#include <ec/acpi/ec.h>
|
||||||
|
#include <ec/lenovo/h8/h8.h>
|
||||||
|
#include <delay.h>
|
||||||
|
#include <` + SouthBridge.GetGPIOHeader() + ">\n\n")
|
||||||
|
|
||||||
|
if GPEUnsure {
|
||||||
|
smi.WriteString("/* FIXME: check this */\n")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(smi, "#define GPE_EC_SCI %d\n", GPE)
|
||||||
|
|
||||||
|
smi.WriteString("/* FIXME: check this */\n")
|
||||||
|
fmt.Fprintf(smi, "#define GPE_EC_WAKE %d\n", wakeGPE)
|
||||||
|
|
||||||
|
smi.WriteString(`
|
||||||
|
static void mainboard_smi_handle_ec_sci(void)
|
||||||
|
{
|
||||||
|
u8 status = inb(EC_SC);
|
||||||
|
u8 event;
|
||||||
|
|
||||||
|
if (!(status & EC_SCI_EVT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
event = ec_query();
|
||||||
|
printk(BIOS_DEBUG, "EC event %#02x\n", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainboard_smi_gpi(u32 gpi_sts)
|
||||||
|
{
|
||||||
|
if (gpi_sts & (1 << GPE_EC_SCI))
|
||||||
|
mainboard_smi_handle_ec_sci();
|
||||||
|
}
|
||||||
|
|
||||||
|
int mainboard_smi_apmc(u8 data)
|
||||||
|
{
|
||||||
|
switch (data) {
|
||||||
|
case APM_CNT_ACPI_ENABLE:
|
||||||
|
/* use 0x1600/0x1604 to prevent races with userspace */
|
||||||
|
ec_set_ports(0x1604, 0x1600);
|
||||||
|
/* route EC_SCI to SCI */
|
||||||
|
gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SCI);
|
||||||
|
/* discard all events, and enable attention */
|
||||||
|
ec_write(0x80, 0x01);
|
||||||
|
break;
|
||||||
|
case APM_CNT_ACPI_DISABLE:
|
||||||
|
/* we have to use port 0x62/0x66, as 0x1600/0x1604 doesn't
|
||||||
|
provide a EC query function */
|
||||||
|
ec_set_ports(0x66, 0x62);
|
||||||
|
/* route EC_SCI to SMI */
|
||||||
|
gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SMI);
|
||||||
|
/* discard all events, and enable attention */
|
||||||
|
ec_write(0x80, 0x01);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainboard_smi_sleep(u8 slp_typ)
|
||||||
|
{
|
||||||
|
if (slp_typ == 3) {
|
||||||
|
u8 ec_wake = ec_read(0x32);
|
||||||
|
/* If EC wake events are enabled, enable wake on EC WAKE GPE. */
|
||||||
|
if (ec_wake & 0x14) {
|
||||||
|
/* Redirect EC WAKE GPE to SCI. */
|
||||||
|
gpi_route_interrupt(GPE_EC_WAKE, GPI_IS_SCI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
ec := Create(ctx, "acpi/ec.asl")
|
||||||
|
defer ec.Close()
|
||||||
|
|
||||||
|
Add_gpl(ec)
|
||||||
|
ec.WriteString("#include <ec/lenovo/h8/acpi/ec.asl>\n")
|
||||||
|
|
||||||
|
KconfigBool["EC_LENOVO_PMH7"] = true
|
||||||
|
KconfigBool["EC_LENOVO_H8"] = true
|
||||||
|
|
||||||
|
pmh := DevTreeNode{
|
||||||
|
Chip: "ec/lenovo/pmh7",
|
||||||
|
Registers: map[string]string{
|
||||||
|
"backlight_enable": "true",
|
||||||
|
"dock_event_enable": "true",
|
||||||
|
},
|
||||||
|
Children: []DevTreeNode{
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "pnp",
|
||||||
|
Comment: "dummy",
|
||||||
|
Dev: 0xff,
|
||||||
|
Func: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
PutChip("lpc", pmh)
|
||||||
|
|
||||||
|
ecs := ctx.InfoSource.GetEC()
|
||||||
|
h8 := DevTreeNode{
|
||||||
|
Chip: "ec/lenovo/h8",
|
||||||
|
Children: []DevTreeNode{
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "pnp",
|
||||||
|
Comment: "dummy",
|
||||||
|
Dev: 0xff,
|
||||||
|
Func: 2,
|
||||||
|
IOs: map[uint16]uint16{
|
||||||
|
0x60: 0x62,
|
||||||
|
0x62: 0x66,
|
||||||
|
0x64: 0x1600,
|
||||||
|
0x66: 0x1604,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Comment: "FIXME: has_keyboard_backlight, has_power_management_beeps, has_uwb",
|
||||||
|
Registers: map[string]string{
|
||||||
|
"config0": FormatHex8(ecs[0]),
|
||||||
|
"config1": FormatHex8(ecs[1]),
|
||||||
|
"config2": FormatHex8(ecs[2]),
|
||||||
|
"config3": FormatHex8(ecs[3]),
|
||||||
|
"beepmask0": FormatHex8(ecs[4]),
|
||||||
|
"beepmask1": FormatHex8(ecs[5]),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i := 0; i < 0x10; i++ {
|
||||||
|
if ecs[0x10+i] != 0 {
|
||||||
|
h8.Registers[fmt.Sprintf("event%x_enable", i)] = FormatHex8(ecs[0x10+i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PutChip("lpc", h8)
|
||||||
|
|
||||||
|
eeprom := DevTreeNode{
|
||||||
|
Chip: "drivers/i2c/at24rf08c",
|
||||||
|
Comment: "eeprom, 8 virtual devices, same chip",
|
||||||
|
Children: []DevTreeNode{
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "i2c",
|
||||||
|
Dev: 0x54,
|
||||||
|
},
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "i2c",
|
||||||
|
Dev: 0x55,
|
||||||
|
},
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "i2c",
|
||||||
|
Dev: 0x56,
|
||||||
|
},
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "i2c",
|
||||||
|
Dev: 0x57,
|
||||||
|
},
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "i2c",
|
||||||
|
Dev: 0x5c,
|
||||||
|
},
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "i2c",
|
||||||
|
Dev: 0x5d,
|
||||||
|
},
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "i2c",
|
||||||
|
Dev: 0x5e,
|
||||||
|
},
|
||||||
|
DevTreeNode{
|
||||||
|
Chip: "i2c",
|
||||||
|
Dev: 0x5f,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
PutChip("smbus", eeprom)
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
func NoEC(ctx Context) {
|
||||||
|
ap := Create(ctx, "acpi/platform.asl")
|
||||||
|
defer ap.Close()
|
||||||
|
|
||||||
|
Add_gpl(ap)
|
||||||
|
ap.WriteString(
|
||||||
|
`Method(_WAK, 1)
|
||||||
|
{
|
||||||
|
Return(Package() {0, 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
Method(_PTS, 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
si := Create(ctx, "acpi/superio.asl")
|
||||||
|
defer si.Close()
|
||||||
|
|
||||||
|
ec := Create(ctx, "acpi/ec.asl")
|
||||||
|
defer ec.Close()
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
module autoport
|
|
@ -0,0 +1,113 @@
|
||||||
|
/* code to generate common GPIO code for Intel 6/7/8 Series Chipset */
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeGPIOSet(ctx Context, sb *os.File,
|
||||||
|
val uint32, set uint, partno int, constraint uint32) {
|
||||||
|
|
||||||
|
max := uint(32)
|
||||||
|
if set == 3 {
|
||||||
|
max = 12
|
||||||
|
}
|
||||||
|
|
||||||
|
bits := [6][2]string{
|
||||||
|
{"GPIO_MODE_NATIVE", "GPIO_MODE_GPIO"},
|
||||||
|
{"GPIO_DIR_OUTPUT", "GPIO_DIR_INPUT"},
|
||||||
|
{"GPIO_LEVEL_LOW", "GPIO_LEVEL_HIGH"},
|
||||||
|
{"GPIO_RESET_PWROK", "GPIO_RESET_RSMRST"},
|
||||||
|
{"GPIO_NO_INVERT", "GPIO_INVERT"},
|
||||||
|
{"GPIO_NO_BLINK", "GPIO_BLINK"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint(0); i < max; i++ {
|
||||||
|
if (constraint>>i)&1 == 1 {
|
||||||
|
fmt.Fprintf(sb, " .gpio%d = %s,\n",
|
||||||
|
(set-1)*32+i,
|
||||||
|
bits[partno][(val>>i)&1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GPIO(ctx Context, inteltool InteltoolData) {
|
||||||
|
var constraint uint32
|
||||||
|
gpio := Create(ctx, "gpio.c")
|
||||||
|
defer gpio.Close()
|
||||||
|
|
||||||
|
AddBootBlockFile("gpio.c", "")
|
||||||
|
AddROMStageFile("gpio.c", "")
|
||||||
|
|
||||||
|
Add_gpl(gpio)
|
||||||
|
gpio.WriteString("#include <southbridge/intel/common/gpio.h>\n\n")
|
||||||
|
|
||||||
|
addresses := [3][6]int{
|
||||||
|
{0x00, 0x04, 0x0c, 0x60, 0x2c, 0x18},
|
||||||
|
{0x30, 0x34, 0x38, 0x64, -1, -1},
|
||||||
|
{0x40, 0x44, 0x48, 0x68, -1, -1},
|
||||||
|
}
|
||||||
|
|
||||||
|
for set := 1; set <= 3; set++ {
|
||||||
|
for partno, part := range []string{"mode", "direction", "level", "reset", "invert", "blink"} {
|
||||||
|
addr := addresses[set-1][partno]
|
||||||
|
if addr < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(gpio, "static const struct pch_gpio_set%d pch_gpio_set%d_%s = {\n",
|
||||||
|
set, set, part)
|
||||||
|
|
||||||
|
constraint = 0xffffffff
|
||||||
|
switch part {
|
||||||
|
case "direction":
|
||||||
|
/* Ignored on native mode */
|
||||||
|
constraint = inteltool.GPIO[uint16(addresses[set-1][0])]
|
||||||
|
case "level":
|
||||||
|
/* Level doesn't matter for input */
|
||||||
|
constraint = inteltool.GPIO[uint16(addresses[set-1][0])]
|
||||||
|
constraint &^= inteltool.GPIO[uint16(addresses[set-1][1])]
|
||||||
|
case "reset":
|
||||||
|
/* Only show reset */
|
||||||
|
constraint = inteltool.GPIO[uint16(addresses[set-1][3])]
|
||||||
|
case "invert":
|
||||||
|
/* Only on input and only show inverted GPIO */
|
||||||
|
constraint = inteltool.GPIO[uint16(addresses[set-1][0])]
|
||||||
|
constraint &= inteltool.GPIO[uint16(addresses[set-1][1])]
|
||||||
|
constraint &= inteltool.GPIO[uint16(addresses[set-1][4])]
|
||||||
|
case "blink":
|
||||||
|
/* Only on output and only show blinking GPIO */
|
||||||
|
constraint = inteltool.GPIO[uint16(addresses[set-1][0])]
|
||||||
|
constraint &^= inteltool.GPIO[uint16(addresses[set-1][1])]
|
||||||
|
constraint &= inteltool.GPIO[uint16(addresses[set-1][5])]
|
||||||
|
}
|
||||||
|
writeGPIOSet(ctx, gpio, inteltool.GPIO[uint16(addr)], uint(set), partno, constraint)
|
||||||
|
gpio.WriteString("};\n\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio.WriteString(`const struct pch_gpio_map mainboard_gpio_map = {
|
||||||
|
.set1 = {
|
||||||
|
.mode = &pch_gpio_set1_mode,
|
||||||
|
.direction = &pch_gpio_set1_direction,
|
||||||
|
.level = &pch_gpio_set1_level,
|
||||||
|
.blink = &pch_gpio_set1_blink,
|
||||||
|
.invert = &pch_gpio_set1_invert,
|
||||||
|
.reset = &pch_gpio_set1_reset,
|
||||||
|
},
|
||||||
|
.set2 = {
|
||||||
|
.mode = &pch_gpio_set2_mode,
|
||||||
|
.direction = &pch_gpio_set2_direction,
|
||||||
|
.level = &pch_gpio_set2_level,
|
||||||
|
.reset = &pch_gpio_set2_reset,
|
||||||
|
},
|
||||||
|
.set3 = {
|
||||||
|
.mode = &pch_gpio_set3_mode,
|
||||||
|
.direction = &pch_gpio_set3_direction,
|
||||||
|
.level = &pch_gpio_set3_level,
|
||||||
|
.reset = &pch_gpio_set3_reset,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
`)
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type haswellmc struct {
|
||||||
|
variant string
|
||||||
|
}
|
||||||
|
|
||||||
|
func divceil(a uint32, b uint32) uint32 {
|
||||||
|
return (a + b - 1) / b
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPanelCfg(inteltool InteltoolData, isULT bool) string {
|
||||||
|
var refclk uint32
|
||||||
|
var pwm_hz uint32
|
||||||
|
|
||||||
|
if isULT {
|
||||||
|
refclk = 24000000
|
||||||
|
} else {
|
||||||
|
refclk = 135000000
|
||||||
|
}
|
||||||
|
if (inteltool.IGD[0xc8254] >> 16) != 0 {
|
||||||
|
pwm_hz = refclk / 128 / (inteltool.IGD[0xc8254] >> 16)
|
||||||
|
} else {
|
||||||
|
pwm_hz = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu_panel_power_up_delay := (inteltool.IGD[0xc7208] >> 16) & 0x1fff
|
||||||
|
gpu_panel_power_backlight_on_delay := inteltool.IGD[0xc7208] & 0x1fff
|
||||||
|
gpu_panel_power_down_delay := (inteltool.IGD[0xc720c] >> 16) & 0x1fff
|
||||||
|
gpu_panel_power_backlight_off_delay := inteltool.IGD[0xc720c] & 0x1fff
|
||||||
|
gpu_panel_power_cycle_delay := inteltool.IGD[0xc7210] & 0x1f
|
||||||
|
|
||||||
|
return fmt.Sprintf(`{
|
||||||
|
.up_delay_ms = %3d,
|
||||||
|
.down_delay_ms = %3d,
|
||||||
|
.cycle_delay_ms = %3d,
|
||||||
|
.backlight_on_delay_ms = %3d,
|
||||||
|
.backlight_off_delay_ms = %3d,
|
||||||
|
.backlight_pwm_hz = %3d,
|
||||||
|
}`,
|
||||||
|
divceil(gpu_panel_power_up_delay, 10),
|
||||||
|
divceil(gpu_panel_power_down_delay, 10),
|
||||||
|
(gpu_panel_power_cycle_delay-1)*100,
|
||||||
|
divceil(gpu_panel_power_backlight_on_delay, 10),
|
||||||
|
divceil(gpu_panel_power_backlight_off_delay, 10),
|
||||||
|
pwm_hz)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i haswellmc) Scan(ctx Context, addr PCIDevData) {
|
||||||
|
inteltool := ctx.InfoSource.GetInteltool()
|
||||||
|
|
||||||
|
isULT := (i.variant == "ULT")
|
||||||
|
DevTree = DevTreeNode{
|
||||||
|
Chip: "northbridge/intel/haswell",
|
||||||
|
MissingParent: "northbridge",
|
||||||
|
Comment: "FIXME: check ec_present, usb_xhci_on_resume, gfx",
|
||||||
|
Registers: map[string]string{
|
||||||
|
"gpu_dp_b_hotplug": FormatInt32((inteltool.IGD[0xc4030] >> 2) & 7),
|
||||||
|
"gpu_dp_c_hotplug": FormatInt32((inteltool.IGD[0xc4030] >> 10) & 7),
|
||||||
|
"gpu_dp_d_hotplug": FormatInt32((inteltool.IGD[0xc4030] >> 18) & 7),
|
||||||
|
"panel_cfg": getPanelCfg(inteltool, isULT),
|
||||||
|
"gpu_ddi_e_connected": FormatBool(((inteltool.IGD[0x64000] >> 4) & 1) == 0),
|
||||||
|
"ec_present": "false",
|
||||||
|
"usb_xhci_on_resume": "false",
|
||||||
|
/* FIXME:XX hardcoded. */
|
||||||
|
"gfx": "GMA_STATIC_DISPLAYS(0)",
|
||||||
|
},
|
||||||
|
Children: []DevTreeNode{
|
||||||
|
{
|
||||||
|
Chip: "cpu/intel/haswell",
|
||||||
|
Children: []DevTreeNode{
|
||||||
|
{
|
||||||
|
Chip: "cpu_cluster",
|
||||||
|
Dev: 0,
|
||||||
|
Ops: "haswell_cpu_bus_ops",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Chip: "domain",
|
||||||
|
Dev: 0,
|
||||||
|
Ops: "haswell_pci_domain_ops",
|
||||||
|
PCIController: true,
|
||||||
|
ChildPCIBus: 0,
|
||||||
|
PCISlots: []PCISlot{
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x0, Func: 0}, writeEmpty: true, additionalComment: i.variant},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1, Func: 0}, writeEmpty: !isULT, additionalComment: "PCIe Bridge for discrete graphics"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x2, Func: 0}, writeEmpty: true, additionalComment: "Internal graphics"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x3, Func: 0}, writeEmpty: true, additionalComment: "Mini-HD audio"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if isULT {
|
||||||
|
DevTree.Registers["dq_pins_interleaved"] = FormatBool(((inteltool.MCHBAR[0x2008] >> 10) & 1) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
PutPCIDev(addr, "Host bridge")
|
||||||
|
|
||||||
|
KconfigBool["NORTHBRIDGE_INTEL_HASWELL"] = true
|
||||||
|
KconfigBool["HAVE_ACPI_TABLES"] = true
|
||||||
|
KconfigBool["HAVE_ACPI_RESUME"] = true
|
||||||
|
|
||||||
|
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||||
|
File: "cpu/intel/common/acpi/cpu.asl",
|
||||||
|
})
|
||||||
|
|
||||||
|
DSDTPCI0Includes = append(DSDTPCI0Includes, DSDTInclude{
|
||||||
|
File: "northbridge/intel/haswell/acpi/hostbridge.asl",
|
||||||
|
}, DSDTInclude{
|
||||||
|
File: "drivers/intel/gma/acpi/default_brightness_levels.asl",
|
||||||
|
Comment: "FIXME: remove this if the board doesn't have backlight",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterPCI(0x8086, 0x0c00, haswellmc{variant: "Desktop"})
|
||||||
|
RegisterPCI(0x8086, 0x0c04, haswellmc{variant: "Mobile"})
|
||||||
|
RegisterPCI(0x8086, 0x0a04, haswellmc{variant: "ULT"})
|
||||||
|
RegisterPCI(0x8086, 0x0c08, haswellmc{variant: "Server"})
|
||||||
|
RegisterPCI(0x8086, 0x0d00, haswellmc{variant: "Crystal Well Desktop"})
|
||||||
|
RegisterPCI(0x8086, 0x0d04, haswellmc{variant: "Crystal Well Mobile"})
|
||||||
|
RegisterPCI(0x8086, 0x0d08, haswellmc{variant: "Crystal Well Server"})
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x0402, 0x0412, 0x0422, /* Desktop */
|
||||||
|
0x0406, 0x0416, 0x0426, /* Mobile */
|
||||||
|
0x040a, 0x041a, 0x042a, /* Server */
|
||||||
|
0x0a06, 0x0a16, 0x0a26, /* ULT */
|
||||||
|
0x0d16, 0x0d22, 0x0d26, 0x0d36, /* Mobile 4+3, GT3e */
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericVGA{GenericPCI{Comment: "VGA controller"}})
|
||||||
|
}
|
||||||
|
/* CPU HD Audio */
|
||||||
|
RegisterPCI(0x8086, 0x0a0c, GenericPCI{})
|
||||||
|
RegisterPCI(0x8086, 0x0c0c, GenericPCI{})
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TryRunAndSave(output string, name string, arg []string) error {
|
||||||
|
cmd := exec.Command(name, arg...)
|
||||||
|
|
||||||
|
f, err := os.Create(output)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Stdout = f
|
||||||
|
cmd.Stderr = f
|
||||||
|
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cmd.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunAndSave(output string, name string, arg ...string) {
|
||||||
|
err := TryRunAndSave(output, name, arg)
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
idx := strings.LastIndex(name, "/")
|
||||||
|
relname := name
|
||||||
|
if idx >= 0 {
|
||||||
|
relname = name[idx+1:]
|
||||||
|
}
|
||||||
|
relname = "./" + relname
|
||||||
|
err = TryRunAndSave(output, relname, arg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAXPROMPTRETRY = 3
|
||||||
|
|
||||||
|
func PromptUser(prompt string, opts []string) (match string, err error) {
|
||||||
|
for i := 1; i < MAXPROMPTRETRY; i++ {
|
||||||
|
fmt.Printf("%s. (%s) Default:%s\n", prompt,
|
||||||
|
strings.Join(opts, "/"), opts[0])
|
||||||
|
var usrInput string
|
||||||
|
fmt.Scanln(&usrInput)
|
||||||
|
|
||||||
|
// Check for default entry
|
||||||
|
if usrInput == "" {
|
||||||
|
match = opts[0]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
if opt == usrInput {
|
||||||
|
match = opt
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = errors.New("max retries exceeded")
|
||||||
|
fmt.Fprintln(os.Stderr, "ERROR: max retries exceeded")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeHDALogs(outDir string, cardName string) {
|
||||||
|
SysDir := "/sys/class/sound/" + cardName + "/"
|
||||||
|
files, _ := ioutil.ReadDir(SysDir)
|
||||||
|
for _, f := range files {
|
||||||
|
if (strings.HasPrefix(f.Name(), "hw") || strings.HasPrefix(f.Name(), "hdaudio")) && f.IsDir() {
|
||||||
|
in, err := os.Open(SysDir + f.Name() + "/init_pin_configs")
|
||||||
|
defer in.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
out, err := os.Create(outDir + "/pin_" + strings.Replace(f.Name(), "hdaudio", "hw", -1))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
io.Copy(out, in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcDir := "/proc/asound/" + cardName + "/"
|
||||||
|
files, _ = ioutil.ReadDir(ProcDir)
|
||||||
|
for _, f := range files {
|
||||||
|
if strings.HasPrefix(f.Name(), "codec#") && !f.IsDir() {
|
||||||
|
in, err := os.Open(ProcDir + f.Name())
|
||||||
|
defer in.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
out, err := os.Create(outDir + "/" + f.Name())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
io.Copy(out, in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeLogs(outDir string) {
|
||||||
|
os.MkdirAll(outDir, 0700)
|
||||||
|
RunAndSave(outDir+"/lspci.log", "lspci", "-nnvvvxxxx")
|
||||||
|
RunAndSave(outDir+"/dmidecode.log", "dmidecode")
|
||||||
|
RunAndSave(outDir+"/acpidump.log", "acpidump")
|
||||||
|
|
||||||
|
inteltoolArgs := "-a"
|
||||||
|
opt, err := PromptUser("WARNING: The following tool MAY cause your system to hang when it attempts "+
|
||||||
|
"to probe for graphics registers. Having the graphics registers will help create a better port. "+
|
||||||
|
"Should autoport probe these registers?",
|
||||||
|
[]string{"y", "yes", "n", "no"})
|
||||||
|
|
||||||
|
// Continue even if there is an error
|
||||||
|
|
||||||
|
switch opt {
|
||||||
|
case "y", "yes":
|
||||||
|
inteltoolArgs += "f"
|
||||||
|
}
|
||||||
|
|
||||||
|
RunAndSave(outDir+"/inteltool.log", "../inteltool/inteltool", inteltoolArgs)
|
||||||
|
RunAndSave(outDir+"/ectool.log", "../ectool/ectool", "-pd")
|
||||||
|
RunAndSave(outDir+"/superiotool.log", "../superiotool/superiotool", "-ade")
|
||||||
|
|
||||||
|
SysSound := "/sys/class/sound/"
|
||||||
|
card := ""
|
||||||
|
cards, _ := ioutil.ReadDir(SysSound)
|
||||||
|
for _, f := range cards {
|
||||||
|
if strings.HasPrefix(f.Name(), "card") {
|
||||||
|
cid, err := ioutil.ReadFile(SysSound + f.Name() + "/id")
|
||||||
|
if err == nil && bytes.Equal(cid, []byte("PCH\n")) {
|
||||||
|
fmt.Fprintln(os.Stderr, "PCH sound card is", f.Name())
|
||||||
|
card = f.Name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if card != "" {
|
||||||
|
MakeHDALogs(outDir, card)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(os.Stderr, "HDAudio not found on PCH.")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fname := range []string{"cpuinfo", "ioports"} {
|
||||||
|
in, err := os.Open("/proc/" + fname)
|
||||||
|
defer in.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
out, err := os.Create(outDir + "/" + fname + ".log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
io.Copy(out, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := os.Create(outDir + "/input_bustypes.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
ClassInputDir := "/sys/class/input/"
|
||||||
|
files, _ := ioutil.ReadDir(ClassInputDir)
|
||||||
|
for _, f := range files {
|
||||||
|
if strings.HasPrefix(f.Name(), "input") && !f.Mode().IsRegular() { /* Allow both dirs and symlinks. */
|
||||||
|
in, err := os.Open(ClassInputDir + f.Name() + "/id/bustype")
|
||||||
|
defer in.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
io.Copy(out, in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,417 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogDevReader struct {
|
||||||
|
InputDirectory string
|
||||||
|
ACPITables map[string][]byte
|
||||||
|
EC []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func isXDigit(x uint8) bool {
|
||||||
|
if x >= '0' && x <= '9' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if x >= 'a' && x <= 'f' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if x >= 'A' && x <= 'F' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type HexLine struct {
|
||||||
|
length uint
|
||||||
|
values [16]byte
|
||||||
|
start uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) ReadHexLine(line string) (hex HexLine) {
|
||||||
|
hex.start = 0
|
||||||
|
line = strings.Trim(line, " ")
|
||||||
|
fmt.Sscanf(line, "%x:", &hex.start)
|
||||||
|
ll, _ := fmt.Sscanf(line, "%x: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", &hex.start,
|
||||||
|
&hex.values[0], &hex.values[1], &hex.values[2],
|
||||||
|
&hex.values[3], &hex.values[4], &hex.values[5],
|
||||||
|
&hex.values[6], &hex.values[7], &hex.values[8],
|
||||||
|
&hex.values[9], &hex.values[10], &hex.values[11],
|
||||||
|
&hex.values[12], &hex.values[13], &hex.values[14],
|
||||||
|
&hex.values[15])
|
||||||
|
hex.length = uint(ll - 1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) AssignHexLine(inp string, target []byte) []byte {
|
||||||
|
hex := l.ReadHexLine(inp)
|
||||||
|
if hex.start+hex.length > uint(len(target)) {
|
||||||
|
target = target[0 : hex.start+hex.length]
|
||||||
|
}
|
||||||
|
copy(target[hex.start:hex.start+hex.length], hex.values[0:hex.length])
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) GetEC() []byte {
|
||||||
|
if l.EC != nil {
|
||||||
|
return l.EC
|
||||||
|
}
|
||||||
|
l.EC = make([]byte, 0x100, 0x100)
|
||||||
|
|
||||||
|
file, err := os.Open(l.InputDirectory + "/ectool.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if len(line) > 7 && isXDigit(line[0]) && isXDigit(line[1]) && line[2] == ':' {
|
||||||
|
l.EC = l.AssignHexLine(line, l.EC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return l.EC
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) GetACPI() (Tables map[string][]byte) {
|
||||||
|
if l.ACPITables != nil {
|
||||||
|
return l.ACPITables
|
||||||
|
}
|
||||||
|
l.ACPITables = Tables
|
||||||
|
|
||||||
|
file, err := os.Open(l.InputDirectory + "/acpidump.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
Tables = map[string][]byte{}
|
||||||
|
|
||||||
|
curTable := ""
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
/* Only supports ACPI tables up to 0x100000 in size, FIXME if needed */
|
||||||
|
is_hexline, _ := regexp.MatchString(" *[0-9A-Fa-f]{4,5}: ", line)
|
||||||
|
switch {
|
||||||
|
case len(line) >= 6 && line[5] == '@':
|
||||||
|
curTable = line[0:4]
|
||||||
|
Tables[curTable] = make([]byte, 0, 0x100000)
|
||||||
|
case is_hexline:
|
||||||
|
Tables[curTable] = l.AssignHexLine(line, Tables[curTable])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) GetPCIList() (PCIList []PCIDevData) {
|
||||||
|
file, err := os.Open(l.InputDirectory + "/lspci.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
PCIList = []PCIDevData{}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
switch {
|
||||||
|
case !(len(line) < 7 || !isXDigit(line[0]) || !isXDigit(line[1]) || line[2] != ':' || !isXDigit(line[3]) || !isXDigit(line[4]) || line[5] != '.' || !isXDigit(line[6])):
|
||||||
|
cur := PCIDevData{}
|
||||||
|
fmt.Sscanf(line, "%x:%x.%x", &cur.Bus, &cur.Dev, &cur.Func)
|
||||||
|
lc := strings.LastIndex(line, ":")
|
||||||
|
li := strings.LastIndex(line[0:lc], "[")
|
||||||
|
if li < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ven := 0
|
||||||
|
dev := 0
|
||||||
|
fmt.Sscanf(line[li+1:], "%x:%x", &ven, &dev)
|
||||||
|
cur.PCIDevID = uint16(dev)
|
||||||
|
cur.PCIVenID = uint16(ven)
|
||||||
|
cur.ConfigDump = make([]byte, 0x100, 0x1000)
|
||||||
|
PCIList = append(PCIList, cur)
|
||||||
|
case len(line) > 7 && isXDigit(line[0]) && line[1] == '0' && line[2] == ':':
|
||||||
|
start := 0
|
||||||
|
fmt.Sscanf(line, "%x:", &start)
|
||||||
|
cur := &PCIList[len(PCIList)-1]
|
||||||
|
cur.ConfigDump = l.AssignHexLine(line, cur.ConfigDump)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) GetInteltool() (ret InteltoolData) {
|
||||||
|
file, err := os.Open(l.InputDirectory + "/inteltool.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
paragraph := ""
|
||||||
|
ret.GPIO = map[uint16]uint32{}
|
||||||
|
ret.RCBA = map[uint16]uint32{}
|
||||||
|
ret.IOBP = map[uint32]uint32{}
|
||||||
|
ret.IGD = map[uint32]uint32{}
|
||||||
|
ret.MCHBAR = map[uint16]uint32{}
|
||||||
|
ret.PMBASE = map[uint16]uint32{}
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
switch {
|
||||||
|
case len(line) > 7 && line[0] == '0' && line[1] == 'x' && line[6] == ':' && paragraph == "RCBA":
|
||||||
|
addr, value := 0, 0
|
||||||
|
fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
|
||||||
|
ret.RCBA[uint16(addr)] = uint32(value)
|
||||||
|
case len(line) > 11 && line[0] == '0' && line[1] == 'x' && line[10] == ':' && paragraph == "IOBP":
|
||||||
|
addr, value := 0, 0
|
||||||
|
fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
|
||||||
|
ret.IOBP[uint32(addr)] = uint32(value)
|
||||||
|
case len(line) > 9 && line[0] == '0' && line[1] == 'x' && line[8] == ':' && paragraph == "IGD":
|
||||||
|
addr, value := 0, 0
|
||||||
|
fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
|
||||||
|
ret.IGD[uint32(addr)] = uint32(value)
|
||||||
|
case len(line) > 7 && line[0] == '0' && line[1] == 'x' && line[6] == ':' && paragraph == "MCHBAR":
|
||||||
|
addr, value := 0, 0
|
||||||
|
fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
|
||||||
|
ret.MCHBAR[uint16(addr)] = uint32(value)
|
||||||
|
case strings.Contains(line, "DEFAULT"):
|
||||||
|
continue
|
||||||
|
case strings.Contains(line, "DIFF"):
|
||||||
|
continue
|
||||||
|
case strings.HasPrefix(line, "gpiobase"):
|
||||||
|
addr, value := 0, 0
|
||||||
|
fmt.Sscanf(line, "gpiobase+0x%x: 0x%x", &addr, &value)
|
||||||
|
ret.GPIO[uint16(addr)] = uint32(value)
|
||||||
|
case strings.HasPrefix(line, "pmbase"):
|
||||||
|
addr, value := 0, 0
|
||||||
|
fmt.Sscanf(line, "pmbase+0x%x: 0x%x", &addr, &value)
|
||||||
|
ret.PMBASE[uint16(addr)] = uint32(value)
|
||||||
|
case strings.HasPrefix(line, "============="):
|
||||||
|
paragraph = strings.Trim(line, "= ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) GetDMI() (ret DMIData) {
|
||||||
|
file, err := os.Open(l.InputDirectory + "/dmidecode.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
paragraph := ""
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if !strings.HasPrefix(line, "\t") {
|
||||||
|
paragraph = strings.TrimSpace(line)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
idx := strings.Index(line, ":")
|
||||||
|
if idx < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := strings.TrimSpace(line[0:idx])
|
||||||
|
value := strings.TrimSpace(line[idx+1:])
|
||||||
|
switch paragraph + ":" + name {
|
||||||
|
case "System Information:Manufacturer":
|
||||||
|
ret.Vendor = value
|
||||||
|
case "System Information:Product Name":
|
||||||
|
ret.Model = value
|
||||||
|
case "System Information:Version":
|
||||||
|
ret.Version = value
|
||||||
|
case "Chassis Information:Type":
|
||||||
|
ret.IsLaptop = (value == "Notebook" || value == "Laptop")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) GetAzaliaCodecs() (ret []AzaliaCodec) {
|
||||||
|
cardno := -1
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
pin, err := os.Open(l.InputDirectory + "/pin_hwC" + strconv.Itoa(i) + "D0")
|
||||||
|
if err == nil {
|
||||||
|
pin.Close()
|
||||||
|
cardno = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cardno == -1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for codecno := 0; codecno < 10; codecno++ {
|
||||||
|
cur := AzaliaCodec{CodecNo: codecno, PinConfig: map[int]uint32{}}
|
||||||
|
codec, err := os.Open(l.InputDirectory + "/codec#" + strconv.Itoa(codecno))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer codec.Close()
|
||||||
|
pin, err := os.Open(l.InputDirectory + "/pin_hwC" + strconv.Itoa(cardno) +
|
||||||
|
"D" + strconv.Itoa(codecno))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer pin.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(codec)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if strings.HasPrefix(line, "Codec:") {
|
||||||
|
fmt.Sscanf(line, "Codec: %s", &cur.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(line, "Vendor Id:") {
|
||||||
|
fmt.Sscanf(line, "Vendor Id: 0x%x", &cur.VendorID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(line, "Subsystem Id:") {
|
||||||
|
fmt.Sscanf(line, "Subsystem Id: 0x%x", &cur.SubsystemID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner = bufio.NewScanner(pin)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
addr := 0
|
||||||
|
val := uint32(0)
|
||||||
|
fmt.Sscanf(line, "0x%x 0x%x", &addr, &val)
|
||||||
|
cur.PinConfig[addr] = val
|
||||||
|
}
|
||||||
|
ret = append(ret, cur)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) GetIOPorts() []IOPorts {
|
||||||
|
file, err := os.Open(l.InputDirectory + "/ioports.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
ret := make([]IOPorts, 0, 100)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
el := IOPorts{}
|
||||||
|
fmt.Sscanf(line, " %x-%x : %s", &el.Start, &el.End, &el.Usage)
|
||||||
|
ret = append(ret, el)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) GetCPUModel() (ret []uint32) {
|
||||||
|
file, err := os.Open(l.InputDirectory + "/cpuinfo.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
ret = make([]uint32, 0, 100)
|
||||||
|
proc := 0
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
sep := strings.Index(line, ":")
|
||||||
|
if sep < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key := strings.TrimSpace(line[0:sep])
|
||||||
|
val := strings.TrimSpace(line[sep+1:])
|
||||||
|
|
||||||
|
if key == "processor" {
|
||||||
|
proc, _ := strconv.Atoi(val)
|
||||||
|
if len(ret) <= proc {
|
||||||
|
ret = ret[0 : proc+1]
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if key == "cpu family" {
|
||||||
|
family, _ := strconv.Atoi(val)
|
||||||
|
ret[proc] |= uint32(((family & 0xf) << 8) | ((family & 0xff0) << 16))
|
||||||
|
}
|
||||||
|
if key == "model" {
|
||||||
|
model, _ := strconv.Atoi(val)
|
||||||
|
ret[proc] |= uint32(((model & 0xf) << 4) | ((model & 0xf0) << 12))
|
||||||
|
}
|
||||||
|
if key == "stepping" {
|
||||||
|
stepping, _ := strconv.Atoi(val)
|
||||||
|
ret[proc] |= uint32(stepping & 0xf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogDevReader) HasPS2() bool {
|
||||||
|
file, err := os.Open(l.InputDirectory + "/input_bustypes.log")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if strings.Index(line, "0011") >= 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var FlagLogInput = flag.String("input_log", ".", "Input log directory")
|
||||||
|
var FlagLogMkLogs = flag.Bool("make_logs", false, "Dump logs")
|
||||||
|
|
||||||
|
func MakeLogReader() *LogDevReader {
|
||||||
|
if *FlagLogMkLogs {
|
||||||
|
MakeLogs(*FlagLogInput)
|
||||||
|
}
|
||||||
|
return &LogDevReader{InputDirectory: *FlagLogInput}
|
||||||
|
}
|
|
@ -0,0 +1,490 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type LPVariant int
|
||||||
|
|
||||||
|
const (
|
||||||
|
LYNX_POINT_MOBILE LPVariant = iota
|
||||||
|
LYNX_POINT_DESKTOP
|
||||||
|
LYNX_POINT_SERVER
|
||||||
|
LYNX_POINT_ULT
|
||||||
|
)
|
||||||
|
|
||||||
|
type lynxpoint struct {
|
||||||
|
variant LPVariant
|
||||||
|
node *DevTreeNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func lpPchGetFlashSize(ctx Context) {
|
||||||
|
inteltool := ctx.InfoSource.GetInteltool()
|
||||||
|
/* In LP PCH, Boot BIOS Straps field in GCS has only one bit. */
|
||||||
|
switch (inteltool.RCBA[0x3410] >> 10) & 1 {
|
||||||
|
case 0:
|
||||||
|
ROMProtocol = "SPI"
|
||||||
|
highflkb := uint32(0)
|
||||||
|
for reg := uint16(0); reg < 5; reg++ {
|
||||||
|
fl := (inteltool.RCBA[0x3854+4*reg] >> 16) & 0x1fff
|
||||||
|
flkb := (fl + 1) << 2
|
||||||
|
if flkb > highflkb {
|
||||||
|
highflkb = flkb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ROMSizeKB = int(highflkb)
|
||||||
|
FlashROMSupport = "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b lynxpoint) GetGPIOHeader() string {
|
||||||
|
return "southbridge/intel/lynxpoint/pch.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b lynxpoint) EnableGPE(in int) {
|
||||||
|
if b.variant != LYNX_POINT_ULT {
|
||||||
|
b.node.Registers[fmt.Sprintf("gpi%d_routing", in)] = "2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b lynxpoint) EncodeGPE(in int) int {
|
||||||
|
return in + 0x10
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b lynxpoint) DecodeGPE(in int) int {
|
||||||
|
return in - 0x10
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b lynxpoint) NeedRouteGPIOManually() {
|
||||||
|
b.node.Comment += ", FIXME: set gpiX_routing for EC support"
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLptDesktopEHCISetting(loc_param uint32, txamp uint32) (string, int) {
|
||||||
|
var port_pos string
|
||||||
|
var port_length int
|
||||||
|
|
||||||
|
if loc_param == 4 {
|
||||||
|
port_pos = "USB_PORT_BACK_PANEL"
|
||||||
|
if txamp <= 2 {
|
||||||
|
port_length = 0x40
|
||||||
|
} else if txamp >= 4 {
|
||||||
|
port_length = 0x140
|
||||||
|
} else {
|
||||||
|
port_length = 0x110
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port_pos = "USB_PORT_FLEX"
|
||||||
|
port_length = 0x40
|
||||||
|
}
|
||||||
|
return port_pos, port_length
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLptMobileEHCISetting(loc_param uint32, txamp uint32) (string, int) {
|
||||||
|
var port_pos string
|
||||||
|
var port_length int
|
||||||
|
|
||||||
|
if loc_param == 4 {
|
||||||
|
port_pos = "USB_PORT_DOCK"
|
||||||
|
if txamp <= 1 {
|
||||||
|
port_length = 0x40
|
||||||
|
} else {
|
||||||
|
port_length = 0x80
|
||||||
|
}
|
||||||
|
} else if loc_param == 6 {
|
||||||
|
/* not internal, not dock, port_length >= 0x70 */
|
||||||
|
port_pos = "USB_PORT_BACK_PANEL"
|
||||||
|
if txamp <= 2 {
|
||||||
|
port_length = 0x80
|
||||||
|
} else {
|
||||||
|
port_length = 0x110
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port_pos = "USB_PORT_BACK_PANEL"
|
||||||
|
port_length = 0x40
|
||||||
|
}
|
||||||
|
return port_pos, port_length
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLptLPEHCISetting(loc_param uint32, txamp uint32) (string, int) {
|
||||||
|
var port_pos string
|
||||||
|
var port_length int
|
||||||
|
|
||||||
|
if loc_param == 6 {
|
||||||
|
/* back panel or mini pcie, length >= 0x70 */
|
||||||
|
port_pos = "USB_PORT_MINI_PCIE"
|
||||||
|
if txamp <= 2 {
|
||||||
|
port_length = 0x80
|
||||||
|
} else {
|
||||||
|
port_length = 0x110
|
||||||
|
}
|
||||||
|
} else if loc_param == 4 {
|
||||||
|
port_pos = "USB_PORT_DOCK"
|
||||||
|
if txamp <= 1 {
|
||||||
|
port_length = 0x40
|
||||||
|
} else {
|
||||||
|
port_length = 0x80
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port_pos = "USB_PORT_BACK_PANEL"
|
||||||
|
port_length = 0x40
|
||||||
|
}
|
||||||
|
return port_pos, port_length
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b lynxpoint) Scan(ctx Context, addr PCIDevData) {
|
||||||
|
|
||||||
|
SouthBridge = &b
|
||||||
|
|
||||||
|
inteltool := ctx.InfoSource.GetInteltool()
|
||||||
|
|
||||||
|
isULT := (b.variant == LYNX_POINT_ULT)
|
||||||
|
|
||||||
|
if isULT {
|
||||||
|
Lynxpoint_LP_GPIO(ctx, inteltool)
|
||||||
|
} else {
|
||||||
|
GPIO(ctx, inteltool)
|
||||||
|
}
|
||||||
|
|
||||||
|
KconfigBool["SOUTHBRIDGE_INTEL_LYNXPOINT"] = true
|
||||||
|
if isULT {
|
||||||
|
KconfigBool["INTEL_LYNXPOINT_LP"] = true
|
||||||
|
}
|
||||||
|
KconfigBool["SERIRQ_CONTINUOUS_MODE"] = true
|
||||||
|
if isULT {
|
||||||
|
KconfigInt["USBDEBUG_HCD_INDEX"] = 1
|
||||||
|
} else {
|
||||||
|
KconfigInt["USBDEBUG_HCD_INDEX"] = 2
|
||||||
|
KconfigComment["USBDEBUG_HCD_INDEX"] = "FIXME: check this"
|
||||||
|
}
|
||||||
|
|
||||||
|
if isULT {
|
||||||
|
lpPchGetFlashSize(ctx)
|
||||||
|
} else {
|
||||||
|
ich9GetFlashSize(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
FADT := ctx.InfoSource.GetACPI()["FACP"]
|
||||||
|
|
||||||
|
sp0dtle_data := (inteltool.IOBP[0xea002750] >> 24) & 0xf
|
||||||
|
sp0dtle_edge := (inteltool.IOBP[0xea002754] >> 16) & 0xf
|
||||||
|
sp1dtle_data := (inteltool.IOBP[0xea002550] >> 24) & 0xf
|
||||||
|
sp1dtle_edge := (inteltool.IOBP[0xea002554] >> 16) & 0xf
|
||||||
|
|
||||||
|
if sp0dtle_data != sp0dtle_edge {
|
||||||
|
fmt.Printf("Different SATA Gen3 port0 DTLE data and edge values are used.\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if sp1dtle_data != sp1dtle_edge {
|
||||||
|
fmt.Printf("Different SATA Gen3 port1 DTLE data and edge values are used.\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
cur := DevTreeNode{
|
||||||
|
Chip: "southbridge/intel/lynxpoint",
|
||||||
|
Comment: "Intel Series 8 Lynx Point PCH",
|
||||||
|
|
||||||
|
/* alt_gp_smi_en is not generated because coreboot doesn't use SMI like OEM firmware */
|
||||||
|
Registers: map[string]string{
|
||||||
|
"gen1_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x84:0x88]),
|
||||||
|
"gen2_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x88:0x8c]),
|
||||||
|
"gen3_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x8c:0x90]),
|
||||||
|
"gen4_dec": FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x90:0x94]),
|
||||||
|
"sata_port_map": fmt.Sprintf("0x%x", PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 2}].ConfigDump[0x92]&0x3f),
|
||||||
|
"docking_supported": (FormatBool((FADT[113] & (1 << 1)) != 0)),
|
||||||
|
"sata_port0_gen3_dtle": fmt.Sprintf("0x%x", sp0dtle_data),
|
||||||
|
"sata_port1_gen3_dtle": fmt.Sprintf("0x%x", sp1dtle_data),
|
||||||
|
},
|
||||||
|
PCISlots: []PCISlot{
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x13, Func: 0}, writeEmpty: isULT, additionalComment: "Smart Sound Audio DSP"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x14, Func: 0}, writeEmpty: true, additionalComment: "xHCI Controller"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 0}, writeEmpty: isULT, additionalComment: "Serial I/O DMA"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 1}, writeEmpty: isULT, additionalComment: "I2C0"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 2}, writeEmpty: isULT, additionalComment: "I2C1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 3}, writeEmpty: isULT, additionalComment: "GSPI0"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 4}, writeEmpty: isULT, additionalComment: "GSPI1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 5}, writeEmpty: isULT, additionalComment: "UART0"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 6}, writeEmpty: isULT, additionalComment: "UART1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 0}, writeEmpty: true, additionalComment: "Management Engine Interface 1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 1}, writeEmpty: true, additionalComment: "Management Engine Interface 2"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 2}, writeEmpty: true, additionalComment: "Management Engine IDE-R"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 3}, writeEmpty: true, additionalComment: "Management Engine KT"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x17, Func: 0}, writeEmpty: isULT, additionalComment: "SDIO"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x19, Func: 0}, writeEmpty: true, additionalComment: "Intel Gigabit Ethernet"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1a, Func: 0}, writeEmpty: !isULT, additionalComment: "USB2 EHCI #2"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1b, Func: 0}, writeEmpty: true, additionalComment: "High Definition Audio"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 0}, writeEmpty: true, additionalComment: "PCIe Port #1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 1}, writeEmpty: true, additionalComment: "PCIe Port #2"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 2}, writeEmpty: true, additionalComment: "PCIe Port #3"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 3}, writeEmpty: true, additionalComment: "PCIe Port #4"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 4}, writeEmpty: true, additionalComment: "PCIe Port #5"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 5}, writeEmpty: true, additionalComment: "PCIe Port #6"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 6}, writeEmpty: !isULT, additionalComment: "PCIe Port #7"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 7}, writeEmpty: !isULT, additionalComment: "PCIe Port #8"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1d, Func: 0}, writeEmpty: true, additionalComment: "USB2 EHCI #1"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 0}, writeEmpty: true, additionalComment: "LPC bridge"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 2}, writeEmpty: true, additionalComment: "SATA Controller (AHCI)"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 3}, writeEmpty: true, additionalComment: "SMBus"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 5}, writeEmpty: !isULT, additionalComment: "SATA Controller (Legacy)"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 6}, writeEmpty: true, additionalComment: "Thermal"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if isULT {
|
||||||
|
cur.Registers["gpe0_en_1"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x90])
|
||||||
|
cur.Registers["gpe0_en_2"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x94])
|
||||||
|
cur.Registers["gpe0_en_3"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x98])
|
||||||
|
cur.Registers["gpe0_en_4"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x9c])
|
||||||
|
} else {
|
||||||
|
cur.Registers["gpe0_en_1"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x28])
|
||||||
|
cur.Registers["gpe0_en_2"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x2c])
|
||||||
|
}
|
||||||
|
|
||||||
|
b.node = &cur
|
||||||
|
|
||||||
|
PutPCIChip(addr, cur)
|
||||||
|
PutPCIDevParent(addr, "", "lpc")
|
||||||
|
|
||||||
|
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||||
|
File: "southbridge/intel/common/acpi/platform.asl",
|
||||||
|
})
|
||||||
|
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||||
|
File: "southbridge/intel/lynxpoint/acpi/globalnvs.asl",
|
||||||
|
Comment: "global NVS and variables",
|
||||||
|
})
|
||||||
|
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||||
|
File: "southbridge/intel/common/acpi/sleepstates.asl",
|
||||||
|
})
|
||||||
|
DSDTPCI0Includes = append(DSDTPCI0Includes, DSDTInclude{
|
||||||
|
File: "southbridge/intel/lynxpoint/acpi/pch.asl",
|
||||||
|
})
|
||||||
|
|
||||||
|
AddBootBlockFile("bootblock.c", "")
|
||||||
|
bb := Create(ctx, "bootblock.c")
|
||||||
|
defer bb.Close()
|
||||||
|
Add_gpl(bb)
|
||||||
|
bb.WriteString(`#include <southbridge/intel/lynxpoint/pch.h>
|
||||||
|
|
||||||
|
/* FIXME: remove this if not needed */
|
||||||
|
void mainboard_config_superio(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
sb := Create(ctx, "romstage.c")
|
||||||
|
defer sb.Close()
|
||||||
|
Add_gpl(sb)
|
||||||
|
sb.WriteString(`#include <stdint.h>
|
||||||
|
#include <northbridge/intel/haswell/haswell.h>
|
||||||
|
#include <northbridge/intel/haswell/raminit.h>
|
||||||
|
#include <southbridge/intel/lynxpoint/pch.h>
|
||||||
|
|
||||||
|
void mainboard_config_rcba(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: called after romstage_common, remove it if not used */
|
||||||
|
void mb_late_romstage_setup(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void mb_get_spd_map(struct spd_info *spdi)
|
||||||
|
{
|
||||||
|
/* FIXME: check this */
|
||||||
|
spdi->addresses[0] = 0x50;
|
||||||
|
spdi->addresses[1] = 0x51;
|
||||||
|
spdi->addresses[2] = 0x52;
|
||||||
|
spdi->addresses[3] = 0x53;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct usb2_port_config mainboard_usb2_ports[MAX_USB2_PORTS] = {
|
||||||
|
/* FIXME: Length and Location are computed from IOBP values, may be inaccurate */
|
||||||
|
/* Length, Enable, OCn#, Location */
|
||||||
|
`)
|
||||||
|
|
||||||
|
pdo1 := PCIMap[PCIAddr{Bus: 0, Dev: 0x1d, Func: 0}].ConfigDump[0x64]
|
||||||
|
ocmap1 := PCIMap[PCIAddr{Bus: 0, Dev: 0x1d, Func: 0}].ConfigDump[0x74:0x78]
|
||||||
|
|
||||||
|
var pdo2 uint8
|
||||||
|
var ocmap2 []uint8
|
||||||
|
var nPorts uint
|
||||||
|
if isULT {
|
||||||
|
nPorts = 8
|
||||||
|
} else {
|
||||||
|
pdo2 = PCIMap[PCIAddr{Bus: 0, Dev: 0x1a, Func: 0}].ConfigDump[0x64]
|
||||||
|
ocmap2 = PCIMap[PCIAddr{Bus: 0, Dev: 0x1a, Func: 0}].ConfigDump[0x74:0x78]
|
||||||
|
nPorts = 14
|
||||||
|
}
|
||||||
|
|
||||||
|
xusb2pr := GetLE16(PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xd0:0xd4])
|
||||||
|
|
||||||
|
for port := uint(0); port < nPorts; port++ {
|
||||||
|
var port_oc int = -1
|
||||||
|
var port_pos string
|
||||||
|
var port_disable uint8
|
||||||
|
|
||||||
|
if port < 8 {
|
||||||
|
port_disable = ((pdo1 >> port) & (uint8(xusb2pr>>port) ^ 1)) & 1
|
||||||
|
for oc := 0; oc < 4; oc++ {
|
||||||
|
if (ocmap1[oc] & (1 << port)) != 0 {
|
||||||
|
port_oc = oc
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port_disable = ((pdo2 >> (port - 8)) & (uint8(xusb2pr>>port) ^ 1)) & 1
|
||||||
|
for oc := 0; oc < 4; oc++ {
|
||||||
|
if (ocmap2[oc] & (1 << (port - 8))) != 0 {
|
||||||
|
port_oc = oc + 4
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get USB2 port length and location from IOBP */
|
||||||
|
port_iobp := inteltool.IOBP[0xe5004100+uint32(port)*0x100]
|
||||||
|
loc_param := (port_iobp >> 8) & 7
|
||||||
|
txamp := (port_iobp >> 11) & 7
|
||||||
|
var port_length int
|
||||||
|
|
||||||
|
if isULT {
|
||||||
|
port_pos, port_length = GetLptLPEHCISetting(loc_param, txamp)
|
||||||
|
} else if b.variant == LYNX_POINT_MOBILE {
|
||||||
|
port_pos, port_length = GetLptMobileEHCISetting(loc_param, txamp)
|
||||||
|
} else { /* desktop or server */
|
||||||
|
port_pos, port_length = GetLptDesktopEHCISetting(loc_param, txamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if port_disable == 1 {
|
||||||
|
port_pos = "USB_PORT_SKIP"
|
||||||
|
}
|
||||||
|
|
||||||
|
if port_oc == -1 {
|
||||||
|
fmt.Fprintf(sb, "\t{ 0x%04x, %d, USB_OC_PIN_SKIP, %s },\n",
|
||||||
|
port_length, (port_disable ^ 1), port_pos)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(sb, "\t{ 0x%04x, %d, %d, %s },\n",
|
||||||
|
port_length, (port_disable ^ 1), port_oc, port_pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteString(`};
|
||||||
|
|
||||||
|
const struct usb3_port_config mainboard_usb3_ports[MAX_USB3_PORTS] = {
|
||||||
|
`)
|
||||||
|
|
||||||
|
xpdo := PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xe8]
|
||||||
|
u3ocm := PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xc8:0xd0]
|
||||||
|
|
||||||
|
if !isULT {
|
||||||
|
nPorts = 6
|
||||||
|
} else {
|
||||||
|
nPorts = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
for port := uint(0); port < nPorts; port++ {
|
||||||
|
var port_oc int = -1
|
||||||
|
port_disable := (xpdo >> port) & 1
|
||||||
|
for oc := 0; oc < 8; oc++ {
|
||||||
|
if (u3ocm[oc] & (1 << port)) != 0 {
|
||||||
|
port_oc = oc
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if port_oc == -1 {
|
||||||
|
fmt.Fprintf(sb, "\t{ %d, USB_OC_PIN_SKIP },\n",
|
||||||
|
(port_disable ^ 1))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(sb, "\t{ %d, %d },\n",
|
||||||
|
(port_disable ^ 1), port_oc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteString(`};
|
||||||
|
`)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x8c41, 0x8c49, 0x8c4b, 0x8c4f,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_MOBILE})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x8c42, 0x8c44, 0x8c46, 0x8c4a,
|
||||||
|
0x8c4c, 0x8c4e, 0x8c50, 0x8c5c,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_DESKTOP})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x8c52, 0x8c54, 0x8c56,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_SERVER})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x9c41, 0x9c43, 0x9c45,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_ULT})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PCIe bridge */
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x8c10, 0x8c12, 0x8c14, 0x8c16, 0x8c18, 0x8c1a, 0x8c1c, 0x8c1e,
|
||||||
|
0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SMBus controller */
|
||||||
|
RegisterPCI(0x8086, 0x8c22, GenericPCI{MissingParent: "smbus"})
|
||||||
|
RegisterPCI(0x8086, 0x9c22, GenericPCI{MissingParent: "smbus"})
|
||||||
|
|
||||||
|
/* SATA */
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x8c00, 0x8c02, 0x8c04, 0x8c06, 0x8c08, 0x8c0e,
|
||||||
|
0x8c01, 0x8c03, 0x8c05, 0x8c07, 0x8c09, 0x8c0f,
|
||||||
|
0x9c03, 0x9c05, 0x9c07, 0x9c0f,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EHCI */
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x9c26, 0x8c26, 0x8c2d,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XHCI */
|
||||||
|
RegisterPCI(0x8086, 0x8c31, GenericPCI{})
|
||||||
|
RegisterPCI(0x8086, 0x9c31, GenericPCI{})
|
||||||
|
|
||||||
|
/* ME and children */
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x8c3a, 0x8c3b, 0x8c3c, 0x8c3d,
|
||||||
|
0x9c3a, 0x9c3b, 0x9c3c, 0x9c3d,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ethernet */
|
||||||
|
RegisterPCI(0x8086, 0x8c33, GenericPCI{})
|
||||||
|
|
||||||
|
/* Thermal */
|
||||||
|
RegisterPCI(0x8086, 0x8c24, GenericPCI{})
|
||||||
|
RegisterPCI(0x8086, 0x9c24, GenericPCI{})
|
||||||
|
|
||||||
|
/* LAN Controller on LP PCH (if EEPROM has 0x0000/0xffff in DID) */
|
||||||
|
RegisterPCI(0x8086, 0x155a, GenericPCI{})
|
||||||
|
|
||||||
|
/* SDIO */
|
||||||
|
RegisterPCI(0x8086, 0x9c35, GenericPCI{})
|
||||||
|
|
||||||
|
/* Smart Sound Technology Controller */
|
||||||
|
RegisterPCI(0x8086, 0x9c36, GenericPCI{})
|
||||||
|
|
||||||
|
/* Serial I/O */
|
||||||
|
for id := uint16(0x9c60); id <= 0x9c66; id++ {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,252 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PIRQI = 0
|
||||||
|
PIRQJ = 1
|
||||||
|
PIRQK = 2
|
||||||
|
PIRQL = 3
|
||||||
|
PIRQM = 4
|
||||||
|
PIRQN = 5
|
||||||
|
PIRQO = 6
|
||||||
|
PIRQP = 7
|
||||||
|
PIRQQ = 8
|
||||||
|
PIRQR = 9
|
||||||
|
PIRQS = 10
|
||||||
|
PIRQT = 11
|
||||||
|
PIRQU = 12
|
||||||
|
PIRQV = 13
|
||||||
|
PIRQW = 14
|
||||||
|
PIRQX = 15
|
||||||
|
)
|
||||||
|
|
||||||
|
/* from sb/intel/lynxpoint/lp_gpio.c */
|
||||||
|
func lp_gpio_to_pirq(gpioNum uint16) int {
|
||||||
|
switch gpioNum {
|
||||||
|
case 8:
|
||||||
|
return PIRQI
|
||||||
|
case 9:
|
||||||
|
return PIRQJ
|
||||||
|
case 10:
|
||||||
|
return PIRQK
|
||||||
|
case 13:
|
||||||
|
return PIRQL
|
||||||
|
case 14:
|
||||||
|
return PIRQM
|
||||||
|
case 45:
|
||||||
|
return PIRQN
|
||||||
|
case 46:
|
||||||
|
return PIRQO
|
||||||
|
case 47:
|
||||||
|
return PIRQP
|
||||||
|
case 48:
|
||||||
|
return PIRQQ
|
||||||
|
case 49:
|
||||||
|
return PIRQR
|
||||||
|
case 50:
|
||||||
|
return PIRQS
|
||||||
|
case 51:
|
||||||
|
return PIRQT
|
||||||
|
case 52:
|
||||||
|
return PIRQU
|
||||||
|
case 53:
|
||||||
|
return PIRQV
|
||||||
|
case 54:
|
||||||
|
return PIRQW
|
||||||
|
case 55:
|
||||||
|
return PIRQX
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func conf0str(conf0 uint32) string {
|
||||||
|
if (conf0 & 1) == 0 {
|
||||||
|
return "GPIO_MODE_NATIVE"
|
||||||
|
} else {
|
||||||
|
s := []string{"GPIO_MODE_GPIO"}
|
||||||
|
var gpio_output bool
|
||||||
|
if ((conf0 >> 2) & 1) == 1 {
|
||||||
|
s = append(s, "GPIO_DIR_INPUT")
|
||||||
|
gpio_output = false
|
||||||
|
} else {
|
||||||
|
s = append(s, "GPIO_DIR_OUTPUT")
|
||||||
|
gpio_output = true
|
||||||
|
}
|
||||||
|
if ((conf0 >> 3) & 1) == 1 {
|
||||||
|
s = append(s, "GPIO_INVERT")
|
||||||
|
}
|
||||||
|
if ((conf0 >> 4) & 1) == 1 {
|
||||||
|
s = append(s, "GPIO_IRQ_LEVEL")
|
||||||
|
}
|
||||||
|
if gpio_output {
|
||||||
|
if ((conf0 >> 31) & 1) == 1 {
|
||||||
|
s = append(s, "GPO_LEVEL_HIGH")
|
||||||
|
} else {
|
||||||
|
s = append(s, "GPO_LEVEL_LOW")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(s, " | ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lpgpio_preset(conf0 uint32, owner uint32, route uint32, irqen uint32, pirq uint32) string {
|
||||||
|
if conf0 == 0xd { /* 0b1101: MODE_GPIO | INPUT | INVERT */
|
||||||
|
if owner == 0 { /* OWNER_ACPI */
|
||||||
|
if irqen == 0 && pirq == 0 {
|
||||||
|
if route == 0 { /* SCI */
|
||||||
|
return "GPIO_ACPI_SCI"
|
||||||
|
} else {
|
||||||
|
return "GPIO_ACPI_SMI"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
} else { /* OWNER_GPIO */
|
||||||
|
if route == 0 && irqen == 0 && pirq != 0 {
|
||||||
|
return "GPIO_INPUT_INVERT"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf0 == 0x5 && owner == 1 { /* 0b101: MODE_GPIO | INPUT, OWNER_GPIO */
|
||||||
|
if route == 0 && irqen == 0 {
|
||||||
|
if pirq == 1 {
|
||||||
|
return "GPIO_PIRQ"
|
||||||
|
} else {
|
||||||
|
return "GPIO_INPUT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if owner == 1 && irqen == 1 {
|
||||||
|
if route == 0 && pirq == 0 {
|
||||||
|
if conf0 == 0x5 { /* 0b00101 */
|
||||||
|
return "GPIO_IRQ_EDGE"
|
||||||
|
}
|
||||||
|
if conf0 == 0x15 { /* 0b10101 */
|
||||||
|
return "GPIO_IRQ_LEVEL"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func gpio_str(conf0 uint32, conf1 uint32, owner uint32, route uint32, irqen uint32, reset uint32, blink uint32, pirq uint32) string {
|
||||||
|
s := []string{}
|
||||||
|
s = append(s, fmt.Sprintf(".conf0 = %s", conf0str(conf0)))
|
||||||
|
if conf1 != 0 {
|
||||||
|
s = append(s, fmt.Sprintf(".conf1 = 0x%x", conf1))
|
||||||
|
}
|
||||||
|
if owner != 0 {
|
||||||
|
s = append(s, ".owner = GPIO_OWNER_GPIO")
|
||||||
|
}
|
||||||
|
if route != 0 {
|
||||||
|
s = append(s, ".route = GPIO_ROUTE_SMI")
|
||||||
|
}
|
||||||
|
if irqen != 0 {
|
||||||
|
s = append(s, ".irqen = GPIO_IRQ_ENABLE")
|
||||||
|
}
|
||||||
|
if reset != 0 {
|
||||||
|
s = append(s, ".reset = GPIO_RESET_RSMRST")
|
||||||
|
}
|
||||||
|
if blink != 0 {
|
||||||
|
s = append(s, ".blink = GPO_BLINK")
|
||||||
|
}
|
||||||
|
if pirq != 0 {
|
||||||
|
s = append(s, ".pirq = GPIO_PIRQ_APIC_ROUTE")
|
||||||
|
}
|
||||||
|
return strings.Join(s, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start addresses of GPIO registers */
|
||||||
|
const (
|
||||||
|
GPIO_OWN = 0x0
|
||||||
|
GPIPIRQ2IOXAPIC = 0x10
|
||||||
|
GPO_BLINK = 0x18
|
||||||
|
GPI_ROUT = 0x30
|
||||||
|
GP_RST_SEL = 0x60
|
||||||
|
GPI_IE = 0x90
|
||||||
|
GPnCONFIGA = 0x100
|
||||||
|
GPnCONFIGB = 0x104
|
||||||
|
)
|
||||||
|
|
||||||
|
func PrintLPGPIO(gpio *os.File, inteltool InteltoolData) {
|
||||||
|
for gpioNum := uint16(0); gpioNum <= 94; gpioNum++ {
|
||||||
|
if gpioNum < 10 {
|
||||||
|
fmt.Fprintf(gpio, "\t[%d] = ", gpioNum)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(gpio, "\t[%d] = ", gpioNum)
|
||||||
|
}
|
||||||
|
conf0 := inteltool.GPIO[GPnCONFIGA+gpioNum*8]
|
||||||
|
conf1 := inteltool.GPIO[GPnCONFIGB+gpioNum*8]
|
||||||
|
set := gpioNum / 32
|
||||||
|
bit := gpioNum % 32
|
||||||
|
/* owner only effective in GPIO mode */
|
||||||
|
owner := (inteltool.GPIO[GPIO_OWN+set*4] >> bit) & 1
|
||||||
|
route := (inteltool.GPIO[GPI_ROUT+set*4] >> bit) & 1
|
||||||
|
irqen := (inteltool.GPIO[GPI_IE+set*4] >> bit) & 1
|
||||||
|
reset := (inteltool.GPIO[GP_RST_SEL+set*4] >> bit) & 1
|
||||||
|
var blink, pirq uint32
|
||||||
|
/* blink only effective in GPIO output mode */
|
||||||
|
if set == 0 {
|
||||||
|
blink = (inteltool.GPIO[GPO_BLINK] >> bit) & 1
|
||||||
|
} else {
|
||||||
|
blink = 0
|
||||||
|
}
|
||||||
|
irqset := lp_gpio_to_pirq(gpioNum)
|
||||||
|
if irqset >= 0 {
|
||||||
|
pirq = (inteltool.GPIO[GPIPIRQ2IOXAPIC] >> uint(irqset)) & 1
|
||||||
|
} else {
|
||||||
|
pirq = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf0 & 1) == 0 {
|
||||||
|
fmt.Fprintf(gpio, "LP_GPIO_NATIVE,\n")
|
||||||
|
} else if (conf0 & 4) == 0 {
|
||||||
|
/* configured as output */
|
||||||
|
if ((conf0 >> 31) & 1) == 0 {
|
||||||
|
fmt.Fprintf(gpio, "LP_GPIO_OUT_LOW,\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(gpio, "LP_GPIO_OUT_HIGH,\n")
|
||||||
|
}
|
||||||
|
} else if (conf1 & 4) != 0 {
|
||||||
|
/* configured as input and sensing disabled */
|
||||||
|
fmt.Fprintf(gpio, "LP_GPIO_UNUSED,\n")
|
||||||
|
} else {
|
||||||
|
is_preset := false
|
||||||
|
if conf1 == 0 && reset == 0 && blink == 0 {
|
||||||
|
preset := lpgpio_preset(conf0, owner, route, irqen, pirq)
|
||||||
|
if preset != "" {
|
||||||
|
fmt.Fprintf(gpio, "LP_%s,\n", preset)
|
||||||
|
is_preset = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !is_preset {
|
||||||
|
fmt.Fprintf(gpio, "{ %s },\n", gpio_str(conf0, conf1, owner, route, irqen, reset, blink, pirq))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Lynxpoint_LP_GPIO(ctx Context, inteltool InteltoolData) {
|
||||||
|
gpio := Create(ctx, "gpio.c")
|
||||||
|
defer gpio.Close()
|
||||||
|
|
||||||
|
AddROMStageFile("gpio.c", "")
|
||||||
|
|
||||||
|
Add_gpl(gpio)
|
||||||
|
gpio.WriteString(`#include <southbridge/intel/lynxpoint/lp_gpio.h>
|
||||||
|
|
||||||
|
const struct pch_lp_gpio_map mainboard_lp_gpio_map[] = {
|
||||||
|
`)
|
||||||
|
PrintLPGPIO(gpio, inteltool)
|
||||||
|
gpio.WriteString("\tLP_GPIO_END\n};\n")
|
||||||
|
}
|
|
@ -0,0 +1,915 @@
|
||||||
|
/* This is just an experiment. Full automatic porting
|
||||||
|
is probably not possible but a lot can be automated. */
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PCIAddr struct {
|
||||||
|
Bus int
|
||||||
|
Dev int
|
||||||
|
Func int
|
||||||
|
}
|
||||||
|
|
||||||
|
type PCIDevData struct {
|
||||||
|
PCIAddr
|
||||||
|
PCIVenID uint16
|
||||||
|
PCIDevID uint16
|
||||||
|
ConfigDump []uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type PCIDevice interface {
|
||||||
|
Scan(ctx Context, addr PCIDevData)
|
||||||
|
}
|
||||||
|
|
||||||
|
type InteltoolData struct {
|
||||||
|
GPIO map[uint16]uint32
|
||||||
|
RCBA map[uint16]uint32
|
||||||
|
IOBP map[uint32]uint32
|
||||||
|
IGD map[uint32]uint32
|
||||||
|
MCHBAR map[uint16]uint32
|
||||||
|
PMBASE map[uint16]uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type DMIData struct {
|
||||||
|
Vendor string
|
||||||
|
Model string
|
||||||
|
Version string
|
||||||
|
IsLaptop bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type AzaliaCodec struct {
|
||||||
|
Name string
|
||||||
|
VendorID uint32
|
||||||
|
SubsystemID uint32
|
||||||
|
CodecNo int
|
||||||
|
PinConfig map[int]uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type DevReader interface {
|
||||||
|
GetPCIList() []PCIDevData
|
||||||
|
GetDMI() DMIData
|
||||||
|
GetInteltool() InteltoolData
|
||||||
|
GetAzaliaCodecs() []AzaliaCodec
|
||||||
|
GetACPI() map[string][]byte
|
||||||
|
GetCPUModel() []uint32
|
||||||
|
GetEC() []byte
|
||||||
|
GetIOPorts() []IOPorts
|
||||||
|
HasPS2() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type IOPorts struct {
|
||||||
|
Start uint16
|
||||||
|
End uint16
|
||||||
|
Usage string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SouthBridger interface {
|
||||||
|
GetGPIOHeader() string
|
||||||
|
EncodeGPE(int) int
|
||||||
|
DecodeGPE(int) int
|
||||||
|
EnableGPE(int)
|
||||||
|
NeedRouteGPIOManually()
|
||||||
|
}
|
||||||
|
|
||||||
|
var SouthBridge SouthBridger
|
||||||
|
var BootBlockFiles map[string]string = map[string]string{}
|
||||||
|
var ROMStageFiles map[string]string = map[string]string{}
|
||||||
|
var RAMStageFiles map[string]string = map[string]string{}
|
||||||
|
var SMMFiles map[string]string = map[string]string{}
|
||||||
|
var MainboardInit string
|
||||||
|
var MainboardEnable string
|
||||||
|
var MainboardIncludes []string
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
MoboID string
|
||||||
|
KconfigName string
|
||||||
|
Vendor string
|
||||||
|
Model string
|
||||||
|
BaseDirectory string
|
||||||
|
InfoSource DevReader
|
||||||
|
SaneVendor string
|
||||||
|
}
|
||||||
|
|
||||||
|
type IOAPICIRQ struct {
|
||||||
|
APICID int
|
||||||
|
IRQNO [4]int
|
||||||
|
}
|
||||||
|
|
||||||
|
var IOAPICIRQs map[PCIAddr]IOAPICIRQ = map[PCIAddr]IOAPICIRQ{}
|
||||||
|
var KconfigBool map[string]bool = map[string]bool{}
|
||||||
|
var KconfigComment map[string]string = map[string]string{}
|
||||||
|
var KconfigString map[string]string = map[string]string{}
|
||||||
|
var KconfigHex map[string]uint32 = map[string]uint32{}
|
||||||
|
var KconfigInt map[string]int = map[string]int{}
|
||||||
|
var ROMSizeKB = 0
|
||||||
|
var ROMProtocol = ""
|
||||||
|
var FlashROMSupport = ""
|
||||||
|
|
||||||
|
func GetLE16(inp []byte) uint16 {
|
||||||
|
return uint16(inp[0]) | (uint16(inp[1]) << 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatHexLE16(inp []byte) string {
|
||||||
|
return fmt.Sprintf("0x%04x", GetLE16(inp))
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatHex32(u uint32) string {
|
||||||
|
return fmt.Sprintf("0x%08x", u)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatHex8(u uint8) string {
|
||||||
|
return fmt.Sprintf("0x%02x", u)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatInt32(u uint32) string {
|
||||||
|
return fmt.Sprintf("%d", u)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatHexLE32(d []uint8) string {
|
||||||
|
u := uint32(d[0]) | (uint32(d[1]) << 8) | (uint32(d[2]) << 16) | (uint32(d[3]) << 24)
|
||||||
|
return FormatHex32(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatBool(inp bool) string {
|
||||||
|
if inp {
|
||||||
|
return "1"
|
||||||
|
} else {
|
||||||
|
return "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitize(inp string) string {
|
||||||
|
result := strings.ToLower(inp)
|
||||||
|
result = strings.Replace(result, " ", "_", -1)
|
||||||
|
result = strings.Replace(result, ",", "_", -1)
|
||||||
|
result = strings.Replace(result, "-", "_", -1)
|
||||||
|
for strings.HasSuffix(result, ".") {
|
||||||
|
result = result[0 : len(result)-1]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddBootBlockFile(Name string, Condition string) {
|
||||||
|
BootBlockFiles[Name] = Condition
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddROMStageFile(Name string, Condition string) {
|
||||||
|
ROMStageFiles[Name] = Condition
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddRAMStageFile(Name string, Condition string) {
|
||||||
|
RAMStageFiles[Name] = Condition
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddSMMFile(Name string, Condition string) {
|
||||||
|
SMMFiles[Name] = Condition
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsIOPortUsedBy(ctx Context, port uint16, name string) bool {
|
||||||
|
for _, io := range ctx.InfoSource.GetIOPorts() {
|
||||||
|
if io.Start <= port && port <= io.End && io.Usage == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var FlagOutDir = flag.String("coreboot_dir", ".", "Resulting coreboot directory")
|
||||||
|
|
||||||
|
func writeMF(mf *os.File, files map[string]string, category string) {
|
||||||
|
keys := []string{}
|
||||||
|
for file, _ := range files {
|
||||||
|
keys = append(keys, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, file := range keys {
|
||||||
|
condition := files[file]
|
||||||
|
if condition == "" {
|
||||||
|
fmt.Fprintf(mf, "%s-y += %s\n", category, file)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(mf, "%s-$(%s) += %s\n", category, condition, file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Create(ctx Context, name string) *os.File {
|
||||||
|
li := strings.LastIndex(name, "/")
|
||||||
|
if li > 0 {
|
||||||
|
os.MkdirAll(ctx.BaseDirectory+"/"+name[0:li], 0700)
|
||||||
|
}
|
||||||
|
mf, err := os.Create(ctx.BaseDirectory + "/" + name)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return mf
|
||||||
|
}
|
||||||
|
|
||||||
|
func Add_gpl(f *os.File) {
|
||||||
|
fmt.Fprintln(f, "/* SPDX-License-Identifier: GPL-2.0-only */")
|
||||||
|
fmt.Fprintln(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestorePCI16Simple(f *os.File, pcidev PCIDevData, addr uint16) {
|
||||||
|
fmt.Fprintf(f, " pci_write_config16(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x);\n",
|
||||||
|
pcidev.Bus, pcidev.Dev, pcidev.Func, addr,
|
||||||
|
pcidev.ConfigDump[addr+1],
|
||||||
|
pcidev.ConfigDump[addr])
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestorePCI32Simple(f *os.File, pcidev PCIDevData, addr uint16) {
|
||||||
|
fmt.Fprintf(f, " pci_write_config32(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x%02x%02x);\n",
|
||||||
|
pcidev.Bus, pcidev.Dev, pcidev.Func, addr,
|
||||||
|
pcidev.ConfigDump[addr+3],
|
||||||
|
pcidev.ConfigDump[addr+2],
|
||||||
|
pcidev.ConfigDump[addr+1],
|
||||||
|
pcidev.ConfigDump[addr])
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestoreRCBA32(f *os.File, inteltool InteltoolData, addr uint16) {
|
||||||
|
fmt.Fprintf(f, "\tRCBA32(0x%04x) = 0x%08x;\n", addr, inteltool.RCBA[addr])
|
||||||
|
}
|
||||||
|
|
||||||
|
type PCISlot struct {
|
||||||
|
PCIAddr
|
||||||
|
alias string
|
||||||
|
additionalComment string
|
||||||
|
writeEmpty bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type DevTreeNode struct {
|
||||||
|
Bus int
|
||||||
|
Dev int
|
||||||
|
Func int
|
||||||
|
Disabled bool
|
||||||
|
Registers map[string]string
|
||||||
|
IOs map[uint16]uint16
|
||||||
|
Children []DevTreeNode
|
||||||
|
PCISlots []PCISlot
|
||||||
|
PCIController bool
|
||||||
|
ChildPCIBus int
|
||||||
|
MissingParent string
|
||||||
|
SubVendor uint16
|
||||||
|
SubSystem uint16
|
||||||
|
Chip string
|
||||||
|
Ops string
|
||||||
|
Comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
var DevTree DevTreeNode
|
||||||
|
var MissingChildren map[string][]DevTreeNode = map[string][]DevTreeNode{}
|
||||||
|
var unmatchedPCIChips map[PCIAddr]DevTreeNode = map[PCIAddr]DevTreeNode{}
|
||||||
|
var unmatchedPCIDevices map[PCIAddr]DevTreeNode = map[PCIAddr]DevTreeNode{}
|
||||||
|
|
||||||
|
func Offset(dt *os.File, offset int) {
|
||||||
|
for i := 0; i < offset; i++ {
|
||||||
|
fmt.Fprintf(dt, "\t")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MatchDev(dev *DevTreeNode) {
|
||||||
|
for idx := range dev.Children {
|
||||||
|
MatchDev(&dev.Children[idx])
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, slot := range dev.PCISlots {
|
||||||
|
slotChip, ok := unmatchedPCIChips[slot.PCIAddr]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if slot.additionalComment != "" && slotChip.Comment != "" {
|
||||||
|
slotChip.Comment = slot.additionalComment + " " + slotChip.Comment
|
||||||
|
} else {
|
||||||
|
slotChip.Comment = slot.additionalComment + slotChip.Comment
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(unmatchedPCIChips, slot.PCIAddr)
|
||||||
|
MatchDev(&slotChip)
|
||||||
|
dev.Children = append(dev.Children, slotChip)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dev.PCIController {
|
||||||
|
for slot, slotDev := range unmatchedPCIChips {
|
||||||
|
if slot.Bus == dev.ChildPCIBus {
|
||||||
|
delete(unmatchedPCIChips, slot)
|
||||||
|
MatchDev(&slotDev)
|
||||||
|
dev.Children = append(dev.Children, slotDev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, slot := range dev.PCISlots {
|
||||||
|
slotDev, ok := unmatchedPCIDevices[slot.PCIAddr]
|
||||||
|
if !ok {
|
||||||
|
if slot.writeEmpty {
|
||||||
|
dev.Children = append(dev.Children,
|
||||||
|
DevTreeNode{
|
||||||
|
Registers: map[string]string{},
|
||||||
|
Chip: "pci",
|
||||||
|
Bus: slot.Bus,
|
||||||
|
Dev: slot.Dev,
|
||||||
|
Func: slot.Func,
|
||||||
|
Comment: slot.additionalComment,
|
||||||
|
Disabled: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if slot.additionalComment != "" && slotDev.Comment != "" {
|
||||||
|
slotDev.Comment = slot.additionalComment + " " + slotDev.Comment
|
||||||
|
} else {
|
||||||
|
slotDev.Comment = slot.additionalComment + slotDev.Comment
|
||||||
|
}
|
||||||
|
|
||||||
|
MatchDev(&slotDev)
|
||||||
|
dev.Children = append(dev.Children, slotDev)
|
||||||
|
delete(unmatchedPCIDevices, slot.PCIAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dev.MissingParent != "" {
|
||||||
|
for _, child := range MissingChildren[dev.MissingParent] {
|
||||||
|
MatchDev(&child)
|
||||||
|
dev.Children = append(dev.Children, child)
|
||||||
|
}
|
||||||
|
delete(MissingChildren, dev.MissingParent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dev.PCIController {
|
||||||
|
for slot, slotDev := range unmatchedPCIDevices {
|
||||||
|
if slot.Bus == dev.ChildPCIBus {
|
||||||
|
MatchDev(&slotDev)
|
||||||
|
dev.Children = append(dev.Children, slotDev)
|
||||||
|
delete(unmatchedPCIDevices, slot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeOn(dt *os.File, dev DevTreeNode) {
|
||||||
|
if dev.Disabled {
|
||||||
|
fmt.Fprintf(dt, "off")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(dt, "on")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteDev(dt *os.File, offset int, alias string, dev DevTreeNode) {
|
||||||
|
Offset(dt, offset)
|
||||||
|
switch dev.Chip {
|
||||||
|
case "cpu_cluster", "lapic", "domain", "ioapic":
|
||||||
|
fmt.Fprintf(dt, "device %s 0x%x ", dev.Chip, dev.Dev)
|
||||||
|
writeOn(dt, dev)
|
||||||
|
case "pci", "pnp":
|
||||||
|
if alias != "" {
|
||||||
|
fmt.Fprintf(dt, "device ref %s ", alias)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(dt, "device %s %02x.%x ", dev.Chip, dev.Dev, dev.Func)
|
||||||
|
}
|
||||||
|
writeOn(dt, dev)
|
||||||
|
case "i2c":
|
||||||
|
fmt.Fprintf(dt, "device %s %02x ", dev.Chip, dev.Dev)
|
||||||
|
writeOn(dt, dev)
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(dt, "chip %s", dev.Chip)
|
||||||
|
}
|
||||||
|
if dev.Comment != "" {
|
||||||
|
fmt.Fprintf(dt, " # %s", dev.Comment)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(dt, "\n")
|
||||||
|
if dev.Ops != "" {
|
||||||
|
Offset(dt, offset+1)
|
||||||
|
fmt.Fprintf(dt, "ops %s\n", dev.Ops)
|
||||||
|
}
|
||||||
|
if dev.Chip == "pci" && dev.SubSystem != 0 && dev.SubVendor != 0 {
|
||||||
|
Offset(dt, offset+1)
|
||||||
|
fmt.Fprintf(dt, "subsystemid 0x%04x 0x%04x\n", dev.SubVendor, dev.SubSystem)
|
||||||
|
}
|
||||||
|
|
||||||
|
ioapic, ok := IOAPICIRQs[PCIAddr{Bus: dev.Bus, Dev: dev.Dev, Func: dev.Func}]
|
||||||
|
if dev.Chip == "pci" && ok {
|
||||||
|
for pin, irq := range ioapic.IRQNO {
|
||||||
|
if irq != 0 {
|
||||||
|
Offset(dt, offset+1)
|
||||||
|
fmt.Fprintf(dt, "ioapic_irq %d INT%c 0x%x\n", ioapic.APICID, 'A'+pin, irq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := []string{}
|
||||||
|
for reg, _ := range dev.Registers {
|
||||||
|
keys = append(keys, reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, reg := range keys {
|
||||||
|
val := dev.Registers[reg]
|
||||||
|
Offset(dt, offset+1)
|
||||||
|
fmt.Fprintf(dt, "register \"%s\" = \"%s\"\n", reg, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
ios := []int{}
|
||||||
|
for reg, _ := range dev.IOs {
|
||||||
|
ios = append(ios, int(reg))
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Ints(ios)
|
||||||
|
|
||||||
|
for _, reg := range ios {
|
||||||
|
val := dev.IOs[uint16(reg)]
|
||||||
|
Offset(dt, offset+1)
|
||||||
|
fmt.Fprintf(dt, "io 0x%x = 0x%x\n", reg, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, child := range dev.Children {
|
||||||
|
alias = ""
|
||||||
|
for _, slot := range dev.PCISlots {
|
||||||
|
if slot.PCIAddr.Bus == child.Bus &&
|
||||||
|
slot.PCIAddr.Dev == child.Dev && slot.PCIAddr.Func == child.Func {
|
||||||
|
alias = slot.alias
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WriteDev(dt, offset+1, alias, child)
|
||||||
|
}
|
||||||
|
|
||||||
|
Offset(dt, offset)
|
||||||
|
fmt.Fprintf(dt, "end\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutChip(domain string, cur DevTreeNode) {
|
||||||
|
MissingChildren[domain] = append(MissingChildren[domain], cur)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutPCIChip(addr PCIDevData, cur DevTreeNode) {
|
||||||
|
unmatchedPCIChips[addr.PCIAddr] = cur
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutPCIDevParent(addr PCIDevData, comment string, parent string) {
|
||||||
|
cur := DevTreeNode{
|
||||||
|
Registers: map[string]string{},
|
||||||
|
Chip: "pci",
|
||||||
|
Bus: addr.Bus,
|
||||||
|
Dev: addr.Dev,
|
||||||
|
Func: addr.Func,
|
||||||
|
MissingParent: parent,
|
||||||
|
Comment: comment,
|
||||||
|
}
|
||||||
|
if addr.ConfigDump[0xa] == 0x04 && addr.ConfigDump[0xb] == 0x06 {
|
||||||
|
cur.PCIController = true
|
||||||
|
cur.ChildPCIBus = int(addr.ConfigDump[0x19])
|
||||||
|
|
||||||
|
loopCtr := 0
|
||||||
|
for capPtr := addr.ConfigDump[0x34]; capPtr != 0; capPtr = addr.ConfigDump[capPtr+1] {
|
||||||
|
/* Avoid hangs. There are only 0x100 different possible values for capPtr.
|
||||||
|
If we iterate longer than that, we're in endless loop. */
|
||||||
|
loopCtr++
|
||||||
|
if loopCtr > 0x100 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if addr.ConfigDump[capPtr] == 0x0d {
|
||||||
|
cur.SubVendor = GetLE16(addr.ConfigDump[capPtr+4 : capPtr+6])
|
||||||
|
cur.SubSystem = GetLE16(addr.ConfigDump[capPtr+6 : capPtr+8])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cur.SubVendor = GetLE16(addr.ConfigDump[0x2c:0x2e])
|
||||||
|
cur.SubSystem = GetLE16(addr.ConfigDump[0x2e:0x30])
|
||||||
|
}
|
||||||
|
unmatchedPCIDevices[addr.PCIAddr] = cur
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutPCIDev(addr PCIDevData, comment string) {
|
||||||
|
PutPCIDevParent(addr, comment, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenericPCI struct {
|
||||||
|
Comment string
|
||||||
|
Bus0Subdiv string
|
||||||
|
MissingParent string
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenericVGA struct {
|
||||||
|
GenericPCI
|
||||||
|
}
|
||||||
|
|
||||||
|
type DSDTInclude struct {
|
||||||
|
Comment string
|
||||||
|
File string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DSDTDefine struct {
|
||||||
|
Key string
|
||||||
|
Comment string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
var DSDTIncludes []DSDTInclude
|
||||||
|
var DSDTPCI0Includes []DSDTInclude
|
||||||
|
var DSDTDefines []DSDTDefine
|
||||||
|
|
||||||
|
func (g GenericPCI) Scan(ctx Context, addr PCIDevData) {
|
||||||
|
PutPCIDevParent(addr, g.Comment, g.MissingParent)
|
||||||
|
}
|
||||||
|
|
||||||
|
var IGDEnabled bool = false
|
||||||
|
|
||||||
|
func (g GenericVGA) Scan(ctx Context, addr PCIDevData) {
|
||||||
|
KconfigString["VGA_BIOS_ID"] = fmt.Sprintf("%04x,%04x",
|
||||||
|
addr.PCIVenID,
|
||||||
|
addr.PCIDevID)
|
||||||
|
PutPCIDevParent(addr, g.Comment, g.MissingParent)
|
||||||
|
IGDEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeKconfigName(ctx Context) {
|
||||||
|
kn := Create(ctx, "Kconfig.name")
|
||||||
|
defer kn.Close()
|
||||||
|
|
||||||
|
fmt.Fprintf(kn, "config %s\n\tbool \"%s\"\n", ctx.KconfigName, ctx.Model)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeComment(name string) string {
|
||||||
|
cmt, ok := KconfigComment[name]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return " # " + cmt
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeKconfig(ctx Context) {
|
||||||
|
kc := Create(ctx, "Kconfig")
|
||||||
|
defer kc.Close()
|
||||||
|
|
||||||
|
fmt.Fprintf(kc, "if %s\n\n", ctx.KconfigName)
|
||||||
|
|
||||||
|
fmt.Fprintf(kc, "config BOARD_SPECIFIC_OPTIONS\n\tdef_bool y\n")
|
||||||
|
keys := []string{}
|
||||||
|
for name, val := range KconfigBool {
|
||||||
|
if val {
|
||||||
|
keys = append(keys, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, name := range keys {
|
||||||
|
fmt.Fprintf(kc, "\tselect %s%s\n", name, makeComment(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = nil
|
||||||
|
for name, val := range KconfigBool {
|
||||||
|
if !val {
|
||||||
|
keys = append(keys, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, name := range keys {
|
||||||
|
fmt.Fprintf(kc, `
|
||||||
|
config %s%s
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
`, name, makeComment(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = nil
|
||||||
|
for name, _ := range KconfigString {
|
||||||
|
keys = append(keys, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, name := range keys {
|
||||||
|
fmt.Fprintf(kc, `
|
||||||
|
config %s%s
|
||||||
|
string
|
||||||
|
default "%s"
|
||||||
|
`, name, makeComment(name), KconfigString[name])
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = nil
|
||||||
|
for name, _ := range KconfigHex {
|
||||||
|
keys = append(keys, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, name := range keys {
|
||||||
|
fmt.Fprintf(kc, `
|
||||||
|
config %s%s
|
||||||
|
hex
|
||||||
|
default 0x%x
|
||||||
|
`, name, makeComment(name), KconfigHex[name])
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = nil
|
||||||
|
for name, _ := range KconfigInt {
|
||||||
|
keys = append(keys, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, name := range keys {
|
||||||
|
fmt.Fprintf(kc, `
|
||||||
|
config %s%s
|
||||||
|
int
|
||||||
|
default %d
|
||||||
|
`, name, makeComment(name), KconfigInt[name])
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(kc, "endif\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
const MoboDir = "/src/mainboard/"
|
||||||
|
|
||||||
|
func makeVendor(ctx Context) {
|
||||||
|
vendor := ctx.Vendor
|
||||||
|
vendorSane := ctx.SaneVendor
|
||||||
|
vendorDir := *FlagOutDir + MoboDir + vendorSane
|
||||||
|
vendorUpper := strings.ToUpper(vendorSane)
|
||||||
|
kconfig := vendorDir + "/Kconfig"
|
||||||
|
if _, err := os.Stat(kconfig); os.IsNotExist(err) {
|
||||||
|
f, err := os.Create(kconfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
f.WriteString(`if VENDOR_` + vendorUpper + `
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Mainboard model"
|
||||||
|
|
||||||
|
source "src/mainboard/` + vendorSane + `/*/Kconfig.name"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
source "src/mainboard/` + vendorSane + `/*/Kconfig"
|
||||||
|
|
||||||
|
config MAINBOARD_VENDOR
|
||||||
|
string
|
||||||
|
default "` + vendor + `"
|
||||||
|
|
||||||
|
endif # VENDOR_` + vendorUpper + "\n")
|
||||||
|
}
|
||||||
|
kconfigName := vendorDir + "/Kconfig.name"
|
||||||
|
if _, err := os.Stat(kconfigName); os.IsNotExist(err) {
|
||||||
|
f, err := os.Create(kconfigName)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
f.WriteString(`config VENDOR_` + vendorUpper + `
|
||||||
|
bool "` + vendor + `"
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GuessECGPE(ctx Context) int {
|
||||||
|
/* FIXME:XX Use iasl -d and/or better parsing */
|
||||||
|
dsdt := ctx.InfoSource.GetACPI()["DSDT"]
|
||||||
|
idx := bytes.Index(dsdt, []byte{0x08, '_', 'G', 'P', 'E', 0x0a}) /* Name (_GPE, byte). */
|
||||||
|
if idx > 0 {
|
||||||
|
return int(dsdt[idx+6])
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func GuessSPDMap(ctx Context) []uint8 {
|
||||||
|
dmi := ctx.InfoSource.GetDMI()
|
||||||
|
|
||||||
|
if dmi.Vendor == "LENOVO" {
|
||||||
|
return []uint8{0x50, 0x52, 0x51, 0x53}
|
||||||
|
}
|
||||||
|
return []uint8{0x50, 0x51, 0x52, 0x53}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
ctx := Context{}
|
||||||
|
|
||||||
|
ctx.InfoSource = MakeLogReader()
|
||||||
|
|
||||||
|
dmi := ctx.InfoSource.GetDMI()
|
||||||
|
|
||||||
|
ctx.Vendor = dmi.Vendor
|
||||||
|
|
||||||
|
if dmi.Vendor == "LENOVO" {
|
||||||
|
ctx.Model = dmi.Version
|
||||||
|
} else {
|
||||||
|
ctx.Model = dmi.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
if dmi.IsLaptop {
|
||||||
|
KconfigBool["SYSTEM_TYPE_LAPTOP"] = true
|
||||||
|
}
|
||||||
|
ctx.SaneVendor = sanitize(ctx.Vendor)
|
||||||
|
for {
|
||||||
|
last := ctx.SaneVendor
|
||||||
|
for _, suf := range []string{"_inc", "_co", "_corp"} {
|
||||||
|
ctx.SaneVendor = strings.TrimSuffix(ctx.SaneVendor, suf)
|
||||||
|
}
|
||||||
|
if last == ctx.SaneVendor {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.MoboID = ctx.SaneVendor + "/" + sanitize(ctx.Model)
|
||||||
|
ctx.KconfigName = "BOARD_" + strings.ToUpper(ctx.SaneVendor+"_"+sanitize(ctx.Model))
|
||||||
|
ctx.BaseDirectory = *FlagOutDir + MoboDir + ctx.MoboID
|
||||||
|
KconfigString["MAINBOARD_DIR"] = ctx.MoboID
|
||||||
|
KconfigString["MAINBOARD_PART_NUMBER"] = ctx.Model
|
||||||
|
|
||||||
|
os.MkdirAll(ctx.BaseDirectory, 0700)
|
||||||
|
|
||||||
|
makeVendor(ctx)
|
||||||
|
|
||||||
|
ScanRoot(ctx)
|
||||||
|
|
||||||
|
if IGDEnabled {
|
||||||
|
KconfigBool["MAINBOARD_HAS_LIBGFXINIT"] = true
|
||||||
|
KconfigComment["MAINBOARD_HAS_LIBGFXINIT"] = "FIXME: check this"
|
||||||
|
AddRAMStageFile("gma-mainboard.ads", "CONFIG_MAINBOARD_USE_LIBGFXINIT")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(BootBlockFiles) > 0 || len(ROMStageFiles) > 0 || len(RAMStageFiles) > 0 || len(SMMFiles) > 0 {
|
||||||
|
mf := Create(ctx, "Makefile.mk")
|
||||||
|
defer mf.Close()
|
||||||
|
writeMF(mf, BootBlockFiles, "bootblock")
|
||||||
|
writeMF(mf, ROMStageFiles, "romstage")
|
||||||
|
writeMF(mf, RAMStageFiles, "ramstage")
|
||||||
|
writeMF(mf, SMMFiles, "smm")
|
||||||
|
}
|
||||||
|
|
||||||
|
devtree := Create(ctx, "devicetree.cb")
|
||||||
|
defer devtree.Close()
|
||||||
|
|
||||||
|
MatchDev(&DevTree)
|
||||||
|
WriteDev(devtree, 0, "", DevTree)
|
||||||
|
|
||||||
|
if MainboardInit != "" || MainboardEnable != "" || MainboardIncludes != nil {
|
||||||
|
mainboard := Create(ctx, "mainboard.c")
|
||||||
|
defer mainboard.Close()
|
||||||
|
Add_gpl(mainboard)
|
||||||
|
mainboard.WriteString("#include <device/device.h>\n")
|
||||||
|
for _, include := range MainboardIncludes {
|
||||||
|
mainboard.WriteString("#include <" + include + ">\n")
|
||||||
|
}
|
||||||
|
mainboard.WriteString("\n")
|
||||||
|
if MainboardInit != "" {
|
||||||
|
mainboard.WriteString(`static void mainboard_init(struct device *dev)
|
||||||
|
{
|
||||||
|
` + MainboardInit + "}\n\n")
|
||||||
|
}
|
||||||
|
if MainboardInit != "" || MainboardEnable != "" {
|
||||||
|
mainboard.WriteString("static void mainboard_enable(struct device *dev)\n{\n")
|
||||||
|
if MainboardInit != "" {
|
||||||
|
mainboard.WriteString("\tdev->ops->init = mainboard_init;\n\n")
|
||||||
|
}
|
||||||
|
mainboard.WriteString(MainboardEnable)
|
||||||
|
mainboard.WriteString("}\n\n")
|
||||||
|
mainboard.WriteString(`struct chip_operations mainboard_ops = {
|
||||||
|
.enable_dev = mainboard_enable,
|
||||||
|
};
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bi := Create(ctx, "board_info.txt")
|
||||||
|
defer bi.Close()
|
||||||
|
|
||||||
|
fixme := ""
|
||||||
|
|
||||||
|
if dmi.IsLaptop {
|
||||||
|
bi.WriteString("Category: laptop\n")
|
||||||
|
} else {
|
||||||
|
bi.WriteString("Category: desktop\n")
|
||||||
|
fixme += "check category, "
|
||||||
|
}
|
||||||
|
|
||||||
|
missing := "ROM package, ROM socketed"
|
||||||
|
|
||||||
|
if ROMProtocol != "" {
|
||||||
|
fmt.Fprintf(bi, "ROM protocol: %s\n", ROMProtocol)
|
||||||
|
} else {
|
||||||
|
missing += ", ROM protocol"
|
||||||
|
}
|
||||||
|
|
||||||
|
if FlashROMSupport != "" {
|
||||||
|
fmt.Fprintf(bi, "Flashrom support: %s\n", FlashROMSupport)
|
||||||
|
} else {
|
||||||
|
missing += ", Flashrom support"
|
||||||
|
}
|
||||||
|
|
||||||
|
missing += ", Release year"
|
||||||
|
|
||||||
|
if fixme != "" {
|
||||||
|
fmt.Fprintf(bi, "FIXME: %s, put %s\n", fixme, missing)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(bi, "FIXME: put %s\n", missing)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ROMSizeKB == 0 {
|
||||||
|
KconfigBool["BOARD_ROMSIZE_KB_2048"] = true
|
||||||
|
KconfigComment["BOARD_ROMSIZE_KB_2048"] = "FIXME: correct this"
|
||||||
|
} else {
|
||||||
|
KconfigBool[fmt.Sprintf("BOARD_ROMSIZE_KB_%d", ROMSizeKB)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
makeKconfig(ctx)
|
||||||
|
makeKconfigName(ctx)
|
||||||
|
|
||||||
|
dsdt := Create(ctx, "dsdt.asl")
|
||||||
|
defer dsdt.Close()
|
||||||
|
|
||||||
|
for _, define := range DSDTDefines {
|
||||||
|
if define.Comment != "" {
|
||||||
|
fmt.Fprintf(dsdt, "\t/* %s. */\n", define.Comment)
|
||||||
|
}
|
||||||
|
dsdt.WriteString("#define " + define.Key + " " + define.Value + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
Add_gpl(dsdt)
|
||||||
|
dsdt.WriteString(
|
||||||
|
`
|
||||||
|
#include <acpi/acpi.h>
|
||||||
|
|
||||||
|
DefinitionBlock(
|
||||||
|
"dsdt.aml",
|
||||||
|
"DSDT",
|
||||||
|
ACPI_DSDT_REV_2,
|
||||||
|
OEM_ID,
|
||||||
|
ACPI_TABLE_CREATOR,
|
||||||
|
0x20141018 /* OEM revision */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
#include <acpi/dsdt_top.asl>
|
||||||
|
#include "acpi/platform.asl"
|
||||||
|
`)
|
||||||
|
|
||||||
|
for _, x := range DSDTIncludes {
|
||||||
|
if x.Comment != "" {
|
||||||
|
fmt.Fprintf(dsdt, "\t/* %s. */\n", x.Comment)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(dsdt, "\t#include <%s>\n", x.File)
|
||||||
|
}
|
||||||
|
|
||||||
|
dsdt.WriteString(`
|
||||||
|
Device (\_SB.PCI0)
|
||||||
|
{
|
||||||
|
`)
|
||||||
|
for _, x := range DSDTPCI0Includes {
|
||||||
|
if x.Comment != "" {
|
||||||
|
fmt.Fprintf(dsdt, "\t/* %s. */\n", x.Comment)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(dsdt, "\t\t#include <%s>\n", x.File)
|
||||||
|
}
|
||||||
|
dsdt.WriteString(
|
||||||
|
` }
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
if IGDEnabled {
|
||||||
|
gma := Create(ctx, "gma-mainboard.ads")
|
||||||
|
defer gma.Close()
|
||||||
|
|
||||||
|
gma.WriteString(`-- SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
with HW.GFX.GMA;
|
||||||
|
with HW.GFX.GMA.Display_Probing;
|
||||||
|
|
||||||
|
use HW.GFX.GMA;
|
||||||
|
use HW.GFX.GMA.Display_Probing;
|
||||||
|
|
||||||
|
private package GMA.Mainboard is
|
||||||
|
|
||||||
|
-- FIXME: check this
|
||||||
|
ports : constant Port_List :=
|
||||||
|
(DP1,
|
||||||
|
DP2,
|
||||||
|
DP3,
|
||||||
|
HDMI1,
|
||||||
|
HDMI2,
|
||||||
|
HDMI3,
|
||||||
|
Analog,
|
||||||
|
LVDS,
|
||||||
|
eDP);
|
||||||
|
|
||||||
|
end GMA.Mainboard;
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type rce823 struct {
|
||||||
|
variant string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r rce823) Scan(ctx Context, addr PCIDevData) {
|
||||||
|
if addr.Dev == 0 && addr.Func == 0 {
|
||||||
|
cur := DevTreeNode{
|
||||||
|
Chip: "drivers/ricoh/rce822",
|
||||||
|
Comment: "Ricoh cardreader",
|
||||||
|
Registers: map[string]string{
|
||||||
|
|
||||||
|
"sdwppol": fmt.Sprintf("%d", (addr.ConfigDump[0xfb]&2)>>1),
|
||||||
|
"disable_mask": fmt.Sprintf("0x%x", addr.ConfigDump[0xcb]),
|
||||||
|
},
|
||||||
|
PCISlots: []PCISlot{
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Bus: addr.Bus, Dev: 0x0, Func: 0}, writeEmpty: false},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Bus: addr.Bus, Dev: 0x0, Func: 1}, writeEmpty: false},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Bus: addr.Bus, Dev: 0x0, Func: 2}, writeEmpty: false},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Bus: addr.Bus, Dev: 0x0, Func: 3}, writeEmpty: false},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Bus: addr.Bus, Dev: 0x0, Func: 4}, writeEmpty: false},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Bus: addr.Bus, Dev: 0x0, Func: 5}, writeEmpty: false},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Bus: addr.Bus, Dev: 0x0, Func: 6}, writeEmpty: false},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Bus: addr.Bus, Dev: 0x0, Func: 7}, writeEmpty: false},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
PutPCIChip(addr, cur)
|
||||||
|
}
|
||||||
|
PutPCIDev(addr, "Ricoh SD card reader")
|
||||||
|
KconfigBool["DRIVERS_RICOH_RCE822"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterPCI(0x1180, 0xe822, rce823{})
|
||||||
|
RegisterPCI(0x1180, 0xe823, rce823{})
|
||||||
|
}
|
|
@ -0,0 +1,457 @@
|
||||||
|
# Porting coreboot using autoport
|
||||||
|
|
||||||
|
## Supported platforms
|
||||||
|
|
||||||
|
### Chipset
|
||||||
|
For any Sandy Bridge or Ivy Bridge platform the generated result should
|
||||||
|
be bootable, possibly with minor fixes.
|
||||||
|
|
||||||
|
### EC / SuperIO
|
||||||
|
EC support is likely to work on Intel-based thinkpads. Other laptops are
|
||||||
|
likely to miss EC support. SuperIO support on desktops is more likely to
|
||||||
|
work out of the box than any EC.
|
||||||
|
|
||||||
|
## How to use autoport
|
||||||
|
|
||||||
|
Enable as many devices as possible in the firmware setup of your system.
|
||||||
|
This is useful to detect as many devices as possible and make the port
|
||||||
|
more complete, as disabled devices cannot be detected.
|
||||||
|
|
||||||
|
Boot into target machine under any Linux-based distribution and install
|
||||||
|
the following tools on it:
|
||||||
|
* `gcc`
|
||||||
|
* `golang`
|
||||||
|
* `lspci`
|
||||||
|
* `dmidecode`
|
||||||
|
* `acpidump` (part of `acpica` on some distros)
|
||||||
|
|
||||||
|
Clone the coreboot tree and `cd` into it. For more detailed steps, refer
|
||||||
|
to Rookie Guide, Lesson 1. Afterwards, run these commands:
|
||||||
|
|
||||||
|
cd util/ectool
|
||||||
|
make
|
||||||
|
cd ../inteltool
|
||||||
|
make
|
||||||
|
cd ../superiotool
|
||||||
|
make
|
||||||
|
cd ../autoport
|
||||||
|
go build
|
||||||
|
sudo ./autoport --input_log=logs --make_logs --coreboot_dir=../..
|
||||||
|
|
||||||
|
Note: in case you have problems getting gcc and golang on the target
|
||||||
|
machine, you can compile the utilities on another computer and copy
|
||||||
|
the binaries to the target machine. You will still need the other
|
||||||
|
listed programs on the target machine, but you may place them in the
|
||||||
|
same directory as autoport.
|
||||||
|
|
||||||
|
Check for unknown detected PCI devices, e.g.:
|
||||||
|
|
||||||
|
Unknown PCI device 8086:0085, assuming removable
|
||||||
|
|
||||||
|
If autoport says `assuming removable`, you are fine. If it doesn't,
|
||||||
|
you may want to add the relevant PCI IDs to autoport. Run `lspci -nn`
|
||||||
|
and check which device this is using the PCI ID. Devices which are not
|
||||||
|
part of the chipset, such as GPUs or network cards, can be considered
|
||||||
|
removable, whereas devices inside the CPU or the PCH such as integrated
|
||||||
|
GPUs and bus controllers (SATA, USB, LPC, SMBus...) are non-removable.
|
||||||
|
|
||||||
|
Your board has now been added to the tree. However, do not flash it
|
||||||
|
in its current state. It can brick your machine. Instead, keep this
|
||||||
|
new port and the logs from `util/autoport/logs` somewhere safe. The
|
||||||
|
following steps will back up your current firmware, which is always
|
||||||
|
recommended, since coreboot may not boot on the first try.
|
||||||
|
|
||||||
|
Disassemble your computer and find the flash chip(s). Since there could be
|
||||||
|
more than one, this guide will refer to "flash chips" as one or more chips.
|
||||||
|
Refer to <https://flashrom.org/Technology> as a reference. The flash chip is
|
||||||
|
usually in a `SOIC-8` (2x4 pins, 200mil) or `SOIC-16` (2x8 pins) package. As
|
||||||
|
it can be seen on flashrom's wiki, the former package is like any other 8-pin
|
||||||
|
chip on the mainboard, but it is slightly larger. The latter package is much
|
||||||
|
easier to locate. Always make sure it is a flash chip by looking up what its
|
||||||
|
model, printed on it, refers to.
|
||||||
|
|
||||||
|
There may be a smaller flash chip for the EC on some laptops, and other chips
|
||||||
|
such as network cards may use similar flash chips. These should be left as-is.
|
||||||
|
If in doubt, ask!
|
||||||
|
|
||||||
|
Once located, use an external flasher to read the flash chips with `flashrom -r`.
|
||||||
|
Verify with `flashrom -v` several times that reading is consistent. If it is not,
|
||||||
|
troubleshoot your flashing setup. Save the results somewhere safe, preferably on
|
||||||
|
media that cannot be easily overwritten and on several devices. You may need this
|
||||||
|
later. The write process erases the flash chips first, and erased data on a flash
|
||||||
|
chip is lost for a very long time, usually forever!
|
||||||
|
|
||||||
|
Compile coreboot for your ported mainboard with some console enabled. The most
|
||||||
|
common ones are EHCI debug, serial port and SPI flash console as a last resort.
|
||||||
|
If your system is a laptop and has a dedicated video card, you may need to add
|
||||||
|
a video BIOS (VBIOS) to coreboot to be able to see any video output. Desktop
|
||||||
|
video cards, as well as some MXM video cards, have this VBIOS on a flash chip
|
||||||
|
on the card's PCB, so this step is not necessary for them.
|
||||||
|
|
||||||
|
Flash coreboot on the machine. On recent Intel chipsets, the flash space is split
|
||||||
|
in several regions. Only the one known as "BIOS region" should be flashed. If
|
||||||
|
there is only one flash chip present, this is best done by adding the `--ifd`
|
||||||
|
and `-i bios` parameters flashrom has (from v1.0 onwards) to specify what flash
|
||||||
|
descriptor region it should operate on. If the ME (Management Engine) region is
|
||||||
|
not readable, which is the case on most systems, use the `--noverify-all`
|
||||||
|
parameter as well.
|
||||||
|
|
||||||
|
For systems with two flash chips, this is not so easy. It is probably better to
|
||||||
|
ask in coreboot or flashrom communication channels, such as via IRC or on the
|
||||||
|
mailing lists.
|
||||||
|
|
||||||
|
Once flashed, try to boot. Anything is possible. If a log is generated, save it
|
||||||
|
and use it to address any issues. See the next section for useful information.
|
||||||
|
Find all the sections marked with `FIXME` and correct them.
|
||||||
|
|
||||||
|
Send your work to review.coreboot.org. I mean it, your effort is very appreciated.
|
||||||
|
Refer to Rookie Guide, Lesson 2 for instructions on how to submit a patch.
|
||||||
|
|
||||||
|
## Manual fixes
|
||||||
|
### SPD
|
||||||
|
In order to initialize the RAM memory, coreboot needs to know its timings, which vary between
|
||||||
|
modules. Socketed RAM has a small EEPROM chip, which is accessible via SMBus and contains the
|
||||||
|
timing data. This data is usually known as SPD. Unfortunately, the SMBus addresses may not
|
||||||
|
correlate with the RAM slots and cannot always be detected automatically. The address map is
|
||||||
|
encoded in function `mainboard_get_spd` in `romstage.c`. By default, autoport uses the most
|
||||||
|
common map `0x50, 0x51, 0x52, 0x53` on everything except for Lenovo systems, which are known
|
||||||
|
to use `0x50, 0x52, 0x51, 0x53`. To detect the correct memory map, the easiest way is to boot
|
||||||
|
on the vendor firmware with just one module in channel 0, slot 0, and check the SMBus address
|
||||||
|
the EEPROM has. Under Linux, you can use these commands to see what is on SMBus:
|
||||||
|
|
||||||
|
$ sudo modprobe i2c-dev
|
||||||
|
$ sudo modprobe i2c-i801
|
||||||
|
$ sudo i2cdetect -l
|
||||||
|
i2c-0 i2c i915 gmbus ssc I2C adapter
|
||||||
|
i2c-1 i2c i915 gmbus vga I2C adapter
|
||||||
|
i2c-2 i2c i915 gmbus panel I2C adapter
|
||||||
|
i2c-3 i2c i915 gmbus dpc I2C adapter
|
||||||
|
i2c-4 i2c i915 gmbus dpb I2C adapter
|
||||||
|
i2c-5 i2c i915 gmbus dpd I2C adapter
|
||||||
|
i2c-6 i2c DPDDC-B I2C adapter
|
||||||
|
i2c-7 i2c DPDDC-C I2C adapter
|
||||||
|
i2c-8 i2c DPDDC-D I2C adapter
|
||||||
|
i2c-9 smbus SMBus I801 adapter at 0400 SMBus adapter
|
||||||
|
|
||||||
|
$ sudo i2cdetect 9
|
||||||
|
WARNING! This program can confuse your I2C bus, cause data loss and worse!
|
||||||
|
I will probe file /dev/i2c-9.
|
||||||
|
I will probe address range 0x03-0x77.
|
||||||
|
Continue? [Y/n] y
|
||||||
|
0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||||
|
00: -- -- -- -- -- 08 -- -- -- -- -- -- --
|
||||||
|
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
20: -- -- -- -- 24 -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
30: 30 31 -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
50: 50 -- -- -- 54 55 56 57 -- -- -- -- 5c 5d 5e 5f
|
||||||
|
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
70: -- -- -- -- -- -- -- --
|
||||||
|
|
||||||
|
Make sure to replace the `9` on the last command with the bus number for SMBus on
|
||||||
|
your system. Here, there is a module at address `0x50`. Since only one module was
|
||||||
|
installed on the first slot of the first channel, we know the first position of
|
||||||
|
the SPD array must be `0x50`. After testing all the slots, your `mainboard_get_spd`
|
||||||
|
should look similar to this:
|
||||||
|
|
||||||
|
void mainboard_get_spd(spd_raw_data *spd) {
|
||||||
|
read_spd(&spd[0], 0x50);
|
||||||
|
read_spd(&spd[1], 0x51);
|
||||||
|
read_spd(&spd[2], 0x52);
|
||||||
|
read_spd(&spd[3], 0x53);
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that there should be one line per memory slot on the mainboard.
|
||||||
|
|
||||||
|
Note: slot labelling may be missing or unreliable. Use `inteltool` to see
|
||||||
|
which slots have modules in them.
|
||||||
|
|
||||||
|
This procedure is ideal, if your RAM is socketed. If you have soldered RAM,
|
||||||
|
remove any socketed memory modules and check if any EEPROM appears on SMBus.
|
||||||
|
If this is the case, you can proceed as if the RAM was socketed. However,
|
||||||
|
you may have to guess some entries if there multiple EEPROMs appear.
|
||||||
|
|
||||||
|
Most of the time, soldered RAM does not have an EEPROM. Instead, the SPD data is
|
||||||
|
inside the main flash chip where the firmware is. If this is the case, you need
|
||||||
|
to generate the SPD data to use with coreboot. Look at `inteltool.log`. There
|
||||||
|
should be something like this:
|
||||||
|
|
||||||
|
/* SPD matching current mode: */
|
||||||
|
/* CH0S0 */
|
||||||
|
00: 92 11 0b 03 04 00 00 09 03 52 01 08 0a 00 80 00
|
||||||
|
10: 6e 78 6e 32 6e 11 18 81 20 08 3c 3c 00 f0 00 00
|
||||||
|
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 00
|
||||||
|
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6d 17
|
||||||
|
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
/* CH1S0 */
|
||||||
|
00: 92 11 0b 03 04 00 00 09 03 52 01 08 0a 00 80 00
|
||||||
|
10: 6e 78 6e 32 6e 11 18 81 20 08 3c 3c 00 f0 00 00
|
||||||
|
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 00
|
||||||
|
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6d 17
|
||||||
|
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
|
||||||
|
This is not a full-fledged SPD dump, as it only lists
|
||||||
|
the currently-used speed configuration, and lacks info
|
||||||
|
such as a serial number, vendor and model. Use `xxd`
|
||||||
|
to create a binary file with this SPD data:
|
||||||
|
|
||||||
|
$ cat | xxd -r > spd.bin <<EOF
|
||||||
|
00: 92 11 0b 03 04 00 00 09 03 52 01 08 0a 00 80 00
|
||||||
|
10: 6e 78 6e 32 6e 11 18 81 20 08 3c 3c 00 f0 00 00
|
||||||
|
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 00
|
||||||
|
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6d 17
|
||||||
|
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EOF (press Ctrl + D)
|
||||||
|
|
||||||
|
Then, move the generated file into your mainboard's directory
|
||||||
|
and hook it up to the build system by adding the following
|
||||||
|
lines to `Makefile.mk`:
|
||||||
|
|
||||||
|
cbfs-files-y += spd.bin
|
||||||
|
spd.bin-file := spd.bin
|
||||||
|
spd.bin-type := raw
|
||||||
|
|
||||||
|
Now we need coreboot to use this SPD file. The following example
|
||||||
|
shows a hybrid configuration, in which one module is soldered and
|
||||||
|
the other one is socketed:
|
||||||
|
|
||||||
|
void mainboard_get_spd(spd_raw_data *spd)
|
||||||
|
{
|
||||||
|
void *spd_file;
|
||||||
|
size_t spd_file_len = 0;
|
||||||
|
/* C0S0 is a soldered RAM with no real SPD. Use stored SPD. */
|
||||||
|
spd_file = cbfs_boot_map_with_leak("spd.bin", CBFS_TYPE_RAW,
|
||||||
|
&spd_file_len);
|
||||||
|
if (spd_file && spd_file_len >= 128)
|
||||||
|
memcpy(&spd[0], spd_file, 128);
|
||||||
|
|
||||||
|
/* C1S0 is a physical slot. */
|
||||||
|
read_spd(&spd[2], 0x52);
|
||||||
|
}
|
||||||
|
|
||||||
|
If several slots are soldered there are two ways to handle them:
|
||||||
|
|
||||||
|
* If all use the same SPD data, use the same file for all the slots. Do
|
||||||
|
not forget to copy the data on all the array elements that need it.
|
||||||
|
* If they use different data, use several files.
|
||||||
|
|
||||||
|
If memory initialization is not working, in particular write training (timB)
|
||||||
|
on DIMM's second rank fails, try enabling rank 1 mirroring, which can't be
|
||||||
|
detected by inteltool. It is described by SPD field "Address Mapping from Edge
|
||||||
|
Connector to DRAM", byte `63` (`0x3f`). Bit 0 describes Rank 1 Mapping,
|
||||||
|
0 = standard, 1 = mirrored; set it to 1. Bits 1-7 are reserved.
|
||||||
|
|
||||||
|
### `board_info.txt`
|
||||||
|
|
||||||
|
`board_info.txt` is a text file used in the board status page to list all
|
||||||
|
the supported boards and their specifications. Most of the information
|
||||||
|
cannot be detected by autoport. Common entries are:
|
||||||
|
|
||||||
|
* `ROM package`, `ROM protocol` and `ROM socketed`:
|
||||||
|
These refer to the flash chips you found earlier. You can visit
|
||||||
|
<https://flashrom.org/Technology> for more information.
|
||||||
|
|
||||||
|
* `Release year`: Use the power of Internet to find that information.
|
||||||
|
* `Category`: This describes the type of mainboard you have.
|
||||||
|
Valid categories are:
|
||||||
|
* `desktop`. Desktops and workstations.
|
||||||
|
* `server`. Servers.
|
||||||
|
* `laptop`. Laptops, notebooks and netbooks.
|
||||||
|
* `half`. Embedded / PC/104 / Half-size boards.
|
||||||
|
* `mini`. Mini-ITX / Micro-ITX / Nano-ITX
|
||||||
|
* `settop`. Set-top-boxes / Thin clients.
|
||||||
|
* `eval`. Development / Evaluation Boards.
|
||||||
|
* `sbc`. Single-Board computer.
|
||||||
|
* `emulation`: Virtual machines and emulators. May require especial care
|
||||||
|
as they often behave differently from real counterparts.
|
||||||
|
* `misc`. Anything not fitting the categories above. Not recommended.
|
||||||
|
|
||||||
|
* `Flashrom support`: This means whether the internal programmer is usable.
|
||||||
|
If flashing coreboot internally works, this should be set to `y`. Else,
|
||||||
|
feel free to investigate why it is not working.
|
||||||
|
|
||||||
|
### `USBDEBUG_HCD_INDEX`
|
||||||
|
|
||||||
|
Which controller the most easily accessible USB debug port is. On Intel,
|
||||||
|
1 is for `00:1d.0` and 2 is for `00:1a.0` (yes, it's reversed). Refer to
|
||||||
|
<https://www.coreboot.org/EHCI_Debug_Port> for more info.
|
||||||
|
|
||||||
|
If you are able to use EHCI debug without setting the HCD index manually,
|
||||||
|
this is correct.
|
||||||
|
|
||||||
|
### `BOARD_ROMSIZE_KB_2048`
|
||||||
|
|
||||||
|
This parameter refers to the total size of the flash chips coreboot will be in.
|
||||||
|
This value must be correct for S3 resume to work properly. This parameter also
|
||||||
|
defines the size of the generated coreboot image, but that is not a major issue
|
||||||
|
since tools like `dd` can be used to cut fragments of a coreboot image to flash
|
||||||
|
on smaller chips.
|
||||||
|
|
||||||
|
This should be detected automatically, but it may not be detected properly in
|
||||||
|
some cases. If it was not detected, put the correct total size here to serve
|
||||||
|
as a sane default when configuring coreboot.
|
||||||
|
|
||||||
|
### `DRAM_RESET_GATE_GPIO`
|
||||||
|
|
||||||
|
When the computer is suspended to RAM (ACPI S3), the RAM reset signal must not
|
||||||
|
reach the RAM modules. Otherwise, the computer will not resume and any opened
|
||||||
|
programs will be lost. This is done by powering down a MOSFET, which disconnects
|
||||||
|
the reset signal from the RAM modules. Most manufacturers put this gate on GPIO
|
||||||
|
60 but Lenovo is known to put it on GPIO 10. If suspending and resuming works,
|
||||||
|
this value is correct. This can also be determined from the board's schematics.
|
||||||
|
|
||||||
|
## GNVS
|
||||||
|
|
||||||
|
`mainboard_fill_gnvs` sets values in GNVS, which then ACPI makes use of for
|
||||||
|
various power-related functions. Normally, there is no need to modify it
|
||||||
|
on laptops (desktops have no "lid"!) but it makes sense to proofread it.
|
||||||
|
|
||||||
|
## `gfx.ndid` and `gfx.did`
|
||||||
|
|
||||||
|
Those describe which video outputs are declared in ACPI tables.
|
||||||
|
Normally, there is no need to have these values, but if you miss some
|
||||||
|
non-standard video output, you can declare it there. Bit 31 is set to
|
||||||
|
indicate the presence of the output. Byte 1 is the type and byte 0 is
|
||||||
|
used for disambigution so that ID composed of byte 1 and 0 is unique.
|
||||||
|
|
||||||
|
Types are:
|
||||||
|
* 1 = VGA
|
||||||
|
* 2 = TV
|
||||||
|
* 3 = DVI
|
||||||
|
* 4 = LCD
|
||||||
|
|
||||||
|
## `c*_acpower` and `c*_battery`
|
||||||
|
|
||||||
|
Which mwait states to match to which ACPI levels. Normally, there is no
|
||||||
|
need to modify anything unless your device has very special power saving
|
||||||
|
requirements.
|
||||||
|
|
||||||
|
## `install_intel_vga_int15_handler`
|
||||||
|
|
||||||
|
This is used with the Intel VGA BIOS, which is not the default option.
|
||||||
|
It is more error-prone than open-source graphics initialization, so do
|
||||||
|
not bother with this until your mainboard boots. This is a function
|
||||||
|
which takes four parameters:
|
||||||
|
1. Which type of LCD panel is connected.
|
||||||
|
2. Panel fit.
|
||||||
|
3. Boot display.
|
||||||
|
4. Display type.
|
||||||
|
|
||||||
|
Refer to `src/drivers/intel/gma/int15.h` to see which values can be used.
|
||||||
|
For desktops, there is no LCD panel directly connected to the Intel GPU,
|
||||||
|
so the first parameter should be `GMA_INT15_ACTIVE_LFP_NONE`. On other
|
||||||
|
mainboards, it depends.
|
||||||
|
|
||||||
|
## CMOS options
|
||||||
|
|
||||||
|
Due to the poor state of CMOS support in coreboot, autoport does not
|
||||||
|
support it and this probably won't change until the format in the tree
|
||||||
|
improves. If you really care about CMOS options:
|
||||||
|
|
||||||
|
* Create files `cmos.layout` and `cmos.default`
|
||||||
|
* Enable `HAVE_OPTION_TABLE` and `HAVE_CMOS_DEFAULT` in `Kconfig`
|
||||||
|
|
||||||
|
## EC (lenovo)
|
||||||
|
|
||||||
|
You need to set `has_keyboard_backlight` (backlit keyboard like X230),
|
||||||
|
`has_power_management_beeps` (optional beeps when e.g. plugging the cord
|
||||||
|
in) and `has_uwb` (third MiniPCIe slot) in accordance to functions available
|
||||||
|
on your machine
|
||||||
|
|
||||||
|
In rare cases autoport is unable to detect GPE. You can detect it from
|
||||||
|
dmesg or ACPI tables. Look for line in dmesg like
|
||||||
|
|
||||||
|
ACPI: EC: GPE = 0x11, I/O: command/status = 0x66, data = 0x62
|
||||||
|
|
||||||
|
This means that GPE is `0x11` in ACPI notation. This is the correct
|
||||||
|
value for `THINKPAD_EC_GPE`. To get the correct value for `GPE_EC_SCI`
|
||||||
|
you need to substract `0x10`, so value for it is `1`.
|
||||||
|
|
||||||
|
The pin used to wake the machine from EC is guessed. If your machine doesn't
|
||||||
|
wake on lid open and pressing of Fn, change `GPE_EC_WAKE`.
|
||||||
|
|
||||||
|
Keep `GPE_EC_WAKE` and `GPE_EC_SCI` in sync with `gpi*_routing`.
|
||||||
|
`gpi*_routing` matching `GPE_EC_WAKE` or `GPE_EC_SCI` is set to `2`
|
||||||
|
and all others are absent.
|
||||||
|
|
||||||
|
If your dock has LPC wires or needs some special treatement you may
|
||||||
|
need to add codes to initialize the dock and support code to
|
||||||
|
DSDT. See the `init_dock()` for `x60`, `x200` or `x201`.
|
||||||
|
|
||||||
|
## EC (generic laptop)
|
||||||
|
|
||||||
|
Almost any laptop has an embedded controller. In a nutshell, it's a
|
||||||
|
small, low-powered computer designed to be used on laptops. Exact
|
||||||
|
functionality differs between machines. Its main functions include:
|
||||||
|
|
||||||
|
* Control of power and rfkill to different component
|
||||||
|
* Keyboard (PS/2) interface implementation
|
||||||
|
* Battery, AC, LID and thermal information exporting
|
||||||
|
* Hotkey support
|
||||||
|
|
||||||
|
autoport automatically attempts to restore the dumped config but it
|
||||||
|
may or may not work and may even lead to a hang or powerdown. If your
|
||||||
|
machine stops at `Replaying EC dump ...` try commenting EC replay out
|
||||||
|
|
||||||
|
autoport tries to detect if machine has PS/2 interface and if so calls
|
||||||
|
`pc_keyboard_init` and exports relevant ACPI objects. If detection fails
|
||||||
|
you may have to add them yourself
|
||||||
|
|
||||||
|
ACPI methods `_PTS` (prepare to sleep) and `_WAK` (wake) are executed
|
||||||
|
when transitioning to sleep or wake state respectively. You may need to
|
||||||
|
add power-related calls there to either shutdown some components or to
|
||||||
|
add a workaround to stop giving OS thermal info until next refresh.
|
||||||
|
|
||||||
|
For exporting the battery/AC/LID/hotkey/thermal info you need to write
|
||||||
|
`acpi/ec.asl`. For an easy example look into `apple/macbook21` or
|
||||||
|
`packardbell/ms2290`. For information about needed methods consult
|
||||||
|
relevant ACPI specs. Tracing which EC events can be done using
|
||||||
|
[dynamic debug](https://wiki.ubuntu.com/Kernel/Reference/ACPITricksAndTips)
|
||||||
|
|
||||||
|
EC GPE needs to be routed to SCI in order for OS in order to receive
|
||||||
|
EC events like "hotkey X pressed" or "AC plugged". autoport attempts
|
||||||
|
to detect GPE but in rare cases may fail. You can detect it from
|
||||||
|
dmesg or ACPI tables. Look for line in dmesg like
|
||||||
|
|
||||||
|
ACPI: EC: GPE = 0x11, I/O: command/status = 0x66, data = 0x62
|
||||||
|
|
||||||
|
This means that GPE is `0x11` in ACPI notation. This is the correct
|
||||||
|
value for `_GPE`.
|
||||||
|
|
||||||
|
Keep GPE in sync with `gpi*_routing`.
|
||||||
|
`gpi*_routing` matching `GPE - 0x10` is set to `2`
|
||||||
|
and all others are absent. If EC has separate wake pin
|
||||||
|
then this GPE needs to be routed as well
|
|
@ -0,0 +1,47 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
var supportedPCIDevices map[uint32]PCIDevice = map[uint32]PCIDevice{}
|
||||||
|
var PCIMap map[PCIAddr]PCIDevData = map[PCIAddr]PCIDevData{}
|
||||||
|
|
||||||
|
func ScanRoot(ctx Context) {
|
||||||
|
for _, pciDev := range ctx.InfoSource.GetPCIList() {
|
||||||
|
PCIMap[pciDev.PCIAddr] = pciDev
|
||||||
|
}
|
||||||
|
for _, pciDev := range ctx.InfoSource.GetPCIList() {
|
||||||
|
vendevid := (uint32(pciDev.PCIDevID) << 16) | uint32(pciDev.PCIVenID)
|
||||||
|
|
||||||
|
dev, ok := supportedPCIDevices[vendevid]
|
||||||
|
if !ok {
|
||||||
|
if pciDev.PCIAddr.Bus != 0 {
|
||||||
|
fmt.Printf("Unknown PCI device %04x:%04x, assuming removable\n",
|
||||||
|
pciDev.PCIVenID, pciDev.PCIDevID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("Unsupported PCI device %04x:%04x\n",
|
||||||
|
pciDev.PCIVenID, pciDev.PCIDevID)
|
||||||
|
dev = GenericPCI{Comment: fmt.Sprintf("Unsupported PCI device %04x:%04x",
|
||||||
|
pciDev.PCIVenID, pciDev.PCIDevID)}
|
||||||
|
}
|
||||||
|
dev.Scan(ctx, pciDev)
|
||||||
|
}
|
||||||
|
if SouthBridge == nil {
|
||||||
|
fmt.Println("Could not detect southbridge. Aborting!")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
dmi := ctx.InfoSource.GetDMI()
|
||||||
|
if !dmi.IsLaptop {
|
||||||
|
NoEC(ctx)
|
||||||
|
} else if dmi.Vendor == "LENOVO" {
|
||||||
|
LenovoEC(ctx)
|
||||||
|
} else {
|
||||||
|
FIXMEEC(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterPCI(VenID uint16, DevID uint16, dev PCIDevice) {
|
||||||
|
vendevid := (uint32(DevID) << 16) | uint32(VenID)
|
||||||
|
supportedPCIDevices[vendevid] = dev
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type sandybridgemc struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i sandybridgemc) Scan(ctx Context, addr PCIDevData) {
|
||||||
|
inteltool := ctx.InfoSource.GetInteltool()
|
||||||
|
|
||||||
|
/* FIXME:XX Move this somewhere else. */
|
||||||
|
MainboardIncludes = append(MainboardIncludes, "drivers/intel/gma/int15.h")
|
||||||
|
MainboardEnable += (` /* FIXME: fix these values. */
|
||||||
|
install_intel_vga_int15_handler(GMA_INT15_ACTIVE_LFP_INT_LVDS,
|
||||||
|
GMA_INT15_PANEL_FIT_DEFAULT,
|
||||||
|
GMA_INT15_BOOT_DISPLAY_DEFAULT, 0);
|
||||||
|
`)
|
||||||
|
|
||||||
|
DevTree = DevTreeNode{
|
||||||
|
Chip: "northbridge/intel/sandybridge",
|
||||||
|
MissingParent: "northbridge",
|
||||||
|
Comment: "FIXME: GPU registers may not always apply.",
|
||||||
|
Registers: map[string]string{
|
||||||
|
"gpu_dp_b_hotplug": FormatInt32((inteltool.IGD[0xc4030] >> 2) & 7),
|
||||||
|
"gpu_dp_c_hotplug": FormatInt32((inteltool.IGD[0xc4030] >> 10) & 7),
|
||||||
|
"gpu_dp_d_hotplug": FormatInt32((inteltool.IGD[0xc4030] >> 18) & 7),
|
||||||
|
"gpu_panel_port_select": FormatInt32((inteltool.IGD[0xc7208] >> 30) & 3),
|
||||||
|
"gpu_panel_power_up_delay": FormatInt32((inteltool.IGD[0xc7208] >> 16) & 0x1fff),
|
||||||
|
"gpu_panel_power_backlight_on_delay": FormatInt32(inteltool.IGD[0xc7208] & 0x1fff),
|
||||||
|
"gpu_panel_power_down_delay": FormatInt32((inteltool.IGD[0xc720c] >> 16) & 0x1fff),
|
||||||
|
"gpu_panel_power_backlight_off_delay": FormatInt32(inteltool.IGD[0xc720c] & 0x1fff),
|
||||||
|
"gpu_panel_power_cycle_delay": FormatInt32(inteltool.IGD[0xc7210] & 0xff),
|
||||||
|
"gpu_cpu_backlight": FormatHex32(inteltool.IGD[0x48254]),
|
||||||
|
"gpu_pch_backlight": FormatHex32((inteltool.IGD[0xc8254] >> 16) * 0x10001),
|
||||||
|
"gfx": fmt.Sprintf("GMA_STATIC_DISPLAYS(%d)", (inteltool.IGD[0xc6200] >> 12) & 1),
|
||||||
|
},
|
||||||
|
Children: []DevTreeNode{
|
||||||
|
{
|
||||||
|
Chip: "domain",
|
||||||
|
Dev: 0,
|
||||||
|
PCIController: true,
|
||||||
|
ChildPCIBus: 0,
|
||||||
|
PCISlots: []PCISlot{
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x0, Func: 0}, writeEmpty: true, alias: "host_bridge", additionalComment: "Host bridge"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x1, Func: 0}, writeEmpty: true, alias: "peg10", additionalComment: "PEG"},
|
||||||
|
PCISlot{PCIAddr: PCIAddr{Dev: 0x2, Func: 0}, writeEmpty: true, alias: "igd", additionalComment: "iGPU"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
PutPCIDev(addr, "Host bridge")
|
||||||
|
|
||||||
|
/* FIXME:XX some configs are unsupported. */
|
||||||
|
KconfigBool["NORTHBRIDGE_INTEL_SANDYBRIDGE"] = true
|
||||||
|
KconfigBool["USE_NATIVE_RAMINIT"] = true
|
||||||
|
KconfigBool["INTEL_INT15"] = true
|
||||||
|
KconfigBool["HAVE_ACPI_TABLES"] = true
|
||||||
|
KconfigBool["HAVE_ACPI_RESUME"] = true
|
||||||
|
|
||||||
|
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||||
|
File: "cpu/intel/common/acpi/cpu.asl",
|
||||||
|
})
|
||||||
|
|
||||||
|
DSDTPCI0Includes = append(DSDTPCI0Includes, DSDTInclude{
|
||||||
|
File: "northbridge/intel/sandybridge/acpi/sandybridge.asl",
|
||||||
|
}, DSDTInclude{
|
||||||
|
File: "drivers/intel/gma/acpi/default_brightness_levels.asl",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterPCI(0x8086, 0x0100, sandybridgemc{})
|
||||||
|
RegisterPCI(0x8086, 0x0104, sandybridgemc{})
|
||||||
|
RegisterPCI(0x8086, 0x0150, sandybridgemc{})
|
||||||
|
RegisterPCI(0x8086, 0x0154, sandybridgemc{})
|
||||||
|
RegisterPCI(0x8086, 0x0158, sandybridgemc{})
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x0102, 0x0106, 0x010a,
|
||||||
|
0x0112, 0x0116, 0x0122, 0x0126,
|
||||||
|
0x0152, 0x0156, 0x0162, 0x0166,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericVGA{GenericPCI{}})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PCIe bridge */
|
||||||
|
for _, id := range []uint16{
|
||||||
|
0x0101, 0x0105, 0x0109, 0x010d,
|
||||||
|
0x0151, 0x0155, 0x0159, 0x015d,
|
||||||
|
} {
|
||||||
|
RegisterPCI(0x8086, id, GenericPCI{})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue