xref: /aosp_15_r20/external/coreboot/util/autoport/lynxpoint.go (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1package main
2
3import "fmt"
4
5type LPVariant int
6
7const (
8	LYNX_POINT_MOBILE LPVariant = iota
9	LYNX_POINT_DESKTOP
10	LYNX_POINT_SERVER
11	LYNX_POINT_ULT
12)
13
14type lynxpoint struct {
15	variant LPVariant
16	node    *DevTreeNode
17}
18
19func lpPchGetFlashSize(ctx Context) {
20	inteltool := ctx.InfoSource.GetInteltool()
21	/* In LP PCH, Boot BIOS Straps field in GCS has only one bit.  */
22	switch (inteltool.RCBA[0x3410] >> 10) & 1 {
23	case 0:
24		ROMProtocol = "SPI"
25		highflkb := uint32(0)
26		for reg := uint16(0); reg < 5; reg++ {
27			fl := (inteltool.RCBA[0x3854+4*reg] >> 16) & 0x1fff
28			flkb := (fl + 1) << 2
29			if flkb > highflkb {
30				highflkb = flkb
31			}
32		}
33		ROMSizeKB = int(highflkb)
34		FlashROMSupport = "y"
35	}
36}
37
38func (b lynxpoint) GetGPIOHeader() string {
39	return "southbridge/intel/lynxpoint/pch.h"
40}
41
42func (b lynxpoint) EnableGPE(in int) {
43	if b.variant != LYNX_POINT_ULT {
44		b.node.Registers[fmt.Sprintf("gpi%d_routing", in)] = "2"
45	}
46}
47
48func (b lynxpoint) EncodeGPE(in int) int {
49	return in + 0x10
50}
51
52func (b lynxpoint) DecodeGPE(in int) int {
53	return in - 0x10
54}
55
56func (b lynxpoint) NeedRouteGPIOManually() {
57	b.node.Comment += ", FIXME: set gpiX_routing for EC support"
58}
59
60func GetLptDesktopEHCISetting(loc_param uint32, txamp uint32) (string, int) {
61	var port_pos string
62	var port_length int
63
64	if loc_param == 4 {
65		port_pos = "USB_PORT_BACK_PANEL"
66		if txamp <= 2 {
67			port_length = 0x40
68		} else if txamp >= 4 {
69			port_length = 0x140
70		} else {
71			port_length = 0x110
72		}
73	} else {
74		port_pos = "USB_PORT_FLEX"
75		port_length = 0x40
76	}
77	return port_pos, port_length
78}
79
80func GetLptMobileEHCISetting(loc_param uint32, txamp uint32) (string, int) {
81	var port_pos string
82	var port_length int
83
84	if loc_param == 4 {
85		port_pos = "USB_PORT_DOCK"
86		if txamp <= 1 {
87			port_length = 0x40
88		} else {
89			port_length = 0x80
90		}
91	} else if loc_param == 6 {
92		/* not internal, not dock, port_length >= 0x70 */
93		port_pos = "USB_PORT_BACK_PANEL"
94		if txamp <= 2 {
95			port_length = 0x80
96		} else {
97			port_length = 0x110
98		}
99	} else {
100		port_pos = "USB_PORT_BACK_PANEL"
101		port_length = 0x40
102	}
103	return port_pos, port_length
104}
105
106func GetLptLPEHCISetting(loc_param uint32, txamp uint32) (string, int) {
107	var port_pos string
108	var port_length int
109
110	if loc_param == 6 {
111		/* back panel or mini pcie, length >= 0x70 */
112		port_pos = "USB_PORT_MINI_PCIE"
113		if txamp <= 2 {
114			port_length = 0x80
115		} else {
116			port_length = 0x110
117		}
118	} else if loc_param == 4 {
119		port_pos = "USB_PORT_DOCK"
120		if txamp <= 1 {
121			port_length = 0x40
122		} else {
123			port_length = 0x80
124		}
125	} else {
126		port_pos = "USB_PORT_BACK_PANEL"
127		port_length = 0x40
128	}
129	return port_pos, port_length
130}
131
132func (b lynxpoint) Scan(ctx Context, addr PCIDevData) {
133
134	SouthBridge = &b
135
136	inteltool := ctx.InfoSource.GetInteltool()
137
138	isULT := (b.variant == LYNX_POINT_ULT)
139
140	if isULT {
141		Lynxpoint_LP_GPIO(ctx, inteltool)
142	} else {
143		GPIO(ctx, inteltool)
144	}
145
146	KconfigBool["SOUTHBRIDGE_INTEL_LYNXPOINT"] = true
147	if isULT {
148		KconfigBool["INTEL_LYNXPOINT_LP"] = true
149	}
150	KconfigBool["SERIRQ_CONTINUOUS_MODE"] = true
151	if isULT {
152		KconfigInt["USBDEBUG_HCD_INDEX"] = 1
153	} else {
154		KconfigInt["USBDEBUG_HCD_INDEX"] = 2
155		KconfigComment["USBDEBUG_HCD_INDEX"] = "FIXME: check this"
156	}
157
158	if isULT {
159		lpPchGetFlashSize(ctx)
160	} else {
161		ich9GetFlashSize(ctx)
162	}
163
164	FADT := ctx.InfoSource.GetACPI()["FACP"]
165
166	sp0dtle_data := (inteltool.IOBP[0xea002750] >> 24) & 0xf
167	sp0dtle_edge := (inteltool.IOBP[0xea002754] >> 16) & 0xf
168	sp1dtle_data := (inteltool.IOBP[0xea002550] >> 24) & 0xf
169	sp1dtle_edge := (inteltool.IOBP[0xea002554] >> 16) & 0xf
170
171	if sp0dtle_data != sp0dtle_edge {
172		fmt.Printf("Different SATA Gen3 port0 DTLE data and edge values are used.\n")
173	}
174
175	if sp1dtle_data != sp1dtle_edge {
176		fmt.Printf("Different SATA Gen3 port1 DTLE data and edge values are used.\n")
177	}
178
179	cur := DevTreeNode{
180		Chip:    "southbridge/intel/lynxpoint",
181		Comment: "Intel Series 8 Lynx Point PCH",
182
183		/* alt_gp_smi_en is not generated because coreboot doesn't use SMI like OEM firmware */
184		Registers: map[string]string{
185			"gen1_dec":             FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x84:0x88]),
186			"gen2_dec":             FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x88:0x8c]),
187			"gen3_dec":             FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x8c:0x90]),
188			"gen4_dec":             FormatHexLE32(PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 0}].ConfigDump[0x90:0x94]),
189			"sata_port_map":        fmt.Sprintf("0x%x", PCIMap[PCIAddr{Bus: 0, Dev: 0x1f, Func: 2}].ConfigDump[0x92]&0x3f),
190			"docking_supported":    (FormatBool((FADT[113] & (1 << 1)) != 0)),
191			"sata_port0_gen3_dtle": fmt.Sprintf("0x%x", sp0dtle_data),
192			"sata_port1_gen3_dtle": fmt.Sprintf("0x%x", sp1dtle_data),
193		},
194		PCISlots: []PCISlot{
195			PCISlot{PCIAddr: PCIAddr{Dev: 0x13, Func: 0}, writeEmpty: isULT, additionalComment: "Smart Sound Audio DSP"},
196			PCISlot{PCIAddr: PCIAddr{Dev: 0x14, Func: 0}, writeEmpty: true, additionalComment: "xHCI Controller"},
197			PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 0}, writeEmpty: isULT, additionalComment: "Serial I/O DMA"},
198			PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 1}, writeEmpty: isULT, additionalComment: "I2C0"},
199			PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 2}, writeEmpty: isULT, additionalComment: "I2C1"},
200			PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 3}, writeEmpty: isULT, additionalComment: "GSPI0"},
201			PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 4}, writeEmpty: isULT, additionalComment: "GSPI1"},
202			PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 5}, writeEmpty: isULT, additionalComment: "UART0"},
203			PCISlot{PCIAddr: PCIAddr{Dev: 0x15, Func: 6}, writeEmpty: isULT, additionalComment: "UART1"},
204			PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 0}, writeEmpty: true, additionalComment: "Management Engine Interface 1"},
205			PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 1}, writeEmpty: true, additionalComment: "Management Engine Interface 2"},
206			PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 2}, writeEmpty: true, additionalComment: "Management Engine IDE-R"},
207			PCISlot{PCIAddr: PCIAddr{Dev: 0x16, Func: 3}, writeEmpty: true, additionalComment: "Management Engine KT"},
208			PCISlot{PCIAddr: PCIAddr{Dev: 0x17, Func: 0}, writeEmpty: isULT, additionalComment: "SDIO"},
209			PCISlot{PCIAddr: PCIAddr{Dev: 0x19, Func: 0}, writeEmpty: true, additionalComment: "Intel Gigabit Ethernet"},
210			PCISlot{PCIAddr: PCIAddr{Dev: 0x1a, Func: 0}, writeEmpty: !isULT, additionalComment: "USB2 EHCI #2"},
211			PCISlot{PCIAddr: PCIAddr{Dev: 0x1b, Func: 0}, writeEmpty: true, additionalComment: "High Definition Audio"},
212			PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 0}, writeEmpty: true, additionalComment: "PCIe Port #1"},
213			PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 1}, writeEmpty: true, additionalComment: "PCIe Port #2"},
214			PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 2}, writeEmpty: true, additionalComment: "PCIe Port #3"},
215			PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 3}, writeEmpty: true, additionalComment: "PCIe Port #4"},
216			PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 4}, writeEmpty: true, additionalComment: "PCIe Port #5"},
217			PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 5}, writeEmpty: true, additionalComment: "PCIe Port #6"},
218			PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 6}, writeEmpty: !isULT, additionalComment: "PCIe Port #7"},
219			PCISlot{PCIAddr: PCIAddr{Dev: 0x1c, Func: 7}, writeEmpty: !isULT, additionalComment: "PCIe Port #8"},
220			PCISlot{PCIAddr: PCIAddr{Dev: 0x1d, Func: 0}, writeEmpty: true, additionalComment: "USB2 EHCI #1"},
221			PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 0}, writeEmpty: true, additionalComment: "LPC bridge"},
222			PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 2}, writeEmpty: true, additionalComment: "SATA Controller (AHCI)"},
223			PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 3}, writeEmpty: true, additionalComment: "SMBus"},
224			PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 5}, writeEmpty: !isULT, additionalComment: "SATA Controller (Legacy)"},
225			PCISlot{PCIAddr: PCIAddr{Dev: 0x1f, Func: 6}, writeEmpty: true, additionalComment: "Thermal"},
226		},
227	}
228
229	if isULT {
230		cur.Registers["gpe0_en_1"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x90])
231		cur.Registers["gpe0_en_2"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x94])
232		cur.Registers["gpe0_en_3"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x98])
233		cur.Registers["gpe0_en_4"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x9c])
234	} else {
235		cur.Registers["gpe0_en_1"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x28])
236		cur.Registers["gpe0_en_2"] = fmt.Sprintf("0x%x", inteltool.PMBASE[0x2c])
237	}
238
239	b.node = &cur
240
241	PutPCIChip(addr, cur)
242	PutPCIDevParent(addr, "", "lpc")
243
244	DSDTIncludes = append(DSDTIncludes, DSDTInclude{
245		File: "southbridge/intel/common/acpi/platform.asl",
246	})
247	DSDTIncludes = append(DSDTIncludes, DSDTInclude{
248		File:    "southbridge/intel/lynxpoint/acpi/globalnvs.asl",
249		Comment: "global NVS and variables",
250	})
251	DSDTIncludes = append(DSDTIncludes, DSDTInclude{
252		File: "southbridge/intel/common/acpi/sleepstates.asl",
253	})
254	DSDTPCI0Includes = append(DSDTPCI0Includes, DSDTInclude{
255		File: "southbridge/intel/lynxpoint/acpi/pch.asl",
256	})
257
258	AddBootBlockFile("bootblock.c", "")
259	bb := Create(ctx, "bootblock.c")
260	defer bb.Close()
261	Add_gpl(bb)
262	bb.WriteString(`#include <southbridge/intel/lynxpoint/pch.h>
263
264/* FIXME: remove this if not needed */
265void mainboard_config_superio(void)
266{
267}
268`)
269
270	sb := Create(ctx, "romstage.c")
271	defer sb.Close()
272	Add_gpl(sb)
273	sb.WriteString(`#include <stdint.h>
274#include <northbridge/intel/haswell/haswell.h>
275#include <northbridge/intel/haswell/raminit.h>
276#include <southbridge/intel/lynxpoint/pch.h>
277
278void mainboard_config_rcba(void)
279{
280}
281
282/* FIXME: called after romstage_common, remove it if not used */
283void mb_late_romstage_setup(void)
284{
285}
286
287void mb_get_spd_map(struct spd_info *spdi)
288{
289	/* FIXME: check this */
290	spdi->addresses[0] = 0x50;
291	spdi->addresses[1] = 0x51;
292	spdi->addresses[2] = 0x52;
293	spdi->addresses[3] = 0x53;
294}
295
296const struct usb2_port_config mainboard_usb2_ports[MAX_USB2_PORTS] = {
297	/* FIXME: Length and Location are computed from IOBP values, may be inaccurate */
298	/* Length, Enable, OCn#, Location */
299`)
300
301	pdo1 := PCIMap[PCIAddr{Bus: 0, Dev: 0x1d, Func: 0}].ConfigDump[0x64]
302	ocmap1 := PCIMap[PCIAddr{Bus: 0, Dev: 0x1d, Func: 0}].ConfigDump[0x74:0x78]
303
304	var pdo2 uint8
305	var ocmap2 []uint8
306	var nPorts uint
307	if isULT {
308		nPorts = 8
309	} else {
310		pdo2 = PCIMap[PCIAddr{Bus: 0, Dev: 0x1a, Func: 0}].ConfigDump[0x64]
311		ocmap2 = PCIMap[PCIAddr{Bus: 0, Dev: 0x1a, Func: 0}].ConfigDump[0x74:0x78]
312		nPorts = 14
313	}
314
315	xusb2pr := GetLE16(PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xd0:0xd4])
316
317	for port := uint(0); port < nPorts; port++ {
318		var port_oc int = -1
319		var port_pos string
320		var port_disable uint8
321
322		if port < 8 {
323			port_disable = ((pdo1 >> port) & (uint8(xusb2pr>>port) ^ 1)) & 1
324			for oc := 0; oc < 4; oc++ {
325				if (ocmap1[oc] & (1 << port)) != 0 {
326					port_oc = oc
327					break
328				}
329			}
330		} else {
331			port_disable = ((pdo2 >> (port - 8)) & (uint8(xusb2pr>>port) ^ 1)) & 1
332			for oc := 0; oc < 4; oc++ {
333				if (ocmap2[oc] & (1 << (port - 8))) != 0 {
334					port_oc = oc + 4
335					break
336				}
337			}
338		}
339
340		/* get USB2 port length and location from IOBP */
341		port_iobp := inteltool.IOBP[0xe5004100+uint32(port)*0x100]
342		loc_param := (port_iobp >> 8) & 7
343		txamp := (port_iobp >> 11) & 7
344		var port_length int
345
346		if isULT {
347			port_pos, port_length = GetLptLPEHCISetting(loc_param, txamp)
348		} else if b.variant == LYNX_POINT_MOBILE {
349			port_pos, port_length = GetLptMobileEHCISetting(loc_param, txamp)
350		} else { /* desktop or server */
351			port_pos, port_length = GetLptDesktopEHCISetting(loc_param, txamp)
352		}
353
354		if port_disable == 1 {
355			port_pos = "USB_PORT_SKIP"
356		}
357
358		if port_oc == -1 {
359			fmt.Fprintf(sb, "\t{ 0x%04x, %d, USB_OC_PIN_SKIP, %s },\n",
360				port_length, (port_disable ^ 1), port_pos)
361		} else {
362			fmt.Fprintf(sb, "\t{ 0x%04x, %d, %d, %s },\n",
363				port_length, (port_disable ^ 1), port_oc, port_pos)
364		}
365	}
366
367	sb.WriteString(`};
368
369const struct usb3_port_config mainboard_usb3_ports[MAX_USB3_PORTS] = {
370`)
371
372	xpdo := PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xe8]
373	u3ocm := PCIMap[PCIAddr{Bus: 0, Dev: 0x14, Func: 0}].ConfigDump[0xc8:0xd0]
374
375	if !isULT {
376		nPorts = 6
377	} else {
378		nPorts = 4
379	}
380
381	for port := uint(0); port < nPorts; port++ {
382		var port_oc int = -1
383		port_disable := (xpdo >> port) & 1
384		for oc := 0; oc < 8; oc++ {
385			if (u3ocm[oc] & (1 << port)) != 0 {
386				port_oc = oc
387				break
388			}
389		}
390		if port_oc == -1 {
391			fmt.Fprintf(sb, "\t{ %d, USB_OC_PIN_SKIP },\n",
392				(port_disable ^ 1))
393		} else {
394			fmt.Fprintf(sb, "\t{ %d, %d },\n",
395				(port_disable ^ 1), port_oc)
396		}
397	}
398
399	sb.WriteString(`};
400`)
401
402}
403
404func init() {
405	for _, id := range []uint16{
406		0x8c41, 0x8c49, 0x8c4b, 0x8c4f,
407	} {
408		RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_MOBILE})
409	}
410
411	for _, id := range []uint16{
412		0x8c42, 0x8c44, 0x8c46, 0x8c4a,
413		0x8c4c, 0x8c4e, 0x8c50, 0x8c5c,
414	} {
415		RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_DESKTOP})
416	}
417
418	for _, id := range []uint16{
419		0x8c52, 0x8c54, 0x8c56,
420	} {
421		RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_SERVER})
422	}
423
424	for _, id := range []uint16{
425		0x9c41, 0x9c43, 0x9c45,
426	} {
427		RegisterPCI(0x8086, uint16(id), lynxpoint{variant: LYNX_POINT_ULT})
428	}
429
430	/* PCIe bridge */
431	for _, id := range []uint16{
432		0x8c10, 0x8c12, 0x8c14, 0x8c16, 0x8c18, 0x8c1a, 0x8c1c, 0x8c1e,
433		0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a,
434	} {
435		RegisterPCI(0x8086, id, GenericPCI{})
436	}
437
438	/* SMBus controller  */
439	RegisterPCI(0x8086, 0x8c22, GenericPCI{MissingParent: "smbus"})
440	RegisterPCI(0x8086, 0x9c22, GenericPCI{MissingParent: "smbus"})
441
442	/* SATA */
443	for _, id := range []uint16{
444		0x8c00, 0x8c02, 0x8c04, 0x8c06, 0x8c08, 0x8c0e,
445		0x8c01, 0x8c03, 0x8c05, 0x8c07, 0x8c09, 0x8c0f,
446		0x9c03, 0x9c05, 0x9c07, 0x9c0f,
447	} {
448		RegisterPCI(0x8086, id, GenericPCI{})
449	}
450
451	/* EHCI */
452	for _, id := range []uint16{
453		0x9c26, 0x8c26, 0x8c2d,
454	} {
455		RegisterPCI(0x8086, id, GenericPCI{})
456	}
457
458	/* XHCI */
459	RegisterPCI(0x8086, 0x8c31, GenericPCI{})
460	RegisterPCI(0x8086, 0x9c31, GenericPCI{})
461
462	/* ME and children */
463	for _, id := range []uint16{
464		0x8c3a, 0x8c3b, 0x8c3c, 0x8c3d,
465		0x9c3a, 0x9c3b, 0x9c3c, 0x9c3d,
466	} {
467		RegisterPCI(0x8086, id, GenericPCI{})
468	}
469
470	/* Ethernet */
471	RegisterPCI(0x8086, 0x8c33, GenericPCI{})
472
473	/* Thermal */
474	RegisterPCI(0x8086, 0x8c24, GenericPCI{})
475	RegisterPCI(0x8086, 0x9c24, GenericPCI{})
476
477	/* LAN Controller on LP PCH (if EEPROM has 0x0000/0xffff in DID) */
478	RegisterPCI(0x8086, 0x155a, GenericPCI{})
479
480	/* SDIO */
481	RegisterPCI(0x8086, 0x9c35, GenericPCI{})
482
483	/* Smart Sound Technology Controller */
484	RegisterPCI(0x8086, 0x9c36, GenericPCI{})
485
486	/* Serial I/O */
487	for id := uint16(0x9c60); id <= 0x9c66; id++ {
488		RegisterPCI(0x8086, id, GenericPCI{})
489	}
490}
491