autoport: Write autoport together with porting guide for sandy/ivybridge.
This should be able to generate bootable ports for sandy/ivy, possible with minor fixes. Howto is in readme.md Change-Id: Ia126cf0939ef2dc2cdbb7ea100d2b63ea6b02f28 Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com> Reviewed-on: http://review.coreboot.org/7131 Tested-by: build bot (Jenkins) Reviewed-by: Edward O'Callaghan <edward.ocallaghan@koparo.com>
This commit is contained in:
parent
b06a249c3b
commit
3129f792f7
|
@ -0,0 +1,64 @@
|
|||
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()
|
||||
|
||||
az.WriteString(
|
||||
`#include <device/azalia_device.h>
|
||||
|
||||
const u32 cim_verb_data[] = {
|
||||
`)
|
||||
|
||||
for _, codec := range ctx.InfoSource.GetAzaliaCodecs() {
|
||||
fmt.Fprintf(az, "\t0x%08x, /* Codec Vendor / Device ID: %s */\n",
|
||||
codec.VendorID, codec.Name)
|
||||
fmt.Fprintf(az, "\t0x%08x, /* Subsystem ID */\n",
|
||||
codec.SubsystemID)
|
||||
fmt.Fprintf(az, "\n\t0x%08x, /* Number of 4 dword sets */\n",
|
||||
len(codec.PinConfig)+1)
|
||||
fmt.Fprintf(az, "\t/* NID 0x01: Subsystem ID. */\n")
|
||||
fmt.Fprintf(az, "\tAZALIA_SUBVENDOR(0x%x, 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, "\n\t/* NID 0x%02x. */\n", nid)
|
||||
fmt.Fprintf(az, "\tAZALIA_PIN_CFG(0x%x, 0x%02x, 0x%08x),\n",
|
||||
codec.CodecNo, nid, codec.PinConfig[nid])
|
||||
}
|
||||
}
|
||||
|
||||
az.WriteString(
|
||||
`};
|
||||
|
||||
const u32 pc_beep_verbs[0] = {};
|
||||
|
||||
AZALIA_ARRAY_SIZES;
|
||||
`)
|
||||
|
||||
PutPCIDev(addr, "Audio controller")
|
||||
}
|
||||
|
||||
func init() {
|
||||
/* I82801GX/I945 */
|
||||
RegisterPCI(0x8086, 0x27d8, azalia{})
|
||||
/* BD82X6X/sandybridge */
|
||||
RegisterPCI(0x8086, 0x1c20, azalia{})
|
||||
/* C216/ivybridge */
|
||||
RegisterPCI(0x8086, 0x1e20, azalia{})
|
||||
}
|
|
@ -0,0 +1,456 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type bd82x6x struct {
|
||||
variant string
|
||||
node *DevTreeNode
|
||||
}
|
||||
|
||||
func (b bd82x6x) writeGPIOSet(ctx Context, sb *os.File,
|
||||
val uint32, set uint, partno int) {
|
||||
|
||||
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++ {
|
||||
fmt.Fprintf(sb, " .gpio%d = %s,\n",
|
||||
(set-1)*32+i,
|
||||
bits[partno][(val>>i)&1])
|
||||
}
|
||||
}
|
||||
|
||||
func (b bd82x6x) GPIO(ctx Context, inteltool InteltoolData) {
|
||||
gpio := Create(ctx, "gpio.c")
|
||||
defer gpio.Close()
|
||||
|
||||
AddROMStageFile("gpio.c", "")
|
||||
|
||||
gpio.WriteString(`#include "southbridge/intel/bd82x6x/gpio.h"
|
||||
`)
|
||||
|
||||
adresses := [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 := adresses[set-1][partno]
|
||||
if addr < 0 {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(gpio, "const struct pch_gpio_set%d pch_gpio_set%d_%s = {\n",
|
||||
set, set, part)
|
||||
|
||||
b.writeGPIOSet(ctx, gpio, inteltool.GPIO[uint16(addr)], uint(set), partno)
|
||||
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,
|
||||
},
|
||||
};
|
||||
`)
|
||||
}
|
||||
|
||||
func (b bd82x6x) 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 << 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()
|
||||
b.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"
|
||||
|
||||
/* Not strictly speaking correct. These subsys/subvendor referer to PCI devices.
|
||||
But most systems don't have any of those. But the config needs to be set
|
||||
nevertheless. So set it to southbridge subsys/subvendor. */
|
||||
KconfigHex["MAINBOARD_PCI_SUBSYSTEM_VENDOR_ID"] = uint32(GetLE16(addr.ConfigDump[0x2c:0x2e]))
|
||||
KconfigHex["MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID"] = uint32(GetLE16(addr.ConfigDump[0x2e:0x30]))
|
||||
|
||||
ich9GetFlashSize(ctx)
|
||||
|
||||
DSDTDefines = append(DSDTDefines,
|
||||
DSDTDefine{
|
||||
Key: "BRIGHTNESS_UP",
|
||||
Value: "\\_SB.PCI0.GFX0.INCB",
|
||||
},
|
||||
DSDTDefine{
|
||||
Key: "BRIGHTNESS_DOWN",
|
||||
Value: "\\_SB.PCI0.GFX0.DECB",
|
||||
},
|
||||
DSDTDefine{
|
||||
Key: "ACPI_VIDEO_DEVICE",
|
||||
Value: "\\_SB.PCI0.GFX0",
|
||||
})
|
||||
|
||||
/* SPI init */
|
||||
MainboardIncludes = append(MainboardIncludes, "southbridge/intel/bd82x6x/pch.h")
|
||||
/* FIXME:XX Move this to runtime. */
|
||||
for _, addr := range []uint16{0x38c8, 0x38c4, 0x38c0} {
|
||||
MainboardInit += fmt.Sprintf("\tRCBA32(0x%04x) = 0x%08x;\n", addr, inteltool.RCBA[addr])
|
||||
}
|
||||
|
||||
FADT := ctx.InfoSource.GetACPI()["FACP"]
|
||||
|
||||
pcieHotplugMap := "{ "
|
||||
|
||||
for port := 0; port < 7; port++ {
|
||||
if b.IsPCIeHotplug(ctx, port) {
|
||||
pcieHotplugMap += "1, "
|
||||
} else {
|
||||
pcieHotplugMap += "0, "
|
||||
}
|
||||
}
|
||||
|
||||
if b.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),
|
||||
|
||||
"p_cnt_throttling_supported": (FormatBool(FADT[104] == 1 && FADT[105] == 3)),
|
||||
"c2_latency": FormatHexLE16(FADT[96:98]),
|
||||
"docking_supported": (FormatBool((FADT[113] & (1 << 1)) != 0)),
|
||||
},
|
||||
PCISlots: []PCISlot{
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x14, Func: 0}, writeEmpty: false, additionalComment: "USB 3.0 Controller"},
|
||||
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: 0x19, Func: 0}, writeEmpty: true, additionalComment: "Intel Gigabit Ethernet"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1a, Func: 0}, writeEmpty: true, 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: true, additionalComment: "PCIe Port #7"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 7}, writeEmpty: true, additionalComment: "PCIe Port #8"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1d, Func: 0}, writeEmpty: true, additionalComment: "USB2 EHCI #1"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1e, Func: 0}, writeEmpty: true, additionalComment: "PCI bridge"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 0}, writeEmpty: true, additionalComment: "LPC bridge"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 2}, writeEmpty: true, additionalComment: "SATA Controller 1"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 3}, writeEmpty: true, additionalComment: "SMBus"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 5}, writeEmpty: true, additionalComment: "SATA Controller 2"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 6}, writeEmpty: true, 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, "PCI-LPC bridge", "lpc")
|
||||
|
||||
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||
File: "southbridge/intel/bd82x6x/acpi/platform.asl",
|
||||
})
|
||||
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||
File: "southbridge/intel/bd82x6x/acpi/globalnvs.asl",
|
||||
Comment: "global NVS and variables",
|
||||
})
|
||||
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||
File: "southbridge/intel/bd82x6x/acpi/sleepstates.asl",
|
||||
})
|
||||
DSDTPCI0Includes = append(DSDTPCI0Includes, DSDTInclude{
|
||||
File: "southbridge/intel/bd82x6x/acpi/pch.asl",
|
||||
})
|
||||
|
||||
sb := Create(ctx, "early_southbridge.c")
|
||||
defer sb.Close()
|
||||
AddROMStageFile("early_southbridge.c", "")
|
||||
sb.WriteString(`#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <lib.h>
|
||||
#include <timestamp.h>
|
||||
#include <arch/byteorder.h>
|
||||
#include <arch/io.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <device/pnp_def.h>
|
||||
#include <cpu/x86/lapic.h>
|
||||
#include <arch/acpi.h>
|
||||
#include <console/console.h>
|
||||
#include "northbridge/intel/sandybridge/sandybridge.h"
|
||||
#include "northbridge/intel/sandybridge/raminit_native.h"
|
||||
#include "southbridge/intel/bd82x6x/pch.h"
|
||||
#include "southbridge/intel/bd82x6x/gpio.h"
|
||||
#include <arch/cpu.h>
|
||||
#include <cpu/x86/msr.h>
|
||||
|
||||
void pch_enable_lpc(void)
|
||||
{
|
||||
`)
|
||||
RestorePCI16Simple(sb, addr, 0x82)
|
||||
RestorePCI32Simple(sb, addr, 0x84)
|
||||
RestorePCI32Simple(sb, addr, 0x88)
|
||||
RestorePCI32Simple(sb, addr, 0x8c)
|
||||
RestorePCI32Simple(sb, addr, 0x90)
|
||||
|
||||
RestorePCI16Simple(sb, addr, 0x80)
|
||||
|
||||
RestorePCI32Simple(sb, addr, 0xac)
|
||||
|
||||
sb.WriteString(`}
|
||||
|
||||
void rcba_config(void)
|
||||
{
|
||||
/* Disable devices. */
|
||||
`)
|
||||
RestoreRCBA32(sb, inteltool, 0x3414)
|
||||
RestoreRCBA32(sb, inteltool, 0x3418)
|
||||
|
||||
sb.WriteString("\n}\n")
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(sb, "\t{ %d, %d, %d },\n",
|
||||
((inteltool.RCBA[0x359c]>>port)&1)^1,
|
||||
currentMap[inteltool.RCBA[uint16(0x3500+4*port)]],
|
||||
OCPin)
|
||||
}
|
||||
sb.WriteString("};\n")
|
||||
|
||||
guessedMap := GuessSPDMap(ctx)
|
||||
|
||||
sb.WriteString(`
|
||||
/* FIXME: Put proper SPD map here. */
|
||||
void mainboard_get_spd(spd_raw_data *spd)
|
||||
{
|
||||
`)
|
||||
for i, spd := range guessedMap {
|
||||
fmt.Fprintf(sb, "\tread_spd(&spd[%d], 0x%02x);\n", i, spd)
|
||||
}
|
||||
sb.WriteString("}\n")
|
||||
|
||||
gnvs := Create(ctx, "gnvs.c")
|
||||
defer gnvs.Close()
|
||||
|
||||
gnvs.WriteString(`#include <southbridge/intel/bd82x6x/nvs.h>
|
||||
|
||||
/* FIXME: check this function. */
|
||||
void acpi_create_gnvs(global_nvs_t *gnvs)
|
||||
{
|
||||
/* Disable USB ports in S3 by default */
|
||||
gnvs->s3u0 = 0;
|
||||
gnvs->s3u1 = 0;
|
||||
|
||||
/* Disable USB ports in S5 by default */
|
||||
gnvs->s5u0 = 0;
|
||||
gnvs->s5u1 = 0;
|
||||
|
||||
// the lid is open by default.
|
||||
gnvs->lids = 1;
|
||||
|
||||
gnvs->tcrt = 100;
|
||||
gnvs->tpsv = 90;
|
||||
}
|
||||
`)
|
||||
|
||||
AddRAMStageFile("gnvs.c", "")
|
||||
}
|
||||
|
||||
func init() {
|
||||
/* BD82X6X LPC */
|
||||
for _, id := range []uint16{
|
||||
0x1c46, 0x1c47, 0x1c49, 0x1c4a,
|
||||
0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e,
|
||||
0x1c4f, 0x1c50, 0x1c52, 0x1c54,
|
||||
0x1c56, 0x1c5c,
|
||||
} {
|
||||
RegisterPCI(0x8086, id, bd82x6x{variant: "BD82X6X"})
|
||||
}
|
||||
|
||||
/* C216 LPC */
|
||||
for _, id := range []uint16{
|
||||
0x1e55, 0x1e57, 0x1e5d, 0x1e5e, 0x1e5f, 0x1e49,
|
||||
} {
|
||||
RegisterPCI(0x8086, 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,
|
||||
} {
|
||||
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{})
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func FIXMEEC(ctx Context) {
|
||||
ap := Create(ctx, "acpi/platform.asl")
|
||||
defer ap.Close()
|
||||
|
||||
hasKeyboard := IsIOPortUsedBy(ctx, 0x60, "keyboard")
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
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");
|
||||
}
|
||||
`
|
||||
|
||||
si := Create(ctx, "acpi/superio.asl")
|
||||
defer si.Close()
|
||||
|
||||
if hasKeyboard {
|
||||
si.WriteString("#include <drivers/pc80/ps2_controller.asl>\n")
|
||||
MainboardInit += fmt.Sprintf("\tpc_keyboard_init();\n")
|
||||
MainboardIncludes = append(MainboardIncludes, "pc80/keyboard.h")
|
||||
}
|
||||
|
||||
ec := Create(ctx, "acpi/ec.asl")
|
||||
defer ec.Close()
|
||||
|
||||
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")
|
||||
}
|
|
@ -0,0 +1,295 @@
|
|||
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)
|
||||
|
||||
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()
|
||||
|
||||
si.WriteString("#include <drivers/pc80/ps2_controller.asl>\n")
|
||||
|
||||
dock := Create(ctx, "dock.c")
|
||||
defer dock.Close()
|
||||
|
||||
AddRAMStageFile("dock.c", "")
|
||||
|
||||
dock.WriteString(
|
||||
`#include <ec/lenovo/h8/h8.h>
|
||||
|
||||
void h8_mainboard_init_dock (void)
|
||||
{
|
||||
/* FIXME: fill this if needed. */
|
||||
}
|
||||
`)
|
||||
|
||||
/* FIXME:XX Move this to ec/lenovo. */
|
||||
smi := Create(ctx, "smihandler.c")
|
||||
defer smi.Close()
|
||||
|
||||
AddSMMFile("smihandler.c", "")
|
||||
|
||||
smi.WriteString(
|
||||
`/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2008-2009 coresystems GmbH
|
||||
* Copyright (C) 2014 Vladimir Serbinenko
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; version 2 of
|
||||
* the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc.
|
||||
*/
|
||||
|
||||
#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_smm_init(void)
|
||||
{
|
||||
printk(BIOS_DEBUG, "initializing SMI\n");
|
||||
/* Enable 0x1600/0x1600 register pair */
|
||||
ec_set_bit(0x00, 0x05);
|
||||
}
|
||||
|
||||
int mainboard_io_trap_handler(int smif)
|
||||
{
|
||||
static int smm_initialized;
|
||||
|
||||
if (!smm_initialized) {
|
||||
mainboard_smm_init();
|
||||
smm_initialized = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
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": "0x01",
|
||||
"dock_event_enable": "0x01",
|
||||
},
|
||||
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,23 @@
|
|||
package main
|
||||
|
||||
func NoEC(ctx Context) {
|
||||
ap := Create(ctx, "acpi/platform.asl")
|
||||
defer ap.Close()
|
||||
|
||||
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,88 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func RunAndSave(output string, name string, arg ...string) {
|
||||
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 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cmd.Wait()
|
||||
}
|
||||
|
||||
func MakeLogs(outDir string) {
|
||||
os.MkdirAll(outDir, 0700)
|
||||
RunAndSave(outDir+"/lspci.log", "lspci", "-nnvvvxxxx")
|
||||
RunAndSave(outDir+"/dmidecode.log", "dmidecode")
|
||||
RunAndSave(outDir+"/acpidump.log", "acpidump")
|
||||
/* FIXME:XX */
|
||||
RunAndSave(outDir+"/inteltool.log", "../inteltool/inteltool", "-a")
|
||||
RunAndSave(outDir+"/ectool.log", "../ectool/ectool", "-a")
|
||||
|
||||
SysDir := "/sys/class/sound/card0/"
|
||||
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/card0/"
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,370 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"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()
|
||||
switch {
|
||||
case len(line) >= 6 && line[5] == '@':
|
||||
curTable = line[0:4]
|
||||
Tables[curTable] = make([]byte, 0, 100000)
|
||||
case len(line) > 7 && line[0:2] == " " && isXDigit(line[2]) && isXDigit(line[3]) && isXDigit(line[4]) && isXDigit(line[5]) && line[6] == ':':
|
||||
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.IGD = map[uint32]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) > 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 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, "============="):
|
||||
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) {
|
||||
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_hwC0D" + 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
|
||||
}
|
||||
|
||||
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,858 @@
|
|||
/* 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
|
||||
IGD map[uint32]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
|
||||
}
|
||||
|
||||
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 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
|
||||
}
|
||||
|
||||
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 KconfigStringUnquoted 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)
|
||||
for strings.HasSuffix(result, ".") {
|
||||
result = result[0 : len(result)-1]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
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 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
|
||||
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
|
||||
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, 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":
|
||||
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.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 {
|
||||
WriteDev(dt, offset+1, 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)
|
||||
}
|
||||
|
||||
func (g GenericVGA) Scan(ctx Context, addr PCIDevData) {
|
||||
KconfigString["VGA_BIOS_ID"] = fmt.Sprintf("%04x,%04x",
|
||||
addr.PCIVenID,
|
||||
addr.PCIDevID)
|
||||
KconfigString["VGA_BIOS_FILE"] = fmt.Sprintf("pci%04x,%04x.rom",
|
||||
addr.PCIVenID,
|
||||
addr.PCIDevID)
|
||||
PutPCIDevParent(addr, g.Comment, g.MissingParent)
|
||||
}
|
||||
|
||||
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 # dummy\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 KconfigStringUnquoted {
|
||||
keys = append(keys, name)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, name := range keys {
|
||||
fmt.Fprintf(kc, `
|
||||
config %s%s
|
||||
string
|
||||
default %s
|
||||
`, name, makeComment(name), KconfigStringUnquoted[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 := sanitize(ctx.Vendor)
|
||||
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, 0x51, 0x52, 0x53}
|
||||
}
|
||||
return []uint8{0x50, 0x52, 0x51, 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.MoboID = sanitize(ctx.Vendor) + "/" + sanitize(ctx.Model)
|
||||
ctx.KconfigName = "BOARD_" + strings.ToUpper(sanitize(ctx.Vendor)+"_"+sanitize(ctx.Model))
|
||||
ctx.BaseDirectory = *FlagOutDir + MoboDir + ctx.MoboID
|
||||
KconfigStringUnquoted["MAINBOARD_DIR"] = ctx.MoboID
|
||||
KconfigString["MAINBOARD_PART_NUMBER"] = ctx.Model
|
||||
|
||||
os.MkdirAll(ctx.BaseDirectory, 0700)
|
||||
|
||||
makeVendor(ctx)
|
||||
|
||||
ScanRoot(ctx)
|
||||
|
||||
if len(ROMStageFiles) > 0 || len(RAMStageFiles) > 0 || len(SMMFiles) > 0 {
|
||||
mf := Create(ctx, "Makefile.inc")
|
||||
defer mf.Close()
|
||||
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()
|
||||
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(device_t dev)
|
||||
{
|
||||
` + MainboardInit + "}\n\n")
|
||||
}
|
||||
if MainboardInit != "" || MainboardEnable != "" {
|
||||
mainboard.WriteString("static void mainboard_enable(device_t 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,
|
||||
};
|
||||
`)
|
||||
}
|
||||
}
|
||||
|
||||
at := Create(ctx, "acpi_tables.c")
|
||||
defer at.Close()
|
||||
at.WriteString("/* dummy */\n")
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
rs := Create(ctx, "romstage.c")
|
||||
defer rs.Close()
|
||||
rs.WriteString("/* dummy file */\n")
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
dsdt.WriteString(
|
||||
`DefinitionBlock(
|
||||
"dsdt.aml",
|
||||
"DSDT",
|
||||
0x03, // DSDT revision: ACPI v3.0
|
||||
"COREv4", // OEM id
|
||||
"COREBOOT", // OEM table id
|
||||
0x20141018 // OEM revision
|
||||
)
|
||||
{
|
||||
// Some generic macros
|
||||
#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(`
|
||||
Scope (\_SB) {
|
||||
Device (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(
|
||||
` }
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
}
|
|
@ -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,383 @@
|
|||
# Porting coreboot using autoport
|
||||
|
||||
## Supported platforms
|
||||
|
||||
### Chipset.
|
||||
For any sandybridge or ivybridge platform generated result should
|
||||
be bootable, possibly with minor fixes.
|
||||
|
||||
### EC
|
||||
EC support is likely to work on intel-based thinkpads. Other laptops are likely to miss EC support
|
||||
|
||||
## How to use
|
||||
|
||||
* Go into BIOS setup on target machine and enable all the device.
|
||||
This will allow autoport to detect as much as possible
|
||||
* Boot into target machine under GNU/Linux
|
||||
* Make sure you have GCC and golang installed
|
||||
* Grab coreboot tree
|
||||
* Execute following commands starting from coreboot tree
|
||||
|
||||
cd util/ectool
|
||||
make
|
||||
cd ../inteltool
|
||||
make
|
||||
cd ../autoport
|
||||
go build
|
||||
./autoport --input_log=logs --make_logs --coreboot_dir=../..
|
||||
|
||||
* Look for output unknown PCI devices. E.g.
|
||||
|
||||
Unknown PCI device 8086:0085, assuming removable
|
||||
|
||||
If autoport says `assuming removable` then you're fine. If it doesn't
|
||||
then you may want to add relevant PCIIDs to autoport. When rerunning
|
||||
you can skip argument `--make_logs` to reuse the same logs
|
||||
|
||||
* At this point the new board is added to the tree but don't flash it
|
||||
yet as it will brick you machine. Instead keep this new port and logs
|
||||
from `util/autoport/logs` somewhere safe
|
||||
|
||||
* Disassemble your laptop and locate flash chip <http://flashrom.org/Technology>
|
||||
is a great resource. Flash chip is usually in `SOIC-8` (2x4 pins) or `SOIC-16`
|
||||
(2x8 chips). You'll probably have several candidates. Look up what's written on
|
||||
them and look up what's this chip on the web.
|
||||
|
||||
* Once you know what's the chip is, get external flasher and read it. Twice. Compare
|
||||
the results and retry if they differ. Save the result somewhere safe, in preference
|
||||
copy to read-only storage as backup.
|
||||
|
||||
* Compile coreboot with console enabled (EHCI debug or serial if present are recommended)
|
||||
|
||||
* For recent intel chipsets you need to avoid overwriting ME firmware. Recommended procedure is
|
||||
(replace 8 with your flash size in MiB):
|
||||
|
||||
cp backup.rom flash.rom
|
||||
dd if=coreboot/build/coreboot.rom skip=$[8-1] seek=$[8-1] bs=1M of=flash.rom
|
||||
|
||||
* Flash the result
|
||||
* Boot and grab the log and fix the issues. See next section for useful info.
|
||||
* grep your board for FIXME. autoport adds comments when it's unsure. Sometimes it's just
|
||||
a minor check and sometimes it needs more involvment. See next section.
|
||||
* Send new board to review.coreboot.org. I mean it, your effort is very appreciated.
|
||||
|
||||
## Manual fixes
|
||||
### SPD
|
||||
If you're able to use full memory with any combination of inserted modules than this is
|
||||
most likely correct. In order to initialize the memory coreboot needs to know RAM timings.
|
||||
For socketed RAM it's stored in a small EEPROM chip which can be accessed through SPD. Unfortunately
|
||||
mapping between SPD addresses and RAM slots differs and cannot always be detected automatically.
|
||||
Resulting SPD map is encoded in function `mainboard_get_spd` in `early_southbridge.c`.
|
||||
autoport uses the most common map `0x50, 0x51, 0x52, 0x53` except for lenovos which are
|
||||
known to use `0x50, 0x52, 0x51, 0x53`. To detect the correct memory map the easiest way is with
|
||||
vendor BIOS to boot with just one module in channel 0 slot 0 and then see where does it show
|
||||
up in SPD. Under Linux you can see present SPD addresses with following commands:
|
||||
|
||||
phcoder@sid:~/coreboot/util/autoport$ sudo modprobe i2c-dev
|
||||
phcoder@sid:~/coreboot/util/autoport$ 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
|
||||
phcoder@sid:~/coreboot/util/autoport$ 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 `9` with whatever bus is marked as smbus. Here in an example
|
||||
you see SPD at address `0x50`. Since we've booted with just the module in C0S0, so
|
||||
the first entry in SPD map has to be `0x50`. Once you have SPD map your
|
||||
`mainboard_get_spd` should look something like:
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
You can and should omit lines which correspond to
|
||||
slots not present on your machine.
|
||||
|
||||
This way works well if your RAM is socketed. For soldered RAM if you see
|
||||
its SPD, you're in a luck and can proceed the same way although you may have to
|
||||
guess some entries due to RAM not being removable.
|
||||
|
||||
Most cases of soldered RAM don't have EEPROM chip. In this case you'd have to create
|
||||
fake SPD. Look in `inteltool.log`. You'll see something like:
|
||||
|
||||
/* 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 completely exact represantation of RAM
|
||||
capablities as it lists only the mode currently used
|
||||
and lacks minor info like serial number. Using `xxd`
|
||||
you can create binary represantation of this SPD:
|
||||
|
||||
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
|
||||
|
||||
Then you can place this file into mainboard directory
|
||||
and hook it up into build system by adding following
|
||||
lines to `Makefile.inc` (creating a new file if needed)
|
||||
|
||||
cbfs-files-y += spd.bin
|
||||
spd.bin-file := spd.bin
|
||||
spd.bin-type := raw
|
||||
|
||||
And then make coreboot actually use this SPD. Following
|
||||
example shows a hybrid situation with one module
|
||||
soldered and another 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_get_file_content(CBFS_DEFAULT_MEDIA, "spd.bin", CBFS_TYPE_RAW,
|
||||
&spd_file_len);
|
||||
if (spd_file && spd_file_len >= 128)
|
||||
memcpy(&spd[0], spd_file, 128);
|
||||
/* C0S0 is a DIMM slot. */
|
||||
read_spd(&spd[1], 0x51);
|
||||
}
|
||||
|
||||
If several slots are soldered there are 3 ways of doing things:
|
||||
|
||||
* If all of them are the same use the same file. Don't forget to copy
|
||||
it to all array elements.
|
||||
* Use several files (recommended). Name them e.g. spd1, spd2,...
|
||||
* Concatenate it into a single file and split into several
|
||||
array elements on runtime. Not recommended
|
||||
|
||||
### `board_info.txt`
|
||||
|
||||
`board_info.txt` is a simple text file used to generate wiki page
|
||||
listing supported boards. Some of the info can't be detected automatically.
|
||||
|
||||
As this is used only to present information to users then when it matches
|
||||
your board and definitions it is correct.
|
||||
|
||||
* Which package is used for ROM and whether it's socketed, as well
|
||||
as release year. For ROM package refer to <http://flashrom.org/Technology>
|
||||
and compare it with ROM you found at the beginning of the port. Set
|
||||
`ROM package`, `ROM socketed` and other variables mentioned in FIXME.
|
||||
* Release year, just go to web and find that information.
|
||||
* Category. It's difficult to make difference between desktop and similar
|
||||
categories from inside the computer. Valid categories are:
|
||||
* `desktop`. Desktops and workstations.
|
||||
* `server`. Servers
|
||||
* `laptop`. Laptops.
|
||||
* `half`. Embedded / PC/104 / Half-size boards.
|
||||
* `mini`. Mini-ITX / Micro-ITX / Nano-ITX
|
||||
* `settop`. Set-top-boxes / Thin clients.
|
||||
* `eval`. Devel/Eval 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. You probably shouldn't use
|
||||
this.
|
||||
|
||||
### `USBDEBUG_HCD_INDEX`
|
||||
|
||||
Which controller the most easily accessible USB debug port is. On intel
|
||||
1 is for `00:1d.0` and 2 is `00:1a.0` (yes, it's reversed). See
|
||||
<http://www.coreboot.org/EHCI_Debug_Port> for more info.
|
||||
|
||||
If you're able to use EHCI debug port without setting HCD index manually
|
||||
in config this is correct.
|
||||
|
||||
### `BOARD_ROMSIZE_KB_2048`
|
||||
|
||||
Default rom size should be detected automatically but sometimes isn't.
|
||||
If yours weren't detected put correct rom size here to serve as sane
|
||||
default when configuring coreboot.
|
||||
|
||||
If default ROM size when slecting the board is right one than this value
|
||||
is correct.
|
||||
|
||||
### `DRAM_RESET_GATE_GPIO`
|
||||
|
||||
When machine is going to S3 in order not to reset the RAM modules, the
|
||||
reset signal must be filtered out from reachin RAM. This is done by
|
||||
powering down a special gate. Most manufacturers put this gate on
|
||||
GPIO 60 but Lenovo is knowon to put it on GPIO 10. If you're able to
|
||||
go to S3 and back than this value is correct.
|
||||
|
||||
## GNVS
|
||||
|
||||
`acpi_create_gnvs` sets values in GNVS which in turn is used by ACPI for
|
||||
various power-related functions. Normally there is no need to modify it
|
||||
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 adjust but if you miss some nonstandard output
|
||||
you can declare it there. Bit 31 is set to indicate 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 no need to modify unless
|
||||
your device has very special power saving requirements.
|
||||
|
||||
## `install_intel_vga_int15_handler`
|
||||
|
||||
This is used to configure int15 hook used by vga bios. Parameters 2 and 3 usually
|
||||
shouldn't be modified as vgabios is quite ok to figure panel fit and active output
|
||||
by itself. Last number is the numerical ID of display type. If you don't get any output
|
||||
with VGABIOS you should try different values for 4th parameter. If it doesn't help
|
||||
try different values for first parameter as well
|
||||
|
||||
## CMOS options
|
||||
|
||||
Due to horrible state of CMOS support in coreboot tree, autoport doesn't support it and
|
||||
this probably won't change until 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
|
||||
need to fill `h8_mainboard_init_dock` and add support code to
|
||||
DSDT. See the code for `x60`, `x200` or `x201`
|
||||
|
||||
## EC (generic laptop)
|
||||
|
||||
Almost any laptop has an embedded controller. In nutshell it's a small
|
||||
low-powered computer specialised on managing power for laptop. Exact
|
||||
functionality differs between macines but of interest to us is mainly:
|
||||
|
||||
* 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,42 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
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)
|
||||
}
|
||||
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,159 @@
|
|||
package main
|
||||
|
||||
type sandybridgemc struct {
|
||||
variant string
|
||||
}
|
||||
|
||||
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 those values*/
|
||||
install_intel_vga_int15_handler(GMA_INT15_ACTIVE_LFP_INT_LVDS, GMA_INT15_PANEL_FIT_DEFAULT, GMA_INT15_BOOT_DISPLAY_DEFAULT, 0);
|
||||
`)
|
||||
|
||||
pchLVDS := inteltool.IGD[0xe1180]
|
||||
dualChannel := pchLVDS&(3<<2) == (3 << 2)
|
||||
pipe := (pchLVDS >> 30) & 1
|
||||
data_m1 := inteltool.IGD[0x60030+0x1000*pipe] & 0xffffff
|
||||
data_n1 := inteltool.IGD[0x60034+0x1000*pipe]
|
||||
link_m1 := inteltool.IGD[0x60040+0x1000*pipe]
|
||||
link_n1 := inteltool.IGD[0x60044+0x1000*pipe]
|
||||
data_factor := float32(data_m1) / float32(data_n1)
|
||||
link_factor := float32(link_m1) / float32(link_n1)
|
||||
num_lanes := uint32((link_factor/data_factor)*18.0/8.0 + 0.5)
|
||||
fp0 := inteltool.IGD[0xc6040+8*pipe]
|
||||
dpll := inteltool.IGD[0xc6014+4*pipe]
|
||||
pixel_m2 := fp0 & 0xff
|
||||
pixel_m1 := (fp0>>8)&0xff + 2
|
||||
pixel_p1 := uint32(1)
|
||||
for i := dpll & 0x1ffff; i != 0 && i&1 == 0; i >>= 1 {
|
||||
pixel_p1++
|
||||
}
|
||||
pixel_n := ((fp0 >> 16) & 0xff) + 2
|
||||
pixel_frequency := float32(120000*(5*pixel_m1+pixel_m2)) / float32(pixel_n*pixel_p1*7.0)
|
||||
if !dualChannel {
|
||||
pixel_frequency /= 2
|
||||
}
|
||||
link_frequency := pixel_frequency / link_factor
|
||||
DevTree = DevTreeNode{
|
||||
Chip: "northbridge/intel/sandybridge",
|
||||
MissingParent: "northbridge",
|
||||
Comment: "FIXME: check gfx.ndid and gfx.did",
|
||||
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.use_spread_spectrum_clock": FormatBool((inteltool.IGD[0xc6200]>>12)&1 != 0),
|
||||
"gfx.lvds_dual_channel": FormatBool(dualChannel),
|
||||
"gfx.lvds_num_lanes": FormatInt32(num_lanes),
|
||||
"gfx.link_frequency_270_mhz": FormatBool(link_frequency > 200000),
|
||||
/* FIXME:XX hardcoded. */
|
||||
"gfx.ndid": "3",
|
||||
"gfx.did": "{ 0x80000100, 0x80000240, 0x80000410, 0x80000410, 0x00000005 }",
|
||||
},
|
||||
Children: []DevTreeNode{
|
||||
{
|
||||
Chip: "cpu_cluster",
|
||||
Dev: 0,
|
||||
Children: []DevTreeNode{
|
||||
{
|
||||
Chip: "cpu/intel/socket_rPGA989",
|
||||
Children: []DevTreeNode{
|
||||
{
|
||||
Chip: "lapic",
|
||||
Dev: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Chip: "cpu/intel/model_206ax",
|
||||
Comment: "FIXME: check all registers",
|
||||
Registers: map[string]string{
|
||||
/* FIXME:XX hardcoded. */
|
||||
"c1_acpower": "1",
|
||||
"c2_acpower": "3",
|
||||
"c3_acpower": "5",
|
||||
"c1_battery": "1",
|
||||
"c2_battery": "3",
|
||||
"c3_battery": "5",
|
||||
},
|
||||
Children: []DevTreeNode{
|
||||
{
|
||||
Chip: "lapic",
|
||||
Dev: 0xacac,
|
||||
Disabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Chip: "domain",
|
||||
Dev: 0,
|
||||
PCIController: true,
|
||||
ChildPCIBus: 0,
|
||||
PCISlots: []PCISlot{
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x0, Func: 0}, writeEmpty: true, additionalComment: "Host bridge"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x1, Func: 0}, writeEmpty: true, additionalComment: "PCIe Bridge for discrete graphics"},
|
||||
PCISlot{PCIAddr: PCIAddr{Dev: 0x2, Func: 0}, writeEmpty: true, additionalComment: "Internal graphics"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
PutPCIDev(addr, "Host bridge")
|
||||
|
||||
/* FIXME:XX Move part to northbridge? */
|
||||
/* FIXME:XX some configs are unsupported. */
|
||||
KconfigBool["MAINBOARD_HAS_NATIVE_VGA_INIT"] = true
|
||||
KconfigBool["MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG"] = true
|
||||
KconfigBool[i.variant+"BRIDGE_LVDS"] = true
|
||||
|
||||
KconfigBool["VGA"] = true
|
||||
KconfigBool["INTEL_EDID"] = true
|
||||
KconfigBool["CPU_INTEL_SOCKET_RPGA989"] = true
|
||||
KconfigBool["NORTHBRIDGE_INTEL_"+i.variant+"BRIDGE_NATIVE"] = true
|
||||
KconfigBool["INTEL_INT15"] = true
|
||||
KconfigBool["HAVE_ACPI_TABLES"] = true
|
||||
KconfigBool["HAVE_ACPI_RESUME"] = true
|
||||
|
||||
KconfigBool["HAVE_IFD_BIN"] = false
|
||||
KconfigBool["HAVE_ME_BIN"] = false
|
||||
|
||||
KconfigHex["MMCONF_BASE_ADDRESS"] = 0xf0000000
|
||||
KconfigInt["MAX_CPUS"] = 8
|
||||
|
||||
DSDTIncludes = append(DSDTIncludes, DSDTInclude{
|
||||
File: "cpu/intel/model_206ax/acpi/cpu.asl",
|
||||
})
|
||||
|
||||
DSDTPCI0Includes = append(DSDTPCI0Includes, DSDTInclude{
|
||||
File: "northbridge/intel/sandybridge/acpi/sandybridge.asl",
|
||||
})
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterPCI(0x8086, 0x0100, sandybridgemc{variant: "SANDY"})
|
||||
RegisterPCI(0x8086, 0x0104, sandybridgemc{variant: "SANDY"})
|
||||
RegisterPCI(0x8086, 0x0150, sandybridgemc{variant: "IVY"})
|
||||
RegisterPCI(0x8086, 0x0154, sandybridgemc{variant: "IVY"})
|
||||
for _, id := range []uint16{
|
||||
0x0102, 0x0106, 0x010a, 0x0112,
|
||||
0x0116, 0x0122, 0x0126, 0x0156,
|
||||
0x0166,
|
||||
} {
|
||||
RegisterPCI(0x8086, id, GenericVGA{GenericPCI{Comment: "VGA controller"}})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue