Maxim Polyakov has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/35643 )
Change subject: util/intelp2m: initial commit ......................................................................
util/intelp2m: initial commit
intelp2m - Intel Pad to Macro
A small utility for converting a pad configuration from an inteltool dump to a PAD_CFG_ * macro coreboot.
Tested on Asroch-H110M-DVS motherboard [2]
[1] https://github.com/maxpoliak/pch-pads-parser [2] https://review.coreboot.org/c/coreboot/+/33565
Change-Id: If3e3b523c4f63dc2f91e9ccd16934e3a1b6e21fa Signed-off-by: Maxim Polyakov max.senia.poliak@gmail.com --- A util/intelp2m/main.go A util/intelp2m/parser/parser.go A util/intelp2m/sunrise/dw.go A util/intelp2m/sunrise/macro.go 4 files changed, 871 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/43/35643/1
diff --git a/util/intelp2m/main.go b/util/intelp2m/main.go new file mode 100644 index 0000000..0881e10 --- /dev/null +++ b/util/intelp2m/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "flag" + "fmt" + "os" +) + +import "./parser" + +// HdrInfoAdd - adds license header to file f +func HdrInfoAdd(f *os.File) { + f.WriteString(`/* + * This file is part of the coreboot project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +`) +} + +// CreateHdrFile - generates include file +func CreateHdrFile() (err error) { + hrdFile, err := os.Create("generate/gpio.h") + if err != nil { + fmt.Printf("Error!\n") + return err + } + defer hrdFile.Close() + + HdrInfoAdd(hrdFile) + hrdFile.WriteString(`#ifndef PCH_GPIO_H +#define PCH_GPIO_H + +#include <soc/gpe.h> +#include <soc/gpio.h> + +const struct pad_config *get_gpio_table(size_t *num); +const struct pad_config *get_early_gpio_table(size_t *num); + +#endif /* PCH_GPIO_H */ +`) + return nil +} + +// CreateGpioFile - generates gpio_raw.c file +// parser : parser data structure +// showRawDataFlag : raw data flag +// in the case when this flag is false, pad information will +// be create as macro +func CreateGpioFile(parser *parser.ParserData, showRawDataFlag bool) (err error) { + var name = "generate/gpio" + if showRawDataFlag { + name += "_raw" + } + name += ".c" + gpio, err := os.Create(name) + if err != nil { + fmt.Printf("Error!\n") + return err + } + defer gpio.Close() + + HdrInfoAdd(gpio) + gpio.WriteString(` +#include <commonlib/helpers.h> +#include "include/gpio.h" +`) + // Add the pads map to gpio.h file + parser.PadMapFprint(gpio, showRawDataFlag) + return nil +} + +// main +func main() { + // Command line arguments + wordPtr := flag.String("file", + "inteltool.log", + "the path to the inteltool log file") + dbgPtr := flag.Bool("dbg", false, "debug flag") + flag.Parse() + + fmt.Println("dbg:", *dbgPtr) + fmt.Println("file:", *wordPtr) + + var parser parser.ParserData + parser.DbgFlag = *dbgPtr + err := parser.Parse(*wordPtr) + if err != nil { + fmt.Printf("Parser: Error!\n") + os.Exit(1) + } + + // create dir for output files + err = os.MkdirAll("generate", os.ModePerm) + if err != nil { + fmt.Printf("Create a directory of generated files: Error!\n") + os.Exit(1) + } + + // gpio.h + err = CreateHdrFile() + if err != nil { + fmt.Printf("Create pch_gpio.h: Error!\n") + os.Exit(1) + } + + // gpio_raw.c + err = CreateGpioFile(&parser, true) + if err != nil { + fmt.Printf("Create gpio_raw.c: Error!\n") + os.Exit(1) + } + + // gpio.c with macros + err = CreateGpioFile(&parser, false) + if err != nil { + fmt.Printf("Create gpio.c: Error!\n") + os.Exit(1) + } +} diff --git a/util/intelp2m/parser/parser.go b/util/intelp2m/parser/parser.go new file mode 100644 index 0000000..b684653 --- /dev/null +++ b/util/intelp2m/parser/parser.go @@ -0,0 +1,189 @@ +package parser + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +import "../sunrise" + +// padInfo - information about pad +// id : pad id string +// offset : the offset of the register address relative to the base +// function : the string that means the pad function +// dw0 : DW0 register value +// dw1 : DW1 register value +type padInfo struct { + id string + offset uint16 + function string + community uint8 + dw0 uint32 + dw1 uint32 +} + +// add - add information about pad to data structure +// line : string from inteltool log file +func (info *padInfo) add(line string) { + var val uint64 + if strings.HasPrefix(line, "----") { + // ------- GPIO Group GPP_A ------- + // ------- GPIO Community 0 ------- + // Add header to define GPIO group or community + info.function = line + return + } + // 0x0520: 0x0000003c44000600 GPP_B12 SLP_S0# + // 0x0438: 0xffffffffffffffff GPP_C7 RESERVED + fmt.Sscanf(line, + "0x%x: 0x%x %s %s", + &info.offset, + &val, + &info.id, + &info.function) + info.dw0 = uint32(val & 0xffffffff) + info.dw1 = uint32(val >> 32) +} + +// titleFprint - print GPIO group title to file +// gpio : gpio.c file descriptor +func (info *padInfo) titleFprint(gpio *os.File) { + fmt.Fprintf(gpio, "\n\t/* %s */\n", info.function) +} + +// reservedFprint - print reserved GPIO to file as comment +// gpio : gpio.c file descriptor +func (info *padInfo) reservedFprint(gpio *os.File) { + // small comment about reserved port + fmt.Fprintf(gpio, "\t/* %s - %s */\n", info.id, info.function) +} + +// padInfoRawFprint - print information about current pad to file using +// raw format: +// _PAD_CFG_STRUCT(GPP_F1, 0x84000502, 0x00003026), /* SATAXPCIE4 */ +// gpio : gpio.c file descriptor +func (info *padInfo) padInfoRawFprint(gpio *os.File) { + fmt.Fprintf(gpio, + "\t_PAD_CFG_STRUCT(%s, 0x%0.8x, 0x%0.8x), /* %s */\n", + info.id, + info.dw0, + (info.dw1 & 0xffffff00), // Interrupt Select - RO + info.function) +} + +// padInfoMacroFprint - print information about current pad to file using +// special macros: +// PAD_CFG_NF(GPP_F1, 20K_PU, PLTRST, NF1), /* SATAXPCIE4 */ +// gpio : gpio.c file descriptor +func (info *padInfo) padInfoMacroFprint(gpio *os.File) { + fmt.Fprintf(gpio, "\t/* %s - %s */\n\t%s\n", + info.id, + info.function, + sunrise.GetMacro(info.id, info.dw0, info.dw1)) +} + +// ParserData - global data +// padmap : pad info map +// dbgFlag : gebug flag, currently not used +type ParserData struct { + padmap []padInfo + DbgFlag bool +} + +// padInfoAdd - adds a new entry to pad info map +// line : string/line from the inteltool log file +// community : pads community number +func (parser *ParserData) padInfoAdd(line string, community uint8) { + pad := padInfo{community : community} + pad.add(line) + parser.padmap = append(parser.padmap, pad) +} + +// getCommunity - scans the string and returns the pads community number +// line : string from inteltool log file +// return +// community number +func (parser *ParserData) getCommunity(line string) uint8 { + var comm uint8 + fmt.Sscanf(line, "------- GPIO Community %d -------", &comm) + return comm +} + +// PadMapFprint - print pad info map to file +// gpio : gpio.c descriptor file +// raw : in the case when this flag is false, pad information will be print +// as macro +func (parser *ParserData) PadMapFprint(gpio *os.File, raw bool) { + gpio.WriteString("\n/* Pad configuration in ramstage */\n") + gpio.WriteString("static const struct pad_config gpio_table[] = {\n") + for _, pad := range parser.padmap { + switch pad.dw0 { + case 0: + pad.titleFprint(gpio) + case 0xffffffff: + pad.reservedFprint(gpio) + default: + if raw { + pad.padInfoRawFprint(gpio) + } else { + pad.padInfoMacroFprint(gpio) + } + } + } + gpio.WriteString("};\n") + + // FIXME: need to add early configuration + gpio.WriteString(`/* Early pad configuration in romstage. */ +static const struct pad_config early_gpio_table[] = { + /* TODO: Add early pad configuration */ +}; + +const struct pad_config *get_gpio_table(size_t *num) +{ + *num = ARRAY_SIZE(gpio_table); + return gpio_table; +} + +const struct pad_config *get_early_gpio_table(size_t *num) +{ + *num = ARRAY_SIZE(early_gpio_table); + return early_gpio_table; +} + +`) +} + +// Parse pads groupe information in the inteltool log file +// logFile : name of inteltool log file +// return +// err : error +func (parser *ParserData) Parse(logFile string) (err error) { + file, err := os.Open(logFile) + if err != nil { + return err + } + defer file.Close() + + // Read all lines from inteltool log file + fmt.Println("Parse IntelTool Log File...") + scanner := bufio.NewScanner(file) + var line string + var community uint8 = 0 + for scanner.Scan() { + line = scanner.Text() + // Use only the string that contains the GPP information + if !strings.Contains(line, "GPP_") && !strings.Contains(line, "GPD") { + // ------- GPIO Community 0 ------- + if strings.Contains(line, "Community") { + community = parser.getCommunity(line) + } else { + continue + } + } + parser.padInfoAdd(line, community) + } + fmt.Println("...done!") + return nil +} \ No newline at end of file diff --git a/util/intelp2m/sunrise/dw.go b/util/intelp2m/sunrise/dw.go new file mode 100644 index 0000000..f3623b0 --- /dev/null +++ b/util/intelp2m/sunrise/dw.go @@ -0,0 +1,198 @@ +package sunrise + +// Bit field constants for DW0 register +const ( + padRstCfgShift uint8 = 30 + padRstCfgMask uint32 = 0x3 << padRstCfgShift + + rxPadStateSelectShift uint8 = 29 + rxPadStateSelectMask uint32 = 0x1 << rxPadStateSelectShift + + rxRawOverrideTo1Shift uint8 = 28 + rxRawOverrideTo1Mask uint32 = 0x1 << rxRawOverrideTo1Shift + + rxLevelEdgeConfigurationShift uint8 = 25 + rxLevelEdgeConfigurationMask uint32 = 0x3 << rxLevelEdgeConfigurationShift + + rxInvertShift uint8 = 23 + rxInvertMask uint32 = 0x1 << rxInvertShift + + gpioInputRouteIOxApicShift uint8 = 20 + gpioInputRouteIOxApicMask uint32 = 0x1 << gpioInputRouteIOxApicShift + + gpioInputRouteSCIShift uint8 = 19 + gpioInputRouteSCIMask uint32 = 0x1 << gpioInputRouteSCIShift + + gpioInputRouteSMIShift uint8 = 18 + gpioInputRouteSMIMask uint32 = 0x1 << gpioInputRouteSMIShift + + gpioInputRouteNMIShift uint8 = 17 + gpioInputRouteNMIMask uint32 = 0x1 << gpioInputRouteNMIShift + + padModeShift uint8 = 10 + padModeMask uint32 = 0x7 << padModeShift + + gpioRxTxDisableShift uint8 = 8 + gpioRxTxDisableMask uint32 = 0x3 << gpioRxTxDisableShift + + gpioRxStateShift uint8 = 1 + gpioRxStateMask uint32 = 0x1 << gpioRxStateShift + + gpioTxStateMask uint32 = 0x1 +) + +// Bit field constants for DW1 register +const ( + termShift uint8 = 10 + termMask uint32 = 0xF << termShift + interruptSelectShift uint32 = 0xFF +) + +// Maximum numbers of the config DW register for Sunrise chipset +const ( + MaxDWNum = 2 +) + +// dwcfg - configuration data structure based on DW0/1 reg value +// reg : register value +// mask : bit fileds mask +type dwcfg struct { + reg [MaxDWNum]uint32 + mask [MaxDWNum]uint32 +} + +// getResetConfig - get Reset Configuration from PADRSTCFG field in PAD_CFG_DW0_GPx register +func (dw *dwcfg) getFieldVal(regNum uint8, mask uint32, shift uint8) uint8 { + if regNum < MaxDWNum { + dw.mask[regNum] |= mask + return uint8((dw.reg[regNum] & mask) >> shift) + } + return 0 +} + +// Check the mask of the new macro +// regNum : DW register number +// Returns true if the macro is generated correctly +func (dw *dwcfg) maskCheck(regNum uint8) bool { + if regNum >= MaxDWNum { + return false + } + + // Take into account the bits that are read-only + readonly := [MaxDWNum]uint32{ + (0x1 << 27) | (0x1 << 24) | (0x3 << 21) | (0xf << 16) | 0xfe, + 0xfffffc3f, + } + mask := ^(dw.mask[regNum] | readonly[regNum]) + return dw.reg[regNum]&mask == 0 +} + +// Fix Pad Reset Config field in mask for DW0 register +// Returns *dwcfg +func (dw *dwcfg) maskResetFix() *dwcfg { + dw.mask[0] |= padRstCfgMask + return dw +} + +// Fix RX Level/Edge Configuration field in mask for DW0 register +// Returns *dwcfg +func (dw *dwcfg) maskTrigFix() *dwcfg { + dw.mask[0] |= rxLevelEdgeConfigurationMask + return dw +} + +// getResetConfig - returns type reset source for corresponding pad +// PADRSTCFG field in PAD_CFG_DW0 register +// 00 = RSMRST#, 01 = DEEP#, 10 = PLTRST#, 11 = RSMRST# for GPDx pads +// and Reserved for others +func (dw *dwcfg) getResetConfig() uint8 { + return dw.getFieldVal(0, padRstCfgMask, padRstCfgShift) +} + +// getRXPadStateSelect - returns RX Pad State (RXINV) +// 0 = Raw RX pad state directly from RX buffer +// 1 = Internal RX pad state +func (dw *dwcfg) getRXPadStateSelect() uint8 { + return dw.getFieldVal(0, rxPadStateSelectMask, rxPadStateSelectShift) +} + +// getRXRawOverrideStatus - returns 1 if the selected pad state is being +// overridden to '1' (RXRAW1 field) +func (dw *dwcfg) getRXRawOverrideStatus() uint8 { + return dw.getFieldVal(0, rxRawOverrideTo1Mask, rxRawOverrideTo1Shift) +} + +// getRXLevelEdgeConfiguration - returns RX Level/Edge Configuration (RXEVCFG) +// 0h = Level, 1h = Edge, 2h = Drive '0', 3h = Reserved (implement as setting 0h) +func (dw *dwcfg) getRXLevelEdgeConfiguration() uint8 { + return dw.getFieldVal(0, rxLevelEdgeConfigurationMask, rxLevelEdgeConfigurationShift) +} + +// getRXLevelConfiguration - returns RX Invert state (RXINV) +// 1 - Inversion, 0 - No inversion +func (dw *dwcfg) getRXLevelConfiguration() bool { + return dw.getFieldVal(0, rxInvertMask, rxInvertShift) != 0 +} + +// getGPIOInputRouteIOxAPIC - returns 1 if the pad can be routed to cause +// peripheral IRQ when configured in GPIO input mode. +func (dw *dwcfg) getGPIOInputRouteIOxAPIC() bool { + return dw.getFieldVal(0, gpioInputRouteIOxApicMask, gpioInputRouteIOxApicShift) != 0 +} + +// getGPIOInputRouteSCI - returns 1 if the pad can be routed to cause SCI when +// configured in GPIO input mode. +func (dw *dwcfg) getGPIOInputRouteSCI() bool { + return dw.getFieldVal(0, gpioInputRouteSCIMask, gpioInputRouteSCIShift) != 0 +} + +// getGPIOInputRouteSMI - returns 1 if the pad can be routed to cause SMI when +// configured in GPIO input mode +func (dw *dwcfg) getGPIOInputRouteSMI() bool { + return dw.getFieldVal(0, gpioInputRouteSMIMask, gpioInputRouteSMIShift) != 0 +} + +// getGPIOInputRouteNMI - returns 1 if the pad can be routed to cause NMI when +// configured in GPIO input mode +func (dw *dwcfg) getGPIOInputRouteNMI() bool { + return dw.getFieldVal(0, gpioInputRouteNMIMask, gpioInputRouteNMIShift) != 0 +} + +// getPadMode - reutrns pad mode or one of the native functions +// 0h = GPIO control the Pad. +// 1h = native function 1, if applicable, controls the Pad +// 2h = native function 2, if applicable, controls the Pad +// 3h = native function 3, if applicable, controls the Pad +// 4h = enable GPIO blink/PWM capability if applicable +func (dw *dwcfg) getPadMode() uint8 { + return dw.getFieldVal(0, padModeMask, padModeShift) +} + +// getGPIORxTxDisableStatus - returns GPIO RX/TX buffer state (GPIORXDIS | GPIOTXDIS) +// 0 - both are enabled, 1 - TX Disable, 2 - RX Disable, 3 - both are disabled +func (dw *dwcfg) getGPIORxTxDisableStatus() uint8 { + return dw.getFieldVal(0, gpioRxTxDisableMask, gpioRxTxDisableShift) +} + +// getGPIORXState - returns GPIO RX State (GPIORXSTATE) +func (dw *dwcfg) getGPIORXState() uint8 { + return dw.getFieldVal(0, gpioRxStateMask, gpioRxStateShift) +} + +// getGPIOTXState - returns GPIO TX State (GPIOTXSTATE) +func (dw *dwcfg) getGPIOTXState() int { + return int(dw.getFieldVal(0, gpioTxStateMask, 0)) +} + +// getTermination - returns the pad termination state defines the different weak +// pull-up and pull-down settings that are supported by the buffer +// 0000 = none; 0010 = 5k PD; 0100 = 20k PD; 1010 = 5k PU; 1100 = 20k PU; +// 1111 = Native controller selected +func (dw *dwcfg) getTermination() uint8 { + return dw.getFieldVal(1, termMask, termShift) +} + +// getInterruptSelect - returns Interrupt Line number from the GPIO controller +func (dw *dwcfg) getInterruptSelect() uint8 { + return dw.getFieldVal(1, interruptSelectShift, 0) +} diff --git a/util/intelp2m/sunrise/macro.go b/util/intelp2m/sunrise/macro.go new file mode 100644 index 0000000..7489709 --- /dev/null +++ b/util/intelp2m/sunrise/macro.go @@ -0,0 +1,355 @@ +package sunrise + +import ( + "fmt" + "strconv" + "strings" +) + +// macro - contains macro information and methods +// padID : pad ID string +// str : macro string entirely +// dwcfg : configuration data structure +type macro struct { + padID string + str string + dwcfg +} + +// dw - returns dwcfg data configuration structure with PAD_CFG_DW0/1 register +// values +func (macro *macro) dw() *dwcfg { + return ¯o.dwcfg +} + +// add a string to macro +func (macro *macro) add(str string) *macro { + macro.str += str + return macro +} + +// set a string in a macro instead of its previous contents +func (macro *macro) set(str string) *macro { + macro.str = str + return macro +} + +// get macro string +func (macro *macro) get() string { + return macro.str +} + +// Adds PAD Id to the macro as a new argument +// return: macro +func (macro *macro) id() *macro { + return macro.add(macro.padID) +} + +// Add separator to macro if needed +func (macro *macro) separator() *macro { + str := macro.get() + c := str[len(str)-1] + if c != '(' && c != '_' { + macro.add(", ") + } + return macro +} + +// Adds the PADRSTCFG parameter from DW0 to the macro as a new argument +// return: macro +func (macro *macro) rstsrc() *macro { + var resetSrc = map[uint8]string{ + 0x0: "PWROK", + 0x1: "DEEP", + 0x2: "PLTRST", + } + str, valid := resetSrc[macro.dw().getResetConfig()] + if !valid { + // Pad Reset Config field in DW0 register should implements 3h value + // as RSMRST for GPD pads group, but this value is reserved for other + // groups + if strings.Contains(macro.padID, "GPD") { + str = "RSMRST" + } else { + str = resetSrc[0] + fmt.Println("Warning:", macro.padID, "PADRSTCFG = 3h Reserved") + fmt.Println("It is implemented as setting 0h (PWROK) for Sunrise PCH") + } + } + return macro.separator().add(str) +} + +// Adds The Pad Termination (TERM) parameter from DW1 to the macro as a new argument +// return: macro +func (macro *macro) pull() *macro { + var pull = map[uint8]string{ + 0x0: "NONE", + 0x2: "5K_PD", + 0x4: "20K_PD", + 0x9: "1K_PU", + 0xa: "5K_PU", + 0xb: "2K_PU", + 0xc: "20K_PU", + 0xd: "667_PU", + 0xf: "NATIVE", + } + str, valid := pull[macro.dw().getTermination()] + if !valid { + str = "INVALID" + fmt.Println("Error", + macro.padID, + " invalid TERM value = ", + int(macro.dw().getTermination())) + } + return macro.separator().add(str) +} + +// Adds Pad GPO value to macro string as a new argument +// return: macro +func (macro *macro) val() *macro { + return macro.separator().add(strconv.Itoa(macro.dw().getGPIOTXState())) +} + +// Adds Pad GPO value to macro string as a new argument +// return: macro +func (macro *macro) trig() *macro { + var dw = macro.dw() + var trig = map[uint8]string{ + 0x0: "LEVEL", + 0x1: "EDGE_SINGLE", + 0x2: "OFF", + 0x3: "EDGE_BOTH", + } + return macro.separator().add(trig[dw.getRXLevelEdgeConfiguration()]) +} + +// Adds Pad Polarity Inversion Stage (RXINV) to macro string as a new argument +// return: macro +func (macro *macro) invert() *macro { + macro.separator() + if macro.dw().getRXLevelConfiguration() { + return macro.add("YES") + } + return macro.add("NONE") +} + +// Adds input/output buffer state +// return: macro +func (macro *macro) bufdis() *macro { + var buffDisStat = map[uint8]string{ + 0x0: "NO_DISABLE", // both buffers are enabled + 0x1: "TX_DISABLE", // output buffer is disabled + 0x2: "RX_DISABLE", // input buffer is disabled + 0x3: "TX_RX_DISABLE", // both buffers are disabled + } + state := macro.dw().getGPIORxTxDisableStatus() + return macro.separator().add(buffDisStat[state]) +} + +//Adds pad native function (PMODE) as a new argument +//return: macro +func (macro *macro) padfn() *macro { + nfnum := int(macro.dw().getPadMode()) + if nfnum != 0 { + return macro.separator().add("NF" + strconv.Itoa(nfnum)) + } + // GPIO used only for PAD_FUNC(x) macro + return macro.add("GPIO") +} + +// Adds suffix to GPI macro with arguments +func (macro *macro) addSuffixInput() { + dw := macro.dw() + isEdge := dw.getRXLevelEdgeConfiguration() + macro.add("_GPI") + switch { + case dw.getGPIOInputRouteNMI(): + // e.g. PAD_CFG_GPI_NMI(GPIO_24, UP_20K, DEEP, LEVEL, INVERT), + macro.add("_NMI").add("(").id().pull().rstsrc().trig().invert() + + case dw.getGPIOInputRouteIOxAPIC(): + // e.g. PAD_CFG_GPI_APIC(GPP_B3, NONE, PLTRST) + macro.add("_APIC") + if isEdge == 0 { + if dw.getRXLevelConfiguration() { + // e.g. PAD_CFG_GPI_APIC_INVERT(GPP_C5, DN_20K, DEEP), + macro.add("_INVERT") + } + macro.add("(").id().pull().rstsrc() + } else { + // PAD_CFG_GPI_APIC_IOS(GPP_C20, NONE, DEEP, LEVEL, INVERT, + // TxDRxE, DISPUPD) macro isn't used for this chipset. But, in + // the case when SOC_INTEL_COMMON_BLOCK_GPIO_LEGACY_MACROS is + // defined in the config, this macro allows you to set trig and + // invert parameters. + macro.add("_IOS").add("(").id().pull().rstsrc().trig().invert() + // IOStandby Config will be ignored for the Sunrise PCH, so use + // any values + macro.add(", TxDRxE, DISPUPD") + } + + case dw.getGPIOInputRouteSCI(): + + // e.g. PAD_CFG_GPI_SCI(GPP_B18, UP_20K, PLTRST, LEVEL, INVERT), + if (isEdge & 0x1) != 0 { + // e.g. PAD_CFG_GPI_ACPI_SCI(GPP_G2, NONE, DEEP, YES), + macro.add("_ACPI") + } + macro.add("_SCI").add("(").id().pull().rstsrc() + if (isEdge & 0x1) == 0 { + macro.trig() + } + macro.invert() + + case dw.getGPIOInputRouteSMI(): + if (isEdge & 0x1) != 0 { + // e.g. PAD_CFG_GPI_ACPI_SMI(GPP_I3, NONE, DEEP, YES), + macro.add("_ACPI") + } + macro.add("_SMI").add("(").id().pull().rstsrc().invert() + + case isEdge != 0: + // e.g. ISH_SPI_CS# + // PAD_CFG_GPI_INT(GPP_D9, NONE, PLTRST, EDGE), + macro.add("_INT").add("(").id().pull().rstsrc().trig() + + default: + // e.g. PAD_CFG_GPI(GPP_A7, NONE, DEEP), + macro.add("(").id().pull().rstsrc() + } +} + +// Adds suffix to GPO macro with arguments +func (macro *macro) addSuffixOutput() { + term := macro.dw().getTermination() + // FIXME: don`t understand how to get PAD_CFG_GPI_GPIO_DRIVER(..) + if term != 0 { + // e.g. PAD_CFG_TERM_GPO(GPP_B23, 1, DN_20K, DEEP), + macro.add("_TERM") + } + macro.add("_GPO").add("(").id().val() + if term != 0 { + macro.pull() + } + macro.rstsrc() + + // Fix mask for RX Level/Edge Configuration (RXEVCFG) + // See https://github.com/coreboot/coreboot/commit/3820e3c + macro.dw().maskTrigFix() +} + +const ( + rxDisable uint8 = 0x2 + txDisable uint8 = 0x1 +) + +// Set common macros macros if the standard ones can't define the values from +// the DW0/1 register +func (macro *macro) common() *macro { + macro.set("_PAD_CFG_STRUCT(").id(). + add(",\n\t\tPAD_FUNC(").padfn(). + add(") | PAD_RESET(").rstsrc().add(") |\n\t\t") + + var str string + var argument = true + switch dw := macro.dw(); { + case dw.getGPIOInputRouteIOxAPIC(): + str = "IOAPIC" + case dw.getGPIOInputRouteSCI(): + str = "SCI" + case dw.getGPIOInputRouteSMI(): + str = "SMI" + case dw.getGPIOInputRouteNMI(): + str = "NMI" + default: + argument = false + } + + if argument { + macro.add("PAD_IRQ_CFG(").add(str).trig().invert().add(")") + } else { + macro.add("PAD_CFG0_TRIG_").trig().add(" | PAD_CFG0_RX_POL_").invert() + } + + macro.add(" |\n\t\t").add("PAD_BUF(").bufdis().add(")") + if macro.dw().getGPIOTXState() != 0 { + macro.add(" | 1") + } + return macro.add(",\n\t\tPAD_PULL(").pull().add(")),") +} + +// Check created macro +func (macro *macro) check() { + if !macro.dw().maskCheck(0) { + macro.common() + // Debug message about this + fmt.Printf( + "\nCoreboot macros can't define the configuration for pad: %s\n", + macro.padID) + fmt.Printf("Use %s\n", macro.get()) + } +} + +// Gets base string of current macro +// return: string of macro +// error +func (macro *macro) generate(id string, dw0 uint32, dw1 uint32) string { + macro.dwcfg.reg[0] = dw0 + macro.dwcfg.reg[1] = dw1 + dw := ¯o.dwcfg + + macro.set("PAD_CFG") + if dw.getPadMode() == 0 { + // GPIO + switch dw.getGPIORxTxDisableStatus() { + case rxDisable: + // GPI + macro.addSuffixInput() + + case txDisable: + // GPO + macro.addSuffixOutput() + + case rxDisable | txDisable: + // NC + macro.set("PAD_NC").add("(").id().pull() + // Fix mask for RX Level/Edge Configuration (RXEVCFG) + // and Pad Reset Config (PADRSTCFG) + // There is no need to check these fields if the pad + // is in the NC state + macro.dw().maskResetFix().maskTrigFix() + + default: + // In case the rule isn't found, a common macro is used + // to create the pad configuration + return macro.common().get() + } + } else { + isEdge := dw.getRXLevelEdgeConfiguration() != 0 + isTxRxBufDis := dw.getGPIORxTxDisableStatus() != 0 + // e.g. PAD_CFG_NF(GPP_D23, NONE, DEEP, NF1) + macro.add("_NF") + if isEdge || isTxRxBufDis { + // e.g. PCHHOT# + // PAD_CFG_NF_BUF_TRIG(GPP_B23, 20K_PD, PLTRST, NF2, RX_DIS, OFF), + macro.add("_BUF_TRIG") + } + macro.add("(").id().pull().rstsrc().padfn() + if isEdge || isTxRxBufDis { + macro.bufdis().trig() + } + } + macro.add("),") + macro.check() + return macro.get() +} + +// GetMacro - get pad macro +// dw0 : DW0 config register value +// dw1 : DW1 config register value +// return: string of macro +// error +func GetMacro(id string, dw0 uint32, dw1 uint32) string { + macro := macro{padID : id} + return macro.generate(id, dw0, dw1) +}