xref: /aosp_15_r20/external/coreboot/util/autoport/main.go (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1/* This is just an experiment. Full automatic porting
2   is probably not possible but a lot can be automated. */
3package main
4
5import (
6	"bytes"
7	"flag"
8	"fmt"
9	"log"
10	"os"
11	"path/filepath"
12	"sort"
13	"strings"
14)
15
16type PCIAddr struct {
17	Bus  int
18	Dev  int
19	Func int
20}
21
22type PCIDevData struct {
23	PCIAddr
24	PCIVenID   uint16
25	PCIDevID   uint16
26	ConfigDump []uint8
27}
28
29type PCIDevice interface {
30	Scan(ctx Context, addr PCIDevData)
31}
32
33type InteltoolData struct {
34	GPIO   map[uint16]uint32
35	RCBA   map[uint16]uint32
36	IOBP   map[uint32]uint32
37	IGD    map[uint32]uint32
38	MCHBAR map[uint16]uint32
39	PMBASE map[uint16]uint32
40}
41
42type DMIData struct {
43	Vendor   string
44	Model    string
45	Version  string
46	IsLaptop bool
47}
48
49type AzaliaCodec struct {
50	Name        string
51	VendorID    uint32
52	SubsystemID uint32
53	CodecNo     int
54	PinConfig   map[int]uint32
55}
56
57type DevReader interface {
58	GetPCIList() []PCIDevData
59	GetDMI() DMIData
60	GetInteltool() InteltoolData
61	GetAzaliaCodecs() []AzaliaCodec
62	GetACPI() map[string][]byte
63	GetCPUModel() []uint32
64	GetEC() []byte
65	GetIOPorts() []IOPorts
66	HasPS2() bool
67}
68
69type IOPorts struct {
70	Start uint16
71	End   uint16
72	Usage string
73}
74
75type SouthBridger interface {
76	GetGPIOHeader() string
77	EncodeGPE(int) int
78	DecodeGPE(int) int
79	EnableGPE(int)
80	NeedRouteGPIOManually()
81}
82
83var SouthBridge SouthBridger
84var BootBlockFiles map[string]string = map[string]string{}
85var ROMStageFiles map[string]string = map[string]string{}
86var RAMStageFiles map[string]string = map[string]string{}
87var SMMFiles map[string]string = map[string]string{}
88var MainboardInit string
89var MainboardEnable string
90var MainboardIncludes []string
91
92type Context struct {
93	MoboID        string
94	KconfigName   string
95	Vendor        string
96	Model         string
97	BaseDirectory string
98	InfoSource    DevReader
99	SaneVendor    string
100}
101
102var KconfigBool map[string]bool = map[string]bool{}
103var KconfigComment map[string]string = map[string]string{}
104var KconfigString map[string]string = map[string]string{}
105var KconfigHex map[string]uint32 = map[string]uint32{}
106var KconfigInt map[string]int = map[string]int{}
107var ROMSizeKB = 0
108var ROMProtocol = ""
109var FlashROMSupport = ""
110
111func GetLE16(inp []byte) uint16 {
112	return uint16(inp[0]) | (uint16(inp[1]) << 8)
113}
114
115func FormatHexLE16(inp []byte) string {
116	return fmt.Sprintf("0x%04x", GetLE16(inp))
117}
118
119func FormatHex32(u uint32) string {
120	return fmt.Sprintf("0x%08x", u)
121}
122
123func FormatHex8(u uint8) string {
124	return fmt.Sprintf("0x%02x", u)
125}
126
127func FormatInt32(u uint32) string {
128	return fmt.Sprintf("%d", u)
129}
130
131func FormatHexLE32(d []uint8) string {
132	u := uint32(d[0]) | (uint32(d[1]) << 8) | (uint32(d[2]) << 16) | (uint32(d[3]) << 24)
133	return FormatHex32(u)
134}
135
136func FormatBool(inp bool) string {
137	if inp {
138		return "1"
139	} else {
140		return "0"
141	}
142}
143
144func sanitize(inp string) string {
145	result := strings.ToLower(inp)
146	result = strings.Replace(result, " ", "_", -1)
147	result = strings.Replace(result, ",", "_", -1)
148	result = strings.Replace(result, "-", "_", -1)
149	for strings.HasSuffix(result, ".") {
150		result = result[0 : len(result)-1]
151	}
152	return result
153}
154
155func AddBootBlockFile(Name string, Condition string) {
156	BootBlockFiles[Name] = Condition
157}
158
159func AddROMStageFile(Name string, Condition string) {
160	ROMStageFiles[Name] = Condition
161}
162
163func AddRAMStageFile(Name string, Condition string) {
164	RAMStageFiles[Name] = Condition
165}
166
167func AddSMMFile(Name string, Condition string) {
168	SMMFiles[Name] = Condition
169}
170
171func IsIOPortUsedBy(ctx Context, port uint16, name string) bool {
172	for _, io := range ctx.InfoSource.GetIOPorts() {
173		if io.Start <= port && port <= io.End && io.Usage == name {
174			return true
175		}
176	}
177	return false
178}
179
180var FlagOutDir = flag.String("coreboot_dir", ".", "Resulting coreboot directory")
181
182func writeMF(mf *os.File, files map[string]string, category string) {
183	keys := []string{}
184	for file, _ := range files {
185		keys = append(keys, file)
186	}
187
188	sort.Strings(keys)
189
190	for _, file := range keys {
191		condition := files[file]
192		if condition == "" {
193			fmt.Fprintf(mf, "%s-y += %s\n", category, file)
194		} else {
195			fmt.Fprintf(mf, "%s-$(%s) += %s\n", category, condition, file)
196		}
197	}
198}
199
200func Create(ctx Context, name string) *os.File {
201	li := strings.LastIndex(name, "/")
202	if li > 0 {
203		os.MkdirAll(ctx.BaseDirectory+"/"+name[0:li], 0700)
204	}
205	mf, err := os.Create(ctx.BaseDirectory + "/" + name)
206	if err != nil {
207		log.Fatal(err)
208	}
209	return mf
210}
211
212func Add_gpl(f *os.File) {
213	fmt.Fprintln(f, "/* SPDX-License-Identifier: GPL-2.0-only */")
214	fmt.Fprintln(f)
215}
216
217func RestorePCI16Simple(f *os.File, pcidev PCIDevData, addr uint16) {
218	fmt.Fprintf(f, "	pci_write_config16(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x);\n",
219		pcidev.Bus, pcidev.Dev, pcidev.Func, addr,
220		pcidev.ConfigDump[addr+1],
221		pcidev.ConfigDump[addr])
222}
223
224func RestorePCI32Simple(f *os.File, pcidev PCIDevData, addr uint16) {
225	fmt.Fprintf(f, "	pci_write_config32(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x%02x%02x);\n",
226		pcidev.Bus, pcidev.Dev, pcidev.Func, addr,
227		pcidev.ConfigDump[addr+3],
228		pcidev.ConfigDump[addr+2],
229		pcidev.ConfigDump[addr+1],
230		pcidev.ConfigDump[addr])
231}
232
233func RestoreRCBA32(f *os.File, inteltool InteltoolData, addr uint16) {
234	fmt.Fprintf(f, "\tRCBA32(0x%04x) = 0x%08x;\n", addr, inteltool.RCBA[addr])
235}
236
237type PCISlot struct {
238	PCIAddr
239	alias             string
240	additionalComment string
241	writeEmpty        bool
242}
243
244type DevTreeNode struct {
245	Bus           int
246	Dev           int
247	Func          int
248	Disabled      bool
249	Registers     map[string]string
250	IOs           map[uint16]uint16
251	Children      []DevTreeNode
252	PCISlots      []PCISlot
253	PCIController bool
254	ChildPCIBus   int
255	MissingParent string
256	SubVendor     uint16
257	SubSystem     uint16
258	Chip          string
259	Ops           string
260	Comment       string
261}
262
263var DevTree DevTreeNode
264var MissingChildren map[string][]DevTreeNode = map[string][]DevTreeNode{}
265var unmatchedPCIChips map[PCIAddr]DevTreeNode = map[PCIAddr]DevTreeNode{}
266var unmatchedPCIDevices map[PCIAddr]DevTreeNode = map[PCIAddr]DevTreeNode{}
267
268func Offset(dt *os.File, offset int) {
269	for i := 0; i < offset; i++ {
270		fmt.Fprintf(dt, "\t")
271	}
272}
273
274func MatchDev(dev *DevTreeNode) {
275	for idx := range dev.Children {
276		MatchDev(&dev.Children[idx])
277	}
278
279	for _, slot := range dev.PCISlots {
280		slotChip, ok := unmatchedPCIChips[slot.PCIAddr]
281
282		if !ok {
283			continue
284		}
285
286		if slot.additionalComment != "" && slotChip.Comment != "" {
287			slotChip.Comment = slot.additionalComment + " " + slotChip.Comment
288		} else {
289			slotChip.Comment = slot.additionalComment + slotChip.Comment
290		}
291
292		delete(unmatchedPCIChips, slot.PCIAddr)
293		MatchDev(&slotChip)
294		dev.Children = append(dev.Children, slotChip)
295	}
296
297	if dev.PCIController {
298		for slot, slotDev := range unmatchedPCIChips {
299			if slot.Bus == dev.ChildPCIBus {
300				delete(unmatchedPCIChips, slot)
301				MatchDev(&slotDev)
302				dev.Children = append(dev.Children, slotDev)
303			}
304		}
305	}
306
307	for _, slot := range dev.PCISlots {
308		slotDev, ok := unmatchedPCIDevices[slot.PCIAddr]
309		if !ok {
310			if slot.writeEmpty {
311				dev.Children = append(dev.Children,
312					DevTreeNode{
313						Registers: map[string]string{},
314						Chip:      "pci",
315						Bus:       slot.Bus,
316						Dev:       slot.Dev,
317						Func:      slot.Func,
318						Comment:   slot.additionalComment,
319						Disabled:  true,
320					},
321				)
322			}
323			continue
324		}
325
326		if slot.additionalComment != "" && slotDev.Comment != "" {
327			slotDev.Comment = slot.additionalComment + " " + slotDev.Comment
328		} else {
329			slotDev.Comment = slot.additionalComment + slotDev.Comment
330		}
331
332		MatchDev(&slotDev)
333		dev.Children = append(dev.Children, slotDev)
334		delete(unmatchedPCIDevices, slot.PCIAddr)
335	}
336
337	if dev.MissingParent != "" {
338		for _, child := range MissingChildren[dev.MissingParent] {
339			MatchDev(&child)
340			dev.Children = append(dev.Children, child)
341		}
342		delete(MissingChildren, dev.MissingParent)
343	}
344
345	if dev.PCIController {
346		for slot, slotDev := range unmatchedPCIDevices {
347			if slot.Bus == dev.ChildPCIBus {
348				MatchDev(&slotDev)
349				dev.Children = append(dev.Children, slotDev)
350				delete(unmatchedPCIDevices, slot)
351			}
352		}
353	}
354}
355
356func writeOn(dt *os.File, dev DevTreeNode) {
357	if dev.Disabled {
358		fmt.Fprintf(dt, "off")
359	} else {
360		fmt.Fprintf(dt, "on")
361	}
362}
363
364func WriteDev(dt *os.File, offset int, alias string, dev DevTreeNode) {
365	Offset(dt, offset)
366	switch dev.Chip {
367	case "cpu_cluster", "domain":
368		fmt.Fprintf(dt, "device %s 0x%x ", dev.Chip, dev.Dev)
369		writeOn(dt, dev)
370	case "pci", "pnp":
371		if alias != "" {
372			fmt.Fprintf(dt, "device ref %s ", alias)
373		} else {
374			fmt.Fprintf(dt, "device %s %02x.%x ", dev.Chip, dev.Dev, dev.Func)
375		}
376		writeOn(dt, dev)
377	case "i2c":
378		fmt.Fprintf(dt, "device %s %02x ", dev.Chip, dev.Dev)
379		writeOn(dt, dev)
380	default:
381		fmt.Fprintf(dt, "chip %s", dev.Chip)
382	}
383	if dev.Comment != "" {
384		fmt.Fprintf(dt, " # %s", dev.Comment)
385	}
386	fmt.Fprintf(dt, "\n")
387	if dev.Ops != "" {
388		Offset(dt, offset+1)
389		fmt.Fprintf(dt, "ops %s\n", dev.Ops)
390	}
391	if dev.Chip == "pci" && dev.SubSystem != 0 && dev.SubVendor != 0 {
392		Offset(dt, offset+1)
393		fmt.Fprintf(dt, "subsystemid 0x%04x 0x%04x\n", dev.SubVendor, dev.SubSystem)
394	}
395
396	keys := []string{}
397	for reg, _ := range dev.Registers {
398		keys = append(keys, reg)
399	}
400
401	sort.Strings(keys)
402
403	for _, reg := range keys {
404		val := dev.Registers[reg]
405		Offset(dt, offset+1)
406		fmt.Fprintf(dt, "register \"%s\" = \"%s\"\n", reg, val)
407	}
408
409	ios := []int{}
410	for reg, _ := range dev.IOs {
411		ios = append(ios, int(reg))
412	}
413
414	sort.Ints(ios)
415
416	for _, reg := range ios {
417		val := dev.IOs[uint16(reg)]
418		Offset(dt, offset+1)
419		fmt.Fprintf(dt, "io 0x%x = 0x%x\n", reg, val)
420	}
421
422	for _, child := range dev.Children {
423		alias = ""
424		for _, slot := range dev.PCISlots {
425			if slot.PCIAddr.Bus == child.Bus &&
426				slot.PCIAddr.Dev == child.Dev && slot.PCIAddr.Func == child.Func {
427				alias = slot.alias
428			}
429		}
430		WriteDev(dt, offset+1, alias, child)
431	}
432
433	Offset(dt, offset)
434	fmt.Fprintf(dt, "end\n")
435}
436
437func PutChip(domain string, cur DevTreeNode) {
438	MissingChildren[domain] = append(MissingChildren[domain], cur)
439}
440
441func PutPCIChip(addr PCIDevData, cur DevTreeNode) {
442	unmatchedPCIChips[addr.PCIAddr] = cur
443}
444
445func PutPCIDevParent(addr PCIDevData, comment string, parent string) {
446	cur := DevTreeNode{
447		Registers:     map[string]string{},
448		Chip:          "pci",
449		Bus:           addr.Bus,
450		Dev:           addr.Dev,
451		Func:          addr.Func,
452		MissingParent: parent,
453		Comment:       comment,
454	}
455	if addr.ConfigDump[0xa] == 0x04 && addr.ConfigDump[0xb] == 0x06 {
456		cur.PCIController = true
457		cur.ChildPCIBus = int(addr.ConfigDump[0x19])
458
459		loopCtr := 0
460		for capPtr := addr.ConfigDump[0x34]; capPtr != 0; capPtr = addr.ConfigDump[capPtr+1] {
461			/* Avoid hangs. There are only 0x100 different possible values for capPtr.
462			   If we iterate longer than that, we're in endless loop. */
463			loopCtr++
464			if loopCtr > 0x100 {
465				break
466			}
467			if addr.ConfigDump[capPtr] == 0x0d {
468				cur.SubVendor = GetLE16(addr.ConfigDump[capPtr+4 : capPtr+6])
469				cur.SubSystem = GetLE16(addr.ConfigDump[capPtr+6 : capPtr+8])
470			}
471		}
472	} else {
473		cur.SubVendor = GetLE16(addr.ConfigDump[0x2c:0x2e])
474		cur.SubSystem = GetLE16(addr.ConfigDump[0x2e:0x30])
475	}
476	unmatchedPCIDevices[addr.PCIAddr] = cur
477}
478
479func PutPCIDev(addr PCIDevData, comment string) {
480	PutPCIDevParent(addr, comment, "")
481}
482
483type GenericPCI struct {
484	Comment       string
485	Bus0Subdiv    string
486	MissingParent string
487}
488
489type GenericVGA struct {
490	GenericPCI
491}
492
493type DSDTInclude struct {
494	Comment string
495	File    string
496}
497
498type DSDTDefine struct {
499	Key     string
500	Comment string
501	Value   string
502}
503
504var DSDTIncludes []DSDTInclude
505var DSDTPCI0Includes []DSDTInclude
506var DSDTDefines []DSDTDefine
507
508func (g GenericPCI) Scan(ctx Context, addr PCIDevData) {
509	PutPCIDevParent(addr, g.Comment, g.MissingParent)
510}
511
512var IGDEnabled bool = false
513
514func (g GenericVGA) Scan(ctx Context, addr PCIDevData) {
515	KconfigString["VGA_BIOS_ID"] = fmt.Sprintf("%04x,%04x",
516		addr.PCIVenID,
517		addr.PCIDevID)
518	PutPCIDevParent(addr, g.Comment, g.MissingParent)
519	IGDEnabled = true
520}
521
522func makeKconfigName(ctx Context) {
523	kn := Create(ctx, "Kconfig.name")
524	defer kn.Close()
525
526	fmt.Fprintf(kn, "config %s\n\tbool \"%s\"\n", ctx.KconfigName, ctx.Model)
527}
528
529func makeComment(name string) string {
530	cmt, ok := KconfigComment[name]
531	if !ok {
532		return ""
533	}
534	return " # " + cmt
535}
536
537func makeKconfig(ctx Context) {
538	kc := Create(ctx, "Kconfig")
539	defer kc.Close()
540
541	fmt.Fprintf(kc, "if %s\n\n", ctx.KconfigName)
542
543	fmt.Fprintf(kc, "config BOARD_SPECIFIC_OPTIONS\n\tdef_bool y\n")
544	keys := []string{}
545	for name, val := range KconfigBool {
546		if val {
547			keys = append(keys, name)
548		}
549	}
550
551	sort.Strings(keys)
552
553	for _, name := range keys {
554		fmt.Fprintf(kc, "\tselect %s%s\n", name, makeComment(name))
555	}
556
557	keys = nil
558	for name, val := range KconfigBool {
559		if !val {
560			keys = append(keys, name)
561		}
562	}
563
564	sort.Strings(keys)
565
566	for _, name := range keys {
567		fmt.Fprintf(kc, `
568config %s%s
569	bool
570	default n
571`, name, makeComment(name))
572	}
573
574	keys = nil
575	for name, _ := range KconfigString {
576		keys = append(keys, name)
577	}
578
579	sort.Strings(keys)
580
581	for _, name := range keys {
582		fmt.Fprintf(kc, `
583config %s%s
584	string
585	default "%s"
586`, name, makeComment(name), KconfigString[name])
587	}
588
589	keys = nil
590	for name, _ := range KconfigHex {
591		keys = append(keys, name)
592	}
593
594	sort.Strings(keys)
595
596	for _, name := range keys {
597		fmt.Fprintf(kc, `
598config %s%s
599	hex
600	default 0x%x
601`, name, makeComment(name), KconfigHex[name])
602	}
603
604	keys = nil
605	for name, _ := range KconfigInt {
606		keys = append(keys, name)
607	}
608
609	sort.Strings(keys)
610
611	for _, name := range keys {
612		fmt.Fprintf(kc, `
613config %s%s
614	int
615	default %d
616`, name, makeComment(name), KconfigInt[name])
617	}
618
619	fmt.Fprintf(kc, "endif\n")
620}
621
622const MoboDir = "/src/mainboard/"
623
624func makeVendor(ctx Context) {
625	vendor := ctx.Vendor
626	vendorSane := ctx.SaneVendor
627	vendorDir := *FlagOutDir + MoboDir + vendorSane
628	vendorUpper := strings.ToUpper(vendorSane)
629	kconfig := vendorDir + "/Kconfig"
630	if _, err := os.Stat(kconfig); os.IsNotExist(err) {
631		f, err := os.Create(kconfig)
632		if err != nil {
633			log.Fatal(err)
634		}
635		defer f.Close()
636		f.WriteString(`if VENDOR_` + vendorUpper + `
637
638choice
639	prompt "Mainboard model"
640
641source "src/mainboard/` + vendorSane + `/*/Kconfig.name"
642
643endchoice
644
645source "src/mainboard/` + vendorSane + `/*/Kconfig"
646
647config MAINBOARD_VENDOR
648	string
649	default "` + vendor + `"
650
651endif # VENDOR_` + vendorUpper + "\n")
652	}
653	kconfigName := vendorDir + "/Kconfig.name"
654	if _, err := os.Stat(kconfigName); os.IsNotExist(err) {
655		f, err := os.Create(kconfigName)
656		if err != nil {
657			log.Fatal(err)
658		}
659		defer f.Close()
660		f.WriteString(`config VENDOR_` + vendorUpper + `
661	bool "` + vendor + `"
662`)
663	}
664
665}
666
667func GuessECGPE(ctx Context) int {
668	/* FIXME:XX Use iasl -d and/or better parsing  */
669	dsdt := ctx.InfoSource.GetACPI()["DSDT"]
670	idx := bytes.Index(dsdt, []byte{0x08, '_', 'G', 'P', 'E', 0x0a}) /* Name (_GPE, byte).  */
671	if idx > 0 {
672		return int(dsdt[idx+6])
673	}
674	return -1
675}
676
677func GuessSPDMap(ctx Context) []uint8 {
678	dmi := ctx.InfoSource.GetDMI()
679
680	if dmi.Vendor == "LENOVO" {
681		return []uint8{0x50, 0x52, 0x51, 0x53}
682	}
683	return []uint8{0x50, 0x51, 0x52, 0x53}
684}
685
686func main() {
687	flag.Parse()
688
689	ctx := Context{}
690
691	ctx.InfoSource = MakeLogReader()
692
693	dmi := ctx.InfoSource.GetDMI()
694
695	ctx.Vendor = dmi.Vendor
696
697	if dmi.Vendor == "LENOVO" {
698		ctx.Model = dmi.Version
699	} else {
700		ctx.Model = dmi.Model
701	}
702
703	if dmi.IsLaptop {
704		KconfigBool["SYSTEM_TYPE_LAPTOP"] = true
705	}
706	ctx.SaneVendor = sanitize(ctx.Vendor)
707	for {
708		last := ctx.SaneVendor
709		for _, suf := range []string{"_inc", "_co", "_corp"} {
710			ctx.SaneVendor = strings.TrimSuffix(ctx.SaneVendor, suf)
711		}
712		if last == ctx.SaneVendor {
713			break
714		}
715	}
716	ctx.MoboID = ctx.SaneVendor + "/" + sanitize(ctx.Model)
717	ctx.KconfigName = "BOARD_" + strings.ToUpper(ctx.SaneVendor+"_"+sanitize(ctx.Model))
718	ctx.BaseDirectory = *FlagOutDir + MoboDir + ctx.MoboID
719	KconfigString["MAINBOARD_DIR"] = ctx.MoboID
720	KconfigString["MAINBOARD_PART_NUMBER"] = ctx.Model
721
722	os.MkdirAll(ctx.BaseDirectory, 0700)
723
724	makeVendor(ctx)
725
726	ScanRoot(ctx)
727
728	if IGDEnabled {
729		KconfigBool["MAINBOARD_HAS_LIBGFXINIT"] = true
730		KconfigComment["MAINBOARD_HAS_LIBGFXINIT"] = "FIXME: check this"
731		AddRAMStageFile("gma-mainboard.ads", "CONFIG_MAINBOARD_USE_LIBGFXINIT")
732	}
733
734	if len(BootBlockFiles) > 0 || len(ROMStageFiles) > 0 || len(RAMStageFiles) > 0 || len(SMMFiles) > 0 {
735		mf := Create(ctx, "Makefile.mk")
736		defer mf.Close()
737		writeMF(mf, BootBlockFiles, "bootblock")
738		writeMF(mf, ROMStageFiles, "romstage")
739		writeMF(mf, RAMStageFiles, "ramstage")
740		writeMF(mf, SMMFiles, "smm")
741	}
742
743	devtree := Create(ctx, "devicetree.cb")
744	defer devtree.Close()
745
746	MatchDev(&DevTree)
747	WriteDev(devtree, 0, "", DevTree)
748
749	if MainboardInit != "" || MainboardEnable != "" || MainboardIncludes != nil {
750		mainboard := Create(ctx, "mainboard.c")
751		defer mainboard.Close()
752		Add_gpl(mainboard)
753		mainboard.WriteString("#include <device/device.h>\n")
754		for _, include := range MainboardIncludes {
755			mainboard.WriteString("#include <" + include + ">\n")
756		}
757		mainboard.WriteString("\n")
758		if MainboardInit != "" {
759			mainboard.WriteString(`static void mainboard_init(struct device *dev)
760{
761` + MainboardInit + "}\n\n")
762		}
763		if MainboardInit != "" || MainboardEnable != "" {
764			mainboard.WriteString("static void mainboard_enable(struct device *dev)\n{\n")
765			if MainboardInit != "" {
766				mainboard.WriteString("\tdev->ops->init = mainboard_init;\n\n")
767			}
768			mainboard.WriteString(MainboardEnable)
769			mainboard.WriteString("}\n\n")
770			mainboard.WriteString(`struct chip_operations mainboard_ops = {
771	.enable_dev = mainboard_enable,
772};
773`)
774		}
775	}
776
777	bi := Create(ctx, "board_info.txt")
778	defer bi.Close()
779
780	fixme := ""
781
782	if dmi.IsLaptop {
783		bi.WriteString("Category: laptop\n")
784	} else {
785		bi.WriteString("Category: desktop\n")
786		fixme += "check category, "
787	}
788
789	missing := "ROM package, ROM socketed"
790
791	if ROMProtocol != "" {
792		fmt.Fprintf(bi, "ROM protocol: %s\n", ROMProtocol)
793	} else {
794		missing += ", ROM protocol"
795	}
796
797	if FlashROMSupport != "" {
798		fmt.Fprintf(bi, "Flashrom support: %s\n", FlashROMSupport)
799	} else {
800		missing += ", Flashrom support"
801	}
802
803	missing += ", Release year"
804
805	if fixme != "" {
806		fmt.Fprintf(bi, "FIXME: %s, put %s\n", fixme, missing)
807	} else {
808		fmt.Fprintf(bi, "FIXME: put %s\n", missing)
809	}
810
811	if ROMSizeKB == 0 {
812		KconfigBool["BOARD_ROMSIZE_KB_2048"] = true
813		KconfigComment["BOARD_ROMSIZE_KB_2048"] = "FIXME: correct this"
814	} else {
815		KconfigBool[fmt.Sprintf("BOARD_ROMSIZE_KB_%d", ROMSizeKB)] = true
816	}
817
818	makeKconfig(ctx)
819	makeKconfigName(ctx)
820
821	dsdt := Create(ctx, "dsdt.asl")
822	defer dsdt.Close()
823	Add_gpl(dsdt)
824
825	for _, define := range DSDTDefines {
826		if define.Comment != "" {
827			fmt.Fprintf(dsdt, "\t/* %s. */\n", define.Comment)
828		}
829		dsdt.WriteString("#define " + define.Key + " " + define.Value + "\n")
830	}
831
832	dsdt.WriteString(
833`#include <acpi/acpi.h>
834
835DefinitionBlock(
836	"dsdt.aml",
837	"DSDT",
838	ACPI_DSDT_REV_2,
839	OEM_ID,
840	ACPI_TABLE_CREATOR,
841	0x20141018
842)
843{
844	#include <acpi/dsdt_top.asl>
845	#include "acpi/platform.asl"
846`)
847
848	for _, x := range DSDTIncludes {
849		if x.Comment != "" {
850			fmt.Fprintf(dsdt, "\t/* %s. */\n", x.Comment)
851		}
852		fmt.Fprintf(dsdt, "\t#include <%s>\n", x.File)
853	}
854
855	dsdt.WriteString(`
856	Device (\_SB.PCI0)
857	{
858`)
859	for _, x := range DSDTPCI0Includes {
860		if x.Comment != "" {
861			fmt.Fprintf(dsdt, "\t/* %s. */\n", x.Comment)
862		}
863		fmt.Fprintf(dsdt, "\t\t#include <%s>\n", x.File)
864	}
865	dsdt.WriteString(
866		`	}
867}
868`)
869
870	if IGDEnabled {
871		gma := Create(ctx, "gma-mainboard.ads")
872		defer gma.Close()
873
874		gma.WriteString(`-- SPDX-License-Identifier: GPL-2.0-or-later
875
876with HW.GFX.GMA;
877with HW.GFX.GMA.Display_Probing;
878
879use HW.GFX.GMA;
880use HW.GFX.GMA.Display_Probing;
881
882private package GMA.Mainboard is
883
884   -- FIXME: check this
885   ports : constant Port_List :=
886     (DP1,
887      DP2,
888      DP3,
889      HDMI1,
890      HDMI2,
891      HDMI3,
892      Analog,
893      LVDS,
894      eDP);
895
896end GMA.Mainboard;
897`)
898	}
899	outputPath, _ := filepath.Abs(ctx.BaseDirectory)
900	fmt.Printf("Done! Generated sources are in %s\n", outputPath)
901}
902