1 /* This is just an experiment. Full automatic porting
2 is probably not possible but a lot can be automated. */
22 type PCIDevData
struct {
29 type PCIDevice
interface {
30 Scan(ctx Context
, addr PCIDevData
)
33 type InteltoolData
struct {
34 GPIO
map[uint16]uint32
35 RCBA
map[uint16]uint32
36 IOBP
map[uint32]uint32
38 MCHBAR
map[uint16]uint32
39 PMBASE
map[uint16]uint32
49 type AzaliaCodec
struct {
54 PinConfig
map[int]uint32
57 type DevReader
interface {
58 GetPCIList() []PCIDevData
60 GetInteltool() InteltoolData
61 GetAzaliaCodecs() []AzaliaCodec
62 GetACPI() map[string][]byte
63 GetCPUModel() []uint32
65 GetIOPorts() []IOPorts
75 type SouthBridger
interface {
76 GetGPIOHeader() string
80 NeedRouteGPIOManually()
83 var SouthBridge SouthBridger
84 var BootBlockFiles
map[string]string = map[string]string{}
85 var ROMStageFiles
map[string]string = map[string]string{}
86 var RAMStageFiles
map[string]string = map[string]string{}
87 var SMMFiles
map[string]string = map[string]string{}
88 var MainboardInit
string
89 var MainboardEnable
string
90 var MainboardIncludes
[]string
112 var CommentFormatStrings
map[Filetype
]string = map[Filetype
]string {
123 GPL2_only License
= "GPL-2.0-only"
124 GPL2_or_later
= "GPL-2.0-or-later"
127 var KconfigBool
map[string]bool = map[string]bool{}
128 var KconfigComment
map[string]string = map[string]string{}
129 var KconfigString
map[string]string = map[string]string{}
130 var KconfigHex
map[string]uint32 = map[string]uint32{}
131 var KconfigInt
map[string]int = map[string]int{}
134 var FlashROMSupport
= ""
136 func GetLE16(inp
[]byte) uint16 {
137 return uint16(inp
[0]) |
(uint16(inp
[1]) << 8)
140 func FormatHexLE16(inp
[]byte) string {
141 return fmt
.Sprintf("0x%04x", GetLE16(inp
))
144 func FormatHex32(u
uint32) string {
145 return fmt
.Sprintf("0x%08x", u
)
148 func FormatHex8(u
uint8) string {
149 return fmt
.Sprintf("0x%02x", u
)
152 func FormatInt32(u
uint32) string {
153 return fmt
.Sprintf("%d", u
)
156 func FormatHexLE32(d
[]uint8) string {
157 u
:= uint32(d
[0]) |
(uint32(d
[1]) << 8) |
(uint32(d
[2]) << 16) |
(uint32(d
[3]) << 24)
158 return FormatHex32(u
)
161 func FormatBool(inp
bool) string {
169 func sanitize(inp
string) string {
170 result
:= strings
.ToLower(inp
)
171 result
= strings
.Replace(result
, " ", "_", -1)
172 result
= strings
.Replace(result
, ",", "_", -1)
173 result
= strings
.Replace(result
, "-", "_", -1)
174 for strings
.HasSuffix(result
, ".") {
175 result
= result
[0 : len(result
)-1]
180 func AddBootBlockFile(Name
string, Condition
string) {
181 BootBlockFiles
[Name
] = Condition
184 func AddROMStageFile(Name
string, Condition
string) {
185 ROMStageFiles
[Name
] = Condition
188 func AddRAMStageFile(Name
string, Condition
string) {
189 RAMStageFiles
[Name
] = Condition
192 func AddSMMFile(Name
string, Condition
string) {
193 SMMFiles
[Name
] = Condition
196 func IsIOPortUsedBy(ctx Context
, port
uint16, name
string) bool {
197 for _
, io
:= range ctx
.InfoSource
.GetIOPorts() {
198 if io
.Start
<= port
&& port
<= io
.End
&& io
.Usage
== name
{
205 var FlagOutDir
= flag
.String("coreboot_dir", ".", "Resulting coreboot directory")
207 func writeMF(mf
*os
.File
, files
map[string]string, category
string) {
209 for file
, _
:= range files
{
210 keys
= append(keys
, file
)
215 for _
, file
:= range keys
{
216 condition
:= files
[file
]
218 fmt
.Fprintf(mf
, "%s-y += %s\n", category
, file
)
220 fmt
.Fprintf(mf
, "%s-$(%s) += %s\n", category
, condition
, file
)
225 func Create(ctx Context
, name
string) *os
.File
{
226 li
:= strings
.LastIndex(name
, "/")
228 os
.MkdirAll(ctx
.BaseDirectory
+"/"+name
[0:li
], 0700)
230 mf
, err
:= os
.Create(ctx
.BaseDirectory
+ "/" + name
)
237 func Add_SPDX(f
*os
.File
, filetype Filetype
, license License
) {
238 Add_Comment(f
, filetype
, "SPDX-License-Identifier: " + string(license
))
242 func Add_Comment(f
*os
.File
, filetype Filetype
, comment
string) {
243 fmt
.Fprintf(f
, CommentFormatStrings
[filetype
], comment
)
246 func RestorePCI16Simple(f
*os
.File
, pcidev PCIDevData
, addr
uint16) {
247 fmt
.Fprintf(f
, " pci_write_config16(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x);\n",
248 pcidev
.Bus
, pcidev
.Dev
, pcidev
.Func
, addr
,
249 pcidev
.ConfigDump
[addr
+1],
250 pcidev
.ConfigDump
[addr
])
253 func RestorePCI32Simple(f
*os
.File
, pcidev PCIDevData
, addr
uint16) {
254 fmt
.Fprintf(f
, " pci_write_config32(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x%02x%02x);\n",
255 pcidev
.Bus
, pcidev
.Dev
, pcidev
.Func
, addr
,
256 pcidev
.ConfigDump
[addr
+3],
257 pcidev
.ConfigDump
[addr
+2],
258 pcidev
.ConfigDump
[addr
+1],
259 pcidev
.ConfigDump
[addr
])
262 func RestoreRCBA32(f
*os
.File
, inteltool InteltoolData
, addr
uint16) {
263 fmt
.Fprintf(f
, "\tRCBA32(0x%04x) = 0x%08x;\n", addr
, inteltool
.RCBA
[addr
])
266 type PCISlot
struct {
269 additionalComment
string
273 type DevTreeNode
struct {
278 Registers
map[string]string
279 IOs
map[uint16]uint16
280 Children
[]DevTreeNode
292 var DevTree DevTreeNode
293 var MissingChildren
map[string][]DevTreeNode
= map[string][]DevTreeNode
{}
294 var unmatchedPCIChips
map[PCIAddr
]DevTreeNode
= map[PCIAddr
]DevTreeNode
{}
295 var unmatchedPCIDevices
map[PCIAddr
]DevTreeNode
= map[PCIAddr
]DevTreeNode
{}
297 func Offset(dt
*os
.File
, offset
int) {
298 for i
:= 0; i
< offset
; i
++ {
299 fmt
.Fprintf(dt
, "\t")
303 func MatchDev(dev
*DevTreeNode
) {
304 for idx
:= range dev
.Children
{
305 MatchDev(&dev
.Children
[idx
])
308 for _
, slot
:= range dev
.PCISlots
{
309 slotDev
, ok
:= unmatchedPCIDevices
[slot
.PCIAddr
]
312 dev
.Children
= append(dev
.Children
,
314 Registers
: map[string]string{},
319 Comment
: slot
.additionalComment
,
327 if slot
.additionalComment
!= "" && slotDev
.Comment
!= "" {
328 slotDev
.Comment
= slot
.additionalComment
+ " " + slotDev
.Comment
330 slotDev
.Comment
= slot
.additionalComment
+ slotDev
.Comment
334 dev
.Children
= append(dev
.Children
, slotDev
)
335 delete(unmatchedPCIDevices
, slot
.PCIAddr
)
338 for _
, slot
:= range dev
.PCISlots
{
339 slotChip
, ok
:= unmatchedPCIChips
[slot
.PCIAddr
]
345 if slot
.additionalComment
!= "" && slotChip
.Comment
!= "" {
346 slotChip
.Comment
= slot
.additionalComment
+ " " + slotChip
.Comment
348 slotChip
.Comment
= slot
.additionalComment
+ slotChip
.Comment
351 delete(unmatchedPCIChips
, slot
.PCIAddr
)
353 dev
.Children
= append(dev
.Children
, slotChip
)
356 if dev
.PCIController
{
357 for slot
, slotDev
:= range unmatchedPCIChips
{
358 if slot
.Bus
== dev
.ChildPCIBus
{
359 delete(unmatchedPCIChips
, slot
)
361 dev
.Children
= append(dev
.Children
, slotDev
)
366 if dev
.MissingParent
!= "" {
367 for _
, child
:= range MissingChildren
[dev
.MissingParent
] {
369 dev
.Children
= append(dev
.Children
, child
)
371 delete(MissingChildren
, dev
.MissingParent
)
374 if dev
.PCIController
{
375 for slot
, slotDev
:= range unmatchedPCIDevices
{
376 if slot
.Bus
== dev
.ChildPCIBus
{
378 dev
.Children
= append(dev
.Children
, slotDev
)
379 delete(unmatchedPCIDevices
, slot
)
385 func writeOn(dt
*os
.File
, dev DevTreeNode
) {
387 fmt
.Fprintf(dt
, "off")
389 fmt
.Fprintf(dt
, "on")
393 func WriteDev(dt
*os
.File
, offset
int, alias
string, dev DevTreeNode
) {
396 case "cpu_cluster", "domain":
397 fmt
.Fprintf(dt
, "device %s 0x%x ", dev
.Chip
, dev
.Dev
)
401 fmt
.Fprintf(dt
, "device ref %s ", alias
)
403 fmt
.Fprintf(dt
, "device %s %02x.%x ", dev
.Chip
, dev
.Dev
, dev
.Func
)
407 fmt
.Fprintf(dt
, "device %s %02x ", dev
.Chip
, dev
.Dev
)
410 fmt
.Fprintf(dt
, "chip %s", dev
.Chip
)
412 if dev
.Comment
!= "" {
413 fmt
.Fprintf(dt
, " # %s", dev
.Comment
)
415 fmt
.Fprintf(dt
, "\n")
418 fmt
.Fprintf(dt
, "ops %s\n", dev
.Ops
)
420 if dev
.Chip
== "pci" && dev
.SubSystem
!= 0 && dev
.SubVendor
!= 0 {
422 fmt
.Fprintf(dt
, "subsystemid 0x%04x 0x%04x\n", dev
.SubVendor
, dev
.SubSystem
)
426 for reg
, _
:= range dev
.Registers
{
427 keys
= append(keys
, reg
)
432 for _
, reg
:= range keys
{
433 val
:= dev
.Registers
[reg
]
435 fmt
.Fprintf(dt
, "register \"%s\" = \"%s\"\n", reg
, val
)
439 for reg
, _
:= range dev
.IOs
{
440 ios
= append(ios
, int(reg
))
445 for _
, reg
:= range ios
{
446 val
:= dev
.IOs
[uint16(reg
)]
448 fmt
.Fprintf(dt
, "io 0x%x = 0x%x\n", reg
, val
)
451 for _
, child
:= range dev
.Children
{
453 for _
, slot
:= range dev
.PCISlots
{
454 if slot
.PCIAddr
.Bus
== child
.Bus
&&
455 slot
.PCIAddr
.Dev
== child
.Dev
&& slot
.PCIAddr
.Func
== child
.Func
{
459 WriteDev(dt
, offset
+1, alias
, child
)
463 fmt
.Fprintf(dt
, "end\n")
466 func PutChip(domain
string, cur DevTreeNode
) {
467 MissingChildren
[domain
] = append(MissingChildren
[domain
], cur
)
470 func PutPCIChip(addr PCIDevData
, cur DevTreeNode
) {
471 unmatchedPCIChips
[addr
.PCIAddr
] = cur
474 func PutPCIDevParent(addr PCIDevData
, comment
string, parent
string) {
476 Registers
: map[string]string{},
481 MissingParent
: parent
,
484 if addr
.ConfigDump
[0xa] == 0x04 && addr
.ConfigDump
[0xb] == 0x06 {
485 cur
.PCIController
= true
486 cur
.ChildPCIBus
= int(addr
.ConfigDump
[0x19])
489 for capPtr
:= addr
.ConfigDump
[0x34]; capPtr
!= 0; capPtr
= addr
.ConfigDump
[capPtr
+1] {
490 /* Avoid hangs. There are only 0x100 different possible values for capPtr.
491 If we iterate longer than that, we're in endless loop. */
496 if addr
.ConfigDump
[capPtr
] == 0x0d {
497 cur
.SubVendor
= GetLE16(addr
.ConfigDump
[capPtr
+4 : capPtr
+6])
498 cur
.SubSystem
= GetLE16(addr
.ConfigDump
[capPtr
+6 : capPtr
+8])
502 cur
.SubVendor
= GetLE16(addr
.ConfigDump
[0x2c:0x2e])
503 cur
.SubSystem
= GetLE16(addr
.ConfigDump
[0x2e:0x30])
505 unmatchedPCIDevices
[addr
.PCIAddr
] = cur
508 func PutPCIDev(addr PCIDevData
, comment
string) {
509 PutPCIDevParent(addr
, comment
, "")
512 type GenericPCI
struct {
518 type GenericVGA
struct {
522 type DSDTInclude
struct {
527 type DSDTDefine
struct {
533 var DSDTIncludes
[]DSDTInclude
534 var DSDTPCI0Includes
[]DSDTInclude
535 var DSDTDefines
[]DSDTDefine
537 func (g GenericPCI
) Scan(ctx Context
, addr PCIDevData
) {
538 PutPCIDevParent(addr
, g
.Comment
, g
.MissingParent
)
541 var IGDEnabled
bool = false
543 func (g GenericVGA
) Scan(ctx Context
, addr PCIDevData
) {
544 KconfigString
["VGA_BIOS_ID"] = fmt
.Sprintf("%04x,%04x",
547 PutPCIDevParent(addr
, g
.Comment
, g
.MissingParent
)
551 func makeKconfigName(ctx Context
) {
552 kn
:= Create(ctx
, "Kconfig.name")
554 Add_SPDX(kn
, Kconfig
, GPL2_only
)
556 fmt
.Fprintf(kn
, "config %s\n\tbool \"%s\"\n", ctx
.KconfigName
, ctx
.Model
)
559 func makeComment(name
string) string {
560 cmt
, ok
:= KconfigComment
[name
]
567 func makeKconfig(ctx Context
) {
568 kc
:= Create(ctx
, "Kconfig")
570 Add_SPDX(kc
, Kconfig
, GPL2_only
)
572 fmt
.Fprintf(kc
, "if %s\n\n", ctx
.KconfigName
)
574 fmt
.Fprintf(kc
, "config BOARD_SPECIFIC_OPTIONS\n\tdef_bool y\n")
576 for name
, val
:= range KconfigBool
{
578 keys
= append(keys
, name
)
584 for _
, name
:= range keys
{
585 fmt
.Fprintf(kc
, "\tselect %s%s\n", name
, makeComment(name
))
589 for name
, val
:= range KconfigBool
{
591 keys
= append(keys
, name
)
597 for _
, name
:= range keys
{
602 `, name
, makeComment(name
))
606 for name
, _
:= range KconfigString
{
607 keys
= append(keys
, name
)
612 for _
, name
:= range keys
{
617 `, name
, makeComment(name
), KconfigString
[name
])
621 for name
, _
:= range KconfigHex
{
622 keys
= append(keys
, name
)
627 for _
, name
:= range keys
{
632 `, name
, makeComment(name
), KconfigHex
[name
])
636 for name
, _
:= range KconfigInt
{
637 keys
= append(keys
, name
)
642 for _
, name
:= range keys
{
647 `, name
, makeComment(name
), KconfigInt
[name
])
650 fmt
.Fprintf(kc
, "endif\n")
653 const MoboDir
= "/src/mainboard/"
655 func makeVendor(ctx Context
) {
657 vendorSane
:= ctx
.SaneVendor
658 vendorDir
:= *FlagOutDir
+ MoboDir
+ vendorSane
659 vendorUpper
:= strings
.ToUpper(vendorSane
)
660 kconfig
:= vendorDir
+ "/Kconfig"
661 if _
, err
:= os
.Stat(kconfig
); os
.IsNotExist(err
) {
662 f
, err
:= os
.Create(kconfig
)
667 Add_SPDX(f
, Kconfig
, GPL2_only
)
668 f
.WriteString(`if VENDOR_` + vendorUpper
+ `
671 prompt "Mainboard model"
673 source "src/mainboard/` + vendorSane
+ `/*/Kconfig.name"
677 source "src/mainboard/` + vendorSane
+ `/*/Kconfig"
679 config MAINBOARD_VENDOR
681 default "` + vendor
+ `"
683 endif # VENDOR_` + vendorUpper
+ "\n")
685 kconfigName
:= vendorDir
+ "/Kconfig.name"
686 if _
, err
:= os
.Stat(kconfigName
); os
.IsNotExist(err
) {
687 f
, err
:= os
.Create(kconfigName
)
692 Add_SPDX(f
, Kconfig
, GPL2_only
)
693 f
.WriteString(`config VENDOR_` + vendorUpper
+ `
694 bool "` + vendor
+ `"
700 func GuessECGPE(ctx Context
) int {
701 /* FIXME:XX Use iasl -d and/or better parsing */
702 dsdt
:= ctx
.InfoSource
.GetACPI()["DSDT"]
703 idx
:= bytes
.Index(dsdt
, []byte{0x08, '_', 'G', 'P', 'E', 0x0a}) /* Name (_GPE, byte). */
705 return int(dsdt
[idx
+6])
710 func GuessSPDMap(ctx Context
) []uint8 {
711 dmi
:= ctx
.InfoSource
.GetDMI()
713 if dmi
.Vendor
== "LENOVO" {
714 return []uint8{0x50, 0x52, 0x51, 0x53}
716 return []uint8{0x50, 0x51, 0x52, 0x53}
724 ctx
.InfoSource
= MakeLogReader()
726 dmi
:= ctx
.InfoSource
.GetDMI()
728 ctx
.Vendor
= dmi
.Vendor
730 if dmi
.Vendor
== "LENOVO" {
731 ctx
.Model
= dmi
.Version
733 ctx
.Model
= dmi
.Model
737 KconfigBool
["SYSTEM_TYPE_LAPTOP"] = true
739 ctx
.SaneVendor
= sanitize(ctx
.Vendor
)
741 last
:= ctx
.SaneVendor
742 for _
, suf
:= range []string{"_inc", "_co", "_corp"} {
743 ctx
.SaneVendor
= strings
.TrimSuffix(ctx
.SaneVendor
, suf
)
745 if last
== ctx
.SaneVendor
{
749 ctx
.MoboID
= ctx
.SaneVendor
+ "/" + sanitize(ctx
.Model
)
750 ctx
.KconfigName
= "BOARD_" + strings
.ToUpper(ctx
.SaneVendor
+"_"+sanitize(ctx
.Model
))
751 ctx
.BaseDirectory
= *FlagOutDir
+ MoboDir
+ ctx
.MoboID
752 KconfigString
["MAINBOARD_DIR"] = ctx
.MoboID
753 KconfigString
["MAINBOARD_PART_NUMBER"] = ctx
.Model
755 os
.MkdirAll(ctx
.BaseDirectory
, 0700)
762 KconfigBool
["MAINBOARD_HAS_LIBGFXINIT"] = true
763 KconfigComment
["MAINBOARD_HAS_LIBGFXINIT"] = "FIXME: check this"
764 AddRAMStageFile("gma-mainboard.ads", "CONFIG_MAINBOARD_USE_LIBGFXINIT")
767 if len(BootBlockFiles
) > 0 ||
len(ROMStageFiles
) > 0 ||
len(RAMStageFiles
) > 0 ||
len(SMMFiles
) > 0 {
768 mf
:= Create(ctx
, "Makefile.mk")
770 Add_SPDX(mf
, Makefile
, GPL2_only
)
771 writeMF(mf
, BootBlockFiles
, "bootblock")
772 writeMF(mf
, ROMStageFiles
, "romstage")
773 writeMF(mf
, RAMStageFiles
, "ramstage")
774 writeMF(mf
, SMMFiles
, "smm")
777 devtree
:= Create(ctx
, "devicetree.cb")
778 defer devtree
.Close()
781 WriteDev(devtree
, 0, "", DevTree
)
783 if MainboardInit
!= "" || MainboardEnable
!= "" || MainboardIncludes
!= nil {
784 mainboard
:= Create(ctx
, "mainboard.c")
785 defer mainboard
.Close()
786 Add_SPDX(mainboard
, C
, GPL2_only
)
787 mainboard
.WriteString("#include <device/device.h>\n")
788 for _
, include
:= range MainboardIncludes
{
789 mainboard
.WriteString("#include <" + include
+ ">\n")
791 mainboard
.WriteString("\n")
792 if MainboardInit
!= "" {
793 mainboard
.WriteString(`static void mainboard_init(struct device *dev)
795 ` + MainboardInit
+ "}\n\n")
797 if MainboardInit
!= "" || MainboardEnable
!= "" {
798 mainboard
.WriteString("static void mainboard_enable(struct device *dev)\n{\n")
799 if MainboardInit
!= "" {
800 mainboard
.WriteString("\tdev->ops->init = mainboard_init;\n\n")
802 mainboard
.WriteString(MainboardEnable
)
803 mainboard
.WriteString("}\n\n")
804 mainboard
.WriteString(`struct chip_operations mainboard_ops = {
805 .enable_dev = mainboard_enable,
811 bi
:= Create(ctx
, "board_info.txt")
817 bi
.WriteString("Category: laptop\n")
819 bi
.WriteString("Category: desktop\n")
820 fixme
+= "check category, "
823 missing
:= "ROM package, ROM socketed"
825 if ROMProtocol
!= "" {
826 fmt
.Fprintf(bi
, "ROM protocol: %s\n", ROMProtocol
)
828 missing
+= ", ROM protocol"
831 if FlashROMSupport
!= "" {
832 fmt
.Fprintf(bi
, "Flashrom support: %s\n", FlashROMSupport
)
834 missing
+= ", Flashrom support"
837 missing
+= ", Release year"
840 fmt
.Fprintf(bi
, "FIXME: %s, put %s\n", fixme
, missing
)
842 fmt
.Fprintf(bi
, "FIXME: put %s\n", missing
)
846 KconfigBool
["BOARD_ROMSIZE_KB_2048"] = true
847 KconfigComment
["BOARD_ROMSIZE_KB_2048"] = "FIXME: correct this"
849 KconfigBool
[fmt
.Sprintf("BOARD_ROMSIZE_KB_%d", ROMSizeKB
)] = true
855 dsdt
:= Create(ctx
, "dsdt.asl")
857 Add_SPDX(dsdt
, ASL
, GPL2_only
)
859 for _
, define
:= range DSDTDefines
{
860 if define
.Comment
!= "" {
861 fmt
.Fprintf(dsdt
, "\t/* %s. */\n", define
.Comment
)
863 dsdt
.WriteString("#define " + define
.Key
+ " " + define
.Value
+ "\n")
867 `#include <acpi/acpi.h>
878 #include <acpi/dsdt_top.asl>
879 #include "acpi/platform.asl"
882 for _
, x
:= range DSDTIncludes
{
884 fmt
.Fprintf(dsdt
, "\t/* %s. */\n", x
.Comment
)
886 fmt
.Fprintf(dsdt
, "\t#include <%s>\n", x
.File
)
893 for _
, x
:= range DSDTPCI0Includes
{
895 fmt
.Fprintf(dsdt
, "\t/* %s. */\n", x
.Comment
)
897 fmt
.Fprintf(dsdt
, "\t\t#include <%s>\n", x
.File
)
905 gma
:= Create(ctx
, "gma-mainboard.ads")
907 Add_SPDX(gma
, Ada
, GPL2_or_later
)
909 gma
.WriteString(`with HW.GFX.GMA;
910 with HW.GFX.GMA.Display_Probing;
913 use HW.GFX.GMA.Display_Probing;
915 private package GMA.Mainboard is
918 ports : constant Port_List :=
932 outputPath
, _
:= filepath
.Abs(ctx
.BaseDirectory
)
933 fmt
.Printf("Done! Generated sources are in %s\n", outputPath
)