1 /* This is just an experiment. Full automatic porting
2 is probably not possible but a lot can be automated. */
21 type PCIDevData
struct {
28 type PCIDevice
interface {
29 Scan(ctx Context
, addr PCIDevData
)
32 type InteltoolData
struct {
33 GPIO
map[uint16]uint32
34 RCBA
map[uint16]uint32
45 type AzaliaCodec
struct {
50 PinConfig
map[int]uint32
53 type DevReader
interface {
54 GetPCIList() []PCIDevData
56 GetInteltool() InteltoolData
57 GetAzaliaCodecs() []AzaliaCodec
58 GetACPI() map[string][]byte
59 GetCPUModel() []uint32
61 GetIOPorts() []IOPorts
71 type SouthBridger
interface {
72 GetGPIOHeader() string
76 NeedRouteGPIOManually()
79 var SouthBridge SouthBridger
80 var BootBlockFiles
map[string]string = map[string]string{}
81 var ROMStageFiles
map[string]string = map[string]string{}
82 var RAMStageFiles
map[string]string = map[string]string{}
83 var SMMFiles
map[string]string = map[string]string{}
84 var MainboardInit
string
85 var MainboardEnable
string
86 var MainboardIncludes
[]string
98 type IOAPICIRQ
struct {
103 var IOAPICIRQs
map[PCIAddr
]IOAPICIRQ
= map[PCIAddr
]IOAPICIRQ
{}
104 var KconfigBool
map[string]bool = map[string]bool{}
105 var KconfigComment
map[string]string = map[string]string{}
106 var KconfigString
map[string]string = map[string]string{}
107 var KconfigStringUnquoted
map[string]string = map[string]string{}
108 var KconfigHex
map[string]uint32 = map[string]uint32{}
109 var KconfigInt
map[string]int = map[string]int{}
112 var FlashROMSupport
= ""
114 func GetLE16(inp
[]byte) uint16 {
115 return uint16(inp
[0]) |
(uint16(inp
[1]) << 8)
118 func FormatHexLE16(inp
[]byte) string {
119 return fmt
.Sprintf("0x%04x", GetLE16(inp
))
122 func FormatHex32(u
uint32) string {
123 return fmt
.Sprintf("0x%08x", u
)
126 func FormatHex8(u
uint8) string {
127 return fmt
.Sprintf("0x%02x", u
)
130 func FormatInt32(u
uint32) string {
131 return fmt
.Sprintf("%d", u
)
134 func FormatHexLE32(d
[]uint8) string {
135 u
:= uint32(d
[0]) |
(uint32(d
[1]) << 8) |
(uint32(d
[2]) << 16) |
(uint32(d
[3]) << 24)
136 return FormatHex32(u
)
139 func FormatBool(inp
bool) string {
147 func sanitize(inp
string) string {
148 result
:= strings
.ToLower(inp
)
149 result
= strings
.Replace(result
, " ", "_", -1)
150 result
= strings
.Replace(result
, ",", "_", -1)
151 result
= strings
.Replace(result
, "-", "_", -1)
152 for strings
.HasSuffix(result
, ".") {
153 result
= result
[0 : len(result
)-1]
158 func AddBootBlockFile(Name
string, Condition
string) {
159 BootBlockFiles
[Name
] = Condition
162 func AddROMStageFile(Name
string, Condition
string) {
163 ROMStageFiles
[Name
] = Condition
166 func AddRAMStageFile(Name
string, Condition
string) {
167 RAMStageFiles
[Name
] = Condition
170 func AddSMMFile(Name
string, Condition
string) {
171 SMMFiles
[Name
] = Condition
174 func IsIOPortUsedBy(ctx Context
, port
uint16, name
string) bool {
175 for _
, io
:= range ctx
.InfoSource
.GetIOPorts() {
176 if io
.Start
<= port
&& port
<= io
.End
&& io
.Usage
== name
{
183 var FlagOutDir
= flag
.String("coreboot_dir", ".", "Resulting coreboot directory")
185 func writeMF(mf
*os
.File
, files
map[string]string, category
string) {
187 for file
, _
:= range files
{
188 keys
= append(keys
, file
)
193 for _
, file
:= range keys
{
194 condition
:= files
[file
]
196 fmt
.Fprintf(mf
, "%s-y += %s\n", category
, file
)
198 fmt
.Fprintf(mf
, "%s-$(%s) += %s\n", category
, condition
, file
)
203 func Create(ctx Context
, name
string) *os
.File
{
204 li
:= strings
.LastIndex(name
, "/")
206 os
.MkdirAll(ctx
.BaseDirectory
+"/"+name
[0:li
], 0700)
208 mf
, err
:= os
.Create(ctx
.BaseDirectory
+ "/" + name
)
215 func Add_gpl(fp
*os
.File
) {
217 * This file is part of the coreboot project.
219 * Copyright (C) 2008-2009 coresystems GmbH
220 * Copyright (C) 2014 Vladimir Serbinenko
222 * This program is free software; you can redistribute it and/or
223 * modify it under the terms of the GNU General Public License as
224 * published by the Free Software Foundation; version 2 of
227 * This program is distributed in the hope that it will be useful,
228 * but WITHOUT ANY WARRANTY; without even the implied warranty of
229 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
230 * GNU General Public License for more details.
236 func RestorePCI16Simple(f
*os
.File
, pcidev PCIDevData
, addr
uint16) {
237 fmt
.Fprintf(f
, " pci_write_config16(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x);\n",
238 pcidev
.Bus
, pcidev
.Dev
, pcidev
.Func
, addr
,
239 pcidev
.ConfigDump
[addr
+1],
240 pcidev
.ConfigDump
[addr
])
243 func RestorePCI32Simple(f
*os
.File
, pcidev PCIDevData
, addr
uint16) {
244 fmt
.Fprintf(f
, " pci_write_config32(PCI_DEV(%d, 0x%02x, %d), 0x%02x, 0x%02x%02x%02x%02x);\n",
245 pcidev
.Bus
, pcidev
.Dev
, pcidev
.Func
, addr
,
246 pcidev
.ConfigDump
[addr
+3],
247 pcidev
.ConfigDump
[addr
+2],
248 pcidev
.ConfigDump
[addr
+1],
249 pcidev
.ConfigDump
[addr
])
252 func RestoreRCBA32(f
*os
.File
, inteltool InteltoolData
, addr
uint16) {
253 fmt
.Fprintf(f
, "\tRCBA32(0x%04x) = 0x%08x;\n", addr
, inteltool
.RCBA
[addr
])
256 type PCISlot
struct {
258 additionalComment
string
262 type DevTreeNode
struct {
267 Registers
map[string]string
268 IOs
map[uint16]uint16
269 Children
[]DevTreeNode
280 var DevTree DevTreeNode
281 var MissingChildren
map[string][]DevTreeNode
= map[string][]DevTreeNode
{}
282 var unmatchedPCIChips
map[PCIAddr
]DevTreeNode
= map[PCIAddr
]DevTreeNode
{}
283 var unmatchedPCIDevices
map[PCIAddr
]DevTreeNode
= map[PCIAddr
]DevTreeNode
{}
285 func Offset(dt
*os
.File
, offset
int) {
286 for i
:= 0; i
< offset
; i
++ {
287 fmt
.Fprintf(dt
, "\t")
291 func MatchDev(dev
*DevTreeNode
) {
292 for idx
:= range dev
.Children
{
293 MatchDev(&dev
.Children
[idx
])
296 for _
, slot
:= range dev
.PCISlots
{
297 slotChip
, ok
:= unmatchedPCIChips
[slot
.PCIAddr
]
303 if slot
.additionalComment
!= "" && slotChip
.Comment
!= "" {
304 slotChip
.Comment
= slot
.additionalComment
+ " " + slotChip
.Comment
306 slotChip
.Comment
= slot
.additionalComment
+ slotChip
.Comment
309 delete(unmatchedPCIChips
, slot
.PCIAddr
)
311 dev
.Children
= append(dev
.Children
, slotChip
)
314 if dev
.PCIController
{
315 for slot
, slotDev
:= range unmatchedPCIChips
{
316 if slot
.Bus
== dev
.ChildPCIBus
{
317 delete(unmatchedPCIChips
, slot
)
319 dev
.Children
= append(dev
.Children
, slotDev
)
324 for _
, slot
:= range dev
.PCISlots
{
325 slotDev
, ok
:= unmatchedPCIDevices
[slot
.PCIAddr
]
328 dev
.Children
= append(dev
.Children
,
330 Registers
: map[string]string{},
335 Comment
: slot
.additionalComment
,
343 if slot
.additionalComment
!= "" && slotDev
.Comment
!= "" {
344 slotDev
.Comment
= slot
.additionalComment
+ " " + slotDev
.Comment
346 slotDev
.Comment
= slot
.additionalComment
+ slotDev
.Comment
350 dev
.Children
= append(dev
.Children
, slotDev
)
351 delete(unmatchedPCIDevices
, slot
.PCIAddr
)
354 if dev
.MissingParent
!= "" {
355 for _
, child
:= range MissingChildren
[dev
.MissingParent
] {
357 dev
.Children
= append(dev
.Children
, child
)
359 delete(MissingChildren
, dev
.MissingParent
)
362 if dev
.PCIController
{
363 for slot
, slotDev
:= range unmatchedPCIDevices
{
364 if slot
.Bus
== dev
.ChildPCIBus
{
366 dev
.Children
= append(dev
.Children
, slotDev
)
367 delete(unmatchedPCIDevices
, slot
)
373 func writeOn(dt
*os
.File
, dev DevTreeNode
) {
375 fmt
.Fprintf(dt
, "off")
377 fmt
.Fprintf(dt
, "on")
381 func WriteDev(dt
*os
.File
, offset
int, dev DevTreeNode
) {
384 case "cpu_cluster", "lapic", "domain", "ioapic":
385 fmt
.Fprintf(dt
, "device %s 0x%x ", dev
.Chip
, dev
.Dev
)
388 fmt
.Fprintf(dt
, "device %s %02x.%x ", dev
.Chip
, dev
.Dev
, dev
.Func
)
391 fmt
.Fprintf(dt
, "device %s %02x ", dev
.Chip
, dev
.Dev
)
394 fmt
.Fprintf(dt
, "chip %s", dev
.Chip
)
396 if dev
.Comment
!= "" {
397 fmt
.Fprintf(dt
, " # %s", dev
.Comment
)
399 fmt
.Fprintf(dt
, "\n")
400 if dev
.Chip
== "pci" && dev
.SubSystem
!= 0 && dev
.SubVendor
!= 0 {
402 fmt
.Fprintf(dt
, "subsystemid 0x%04x 0x%04x\n", dev
.SubVendor
, dev
.SubSystem
)
405 ioapic
, ok
:= IOAPICIRQs
[PCIAddr
{Bus
: dev
.Bus
, Dev
: dev
.Dev
, Func
: dev
.Func
}]
406 if dev
.Chip
== "pci" && ok
{
407 for pin
, irq
:= range ioapic
.IRQNO
{
410 fmt
.Fprintf(dt
, "ioapic_irq %d INT%c 0x%x\n", ioapic
.APICID
, 'A'+pin
, irq
)
416 for reg
, _
:= range dev
.Registers
{
417 keys
= append(keys
, reg
)
422 for _
, reg
:= range keys
{
423 val
:= dev
.Registers
[reg
]
425 fmt
.Fprintf(dt
, "register \"%s\" = \"%s\"\n", reg
, val
)
429 for reg
, _
:= range dev
.IOs
{
430 ios
= append(ios
, int(reg
))
435 for _
, reg
:= range ios
{
436 val
:= dev
.IOs
[uint16(reg
)]
438 fmt
.Fprintf(dt
, "io 0x%x = 0x%x\n", reg
, val
)
441 for _
, child
:= range dev
.Children
{
442 WriteDev(dt
, offset
+1, child
)
446 fmt
.Fprintf(dt
, "end\n")
449 func PutChip(domain
string, cur DevTreeNode
) {
450 MissingChildren
[domain
] = append(MissingChildren
[domain
], cur
)
453 func PutPCIChip(addr PCIDevData
, cur DevTreeNode
) {
454 unmatchedPCIChips
[addr
.PCIAddr
] = cur
457 func PutPCIDevParent(addr PCIDevData
, comment
string, parent
string) {
459 Registers
: map[string]string{},
464 MissingParent
: parent
,
467 if addr
.ConfigDump
[0xa] == 0x04 && addr
.ConfigDump
[0xb] == 0x06 {
468 cur
.PCIController
= true
469 cur
.ChildPCIBus
= int(addr
.ConfigDump
[0x19])
472 for capPtr
:= addr
.ConfigDump
[0x34]; capPtr
!= 0; capPtr
= addr
.ConfigDump
[capPtr
+1] {
473 /* Avoid hangs. There are only 0x100 different possible values for capPtr.
474 If we iterate longer than that, we're in endless loop. */
479 if addr
.ConfigDump
[capPtr
] == 0x0d {
480 cur
.SubVendor
= GetLE16(addr
.ConfigDump
[capPtr
+4 : capPtr
+6])
481 cur
.SubSystem
= GetLE16(addr
.ConfigDump
[capPtr
+6 : capPtr
+8])
485 cur
.SubVendor
= GetLE16(addr
.ConfigDump
[0x2c:0x2e])
486 cur
.SubSystem
= GetLE16(addr
.ConfigDump
[0x2e:0x30])
488 unmatchedPCIDevices
[addr
.PCIAddr
] = cur
491 func PutPCIDev(addr PCIDevData
, comment
string) {
492 PutPCIDevParent(addr
, comment
, "")
495 type GenericPCI
struct {
501 type GenericVGA
struct {
505 type DSDTInclude
struct {
510 type DSDTDefine
struct {
516 var DSDTIncludes
[]DSDTInclude
517 var DSDTPCI0Includes
[]DSDTInclude
518 var DSDTDefines
[]DSDTDefine
520 func (g GenericPCI
) Scan(ctx Context
, addr PCIDevData
) {
521 PutPCIDevParent(addr
, g
.Comment
, g
.MissingParent
)
524 var IGDEnabled
bool = false
526 func (g GenericVGA
) Scan(ctx Context
, addr PCIDevData
) {
527 KconfigString
["VGA_BIOS_ID"] = fmt
.Sprintf("%04x,%04x",
530 KconfigString
["VGA_BIOS_FILE"] = fmt
.Sprintf("pci%04x,%04x.rom",
533 PutPCIDevParent(addr
, g
.Comment
, g
.MissingParent
)
537 func makeKconfigName(ctx Context
) {
538 kn
:= Create(ctx
, "Kconfig.name")
541 fmt
.Fprintf(kn
, "config %s\n\tbool \"%s\"\n", ctx
.KconfigName
, ctx
.Model
)
544 func makeComment(name
string) string {
545 cmt
, ok
:= KconfigComment
[name
]
552 func makeKconfig(ctx Context
) {
553 kc
:= Create(ctx
, "Kconfig")
556 fmt
.Fprintf(kc
, "if %s\n\n", ctx
.KconfigName
)
558 fmt
.Fprintf(kc
, "config BOARD_SPECIFIC_OPTIONS\n\tdef_bool y\n")
560 for name
, val
:= range KconfigBool
{
562 keys
= append(keys
, name
)
568 for _
, name
:= range keys
{
569 fmt
.Fprintf(kc
, "\tselect %s%s\n", name
, makeComment(name
))
573 for name
, val
:= range KconfigBool
{
575 keys
= append(keys
, name
)
581 for _
, name
:= range keys
{
586 `, name
, makeComment(name
))
590 for name
, _
:= range KconfigStringUnquoted
{
591 keys
= append(keys
, name
)
596 for _
, name
:= range keys
{
601 `, name
, makeComment(name
), KconfigStringUnquoted
[name
])
605 for name
, _
:= range KconfigString
{
606 keys
= append(keys
, name
)
611 for _
, name
:= range keys
{
616 `, name
, makeComment(name
), KconfigString
[name
])
620 for name
, _
:= range KconfigHex
{
621 keys
= append(keys
, name
)
626 for _
, name
:= range keys
{
631 `, name
, makeComment(name
), KconfigHex
[name
])
635 for name
, _
:= range KconfigInt
{
636 keys
= append(keys
, name
)
641 for _
, name
:= range keys
{
646 `, name
, makeComment(name
), KconfigInt
[name
])
649 fmt
.Fprintf(kc
, "endif\n")
652 const MoboDir
= "/src/mainboard/"
654 func makeVendor(ctx Context
) {
656 vendorSane
:= ctx
.SaneVendor
657 vendorDir
:= *FlagOutDir
+ MoboDir
+ vendorSane
658 vendorUpper
:= strings
.ToUpper(vendorSane
)
659 kconfig
:= vendorDir
+ "/Kconfig"
660 if _
, err
:= os
.Stat(kconfig
); os
.IsNotExist(err
) {
661 f
, err
:= os
.Create(kconfig
)
666 f
.WriteString(`if VENDOR_` + vendorUpper
+ `
669 prompt "Mainboard model"
671 source "src/mainboard/` + vendorSane
+ `/*/Kconfig.name"
675 source "src/mainboard/` + vendorSane
+ `/*/Kconfig"
677 config MAINBOARD_VENDOR
679 default "` + vendor
+ `"
681 endif # VENDOR_` + vendorUpper
+ "\n")
683 kconfigName
:= vendorDir
+ "/Kconfig.name"
684 if _
, err
:= os
.Stat(kconfigName
); os
.IsNotExist(err
) {
685 f
, err
:= os
.Create(kconfigName
)
690 f
.WriteString(`config VENDOR_` + vendorUpper
+ `
691 bool "` + vendor
+ `"
697 func GuessECGPE(ctx Context
) int {
698 /* FIXME:XX Use iasl -d and/or better parsing */
699 dsdt
:= ctx
.InfoSource
.GetACPI()["DSDT"]
700 idx
:= bytes
.Index(dsdt
, []byte{0x08, '_', 'G', 'P', 'E', 0x0a}) /* Name (_GPE, byte). */
702 return int(dsdt
[idx
+6])
707 func GuessSPDMap(ctx Context
) []uint8 {
708 dmi
:= ctx
.InfoSource
.GetDMI()
710 if dmi
.Vendor
== "LENOVO" {
711 return []uint8{0x50, 0x52, 0x51, 0x53}
713 return []uint8{0x50, 0x51, 0x52, 0x53}
721 ctx
.InfoSource
= MakeLogReader()
723 dmi
:= ctx
.InfoSource
.GetDMI()
725 ctx
.Vendor
= dmi
.Vendor
727 if dmi
.Vendor
== "LENOVO" {
728 ctx
.Model
= dmi
.Version
730 ctx
.Model
= dmi
.Model
734 KconfigBool
["SYSTEM_TYPE_LAPTOP"] = true
736 ctx
.SaneVendor
= sanitize(ctx
.Vendor
)
738 last
:= ctx
.SaneVendor
739 for _
, suf
:= range []string{"_inc", "_co", "_corp"} {
740 ctx
.SaneVendor
= strings
.TrimSuffix(ctx
.SaneVendor
, suf
)
742 if last
== ctx
.SaneVendor
{
746 ctx
.MoboID
= ctx
.SaneVendor
+ "/" + sanitize(ctx
.Model
)
747 ctx
.KconfigName
= "BOARD_" + strings
.ToUpper(ctx
.SaneVendor
+"_"+sanitize(ctx
.Model
))
748 ctx
.BaseDirectory
= *FlagOutDir
+ MoboDir
+ ctx
.MoboID
749 KconfigStringUnquoted
["MAINBOARD_DIR"] = ctx
.MoboID
750 KconfigString
["MAINBOARD_PART_NUMBER"] = ctx
.Model
752 os
.MkdirAll(ctx
.BaseDirectory
, 0700)
759 KconfigBool
["MAINBOARD_HAS_LIBGFXINIT"] = true
760 KconfigComment
["MAINBOARD_HAS_LIBGFXINIT"] = "FIXME: check this"
761 AddRAMStageFile("gma-mainboard.ads", "CONFIG_MAINBOARD_USE_LIBGFXINIT")
764 if len(BootBlockFiles
) > 0 ||
len(ROMStageFiles
) > 0 ||
len(RAMStageFiles
) > 0 ||
len(SMMFiles
) > 0 {
765 mf
:= Create(ctx
, "Makefile.inc")
767 writeMF(mf
, BootBlockFiles
, "bootblock")
768 writeMF(mf
, ROMStageFiles
, "romstage")
769 writeMF(mf
, RAMStageFiles
, "ramstage")
770 writeMF(mf
, SMMFiles
, "smm")
773 devtree
:= Create(ctx
, "devicetree.cb")
774 defer devtree
.Close()
777 WriteDev(devtree
, 0, DevTree
)
779 if MainboardInit
!= "" || MainboardEnable
!= "" || MainboardIncludes
!= nil {
780 mainboard
:= Create(ctx
, "mainboard.c")
781 defer mainboard
.Close()
782 mainboard
.WriteString("#include <device/device.h>\n")
783 for _
, include
:= range MainboardIncludes
{
784 mainboard
.WriteString("#include <" + include
+ ">\n")
786 mainboard
.WriteString("\n")
787 if MainboardInit
!= "" {
788 mainboard
.WriteString(`static void mainboard_init(struct device *dev)
790 ` + MainboardInit
+ "}\n\n")
792 if MainboardInit
!= "" || MainboardEnable
!= "" {
793 mainboard
.WriteString("static void mainboard_enable(struct device *dev)\n{\n")
794 if MainboardInit
!= "" {
795 mainboard
.WriteString("\tdev->ops->init = mainboard_init;\n\n")
797 mainboard
.WriteString(MainboardEnable
)
798 mainboard
.WriteString("}\n\n")
799 mainboard
.WriteString(`struct chip_operations mainboard_ops = {
800 .enable_dev = mainboard_enable,
806 bi
:= Create(ctx
, "board_info.txt")
812 bi
.WriteString("Category: laptop\n")
814 bi
.WriteString("Category: desktop\n")
815 fixme
+= "check category, "
818 missing
:= "ROM package, ROM socketed"
820 if ROMProtocol
!= "" {
821 fmt
.Fprintf(bi
, "ROM protocol: %s\n", ROMProtocol
)
823 missing
+= ", ROM protocol"
826 if FlashROMSupport
!= "" {
827 fmt
.Fprintf(bi
, "Flashrom support: %s\n", FlashROMSupport
)
829 missing
+= ", Flashrom support"
832 missing
+= ", Release year"
835 fmt
.Fprintf(bi
, "FIXME: %s, put %s\n", fixme
, missing
)
837 fmt
.Fprintf(bi
, "FIXME: put %s\n", missing
)
841 KconfigBool
["BOARD_ROMSIZE_KB_2048"] = true
842 KconfigComment
["BOARD_ROMSIZE_KB_2048"] = "FIXME: correct this"
844 KconfigBool
[fmt
.Sprintf("BOARD_ROMSIZE_KB_%d", ROMSizeKB
)] = true
850 dsdt
:= Create(ctx
, "dsdt.asl")
853 for _
, define
:= range DSDTDefines
{
854 if define
.Comment
!= "" {
855 fmt
.Fprintf(dsdt
, "\t/* %s. */\n", define
.Comment
)
857 dsdt
.WriteString("#define " + define
.Key
+ " " + define
.Value
+ "\n")
863 #include <arch/acpi.h>
868 0x02, /* DSDT revision: ACPI 2.0 and up */
871 0x20141018 /* OEM revision */
874 #include "acpi/platform.asl"
877 for _
, x
:= range DSDTIncludes
{
879 fmt
.Fprintf(dsdt
, "\t/* %s. */\n", x
.Comment
)
881 fmt
.Fprintf(dsdt
, "\t#include <%s>\n", x
.File
)
888 for _
, x
:= range DSDTPCI0Includes
{
890 fmt
.Fprintf(dsdt
, "\t/* %s. */\n", x
.Comment
)
892 fmt
.Fprintf(dsdt
, "\t\t#include <%s>\n", x
.File
)
900 gma
:= Create(ctx
, "gma-mainboard.ads")
904 -- This file is part of the coreboot project.
906 -- This program is free software; you can redistribute it and/or modify
907 -- it under the terms of the GNU General Public License as published by
908 -- the Free Software Foundation; either version 2 of the License, or
909 -- (at your option) any later version.
911 -- This program is distributed in the hope that it will be useful,
912 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
913 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
914 -- GNU General Public License for more details.
918 with HW.GFX.GMA.Display_Probing;
921 use HW.GFX.GMA.Display_Probing;
923 private package GMA.Mainboard is
926 ports : constant Port_List :=