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