mb/ocp/tiogapass: Fix GPIOs
[coreboot2.git] / util / spd_tools / src / spd_gen / spd_gen.go
blob5c7ed79b1557265ef99a03d4e5cadf13bb9f95cc
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 package main
4 import (
5 "encoding/json"
6 "fmt"
7 "io/ioutil"
8 "log"
9 "os"
10 "path/filepath"
11 "reflect"
12 "regexp"
13 "sort"
14 "strings"
17 /* ------------------------------------------------------------------------------------------ */
18 /* Program-defined types */
19 /* ------------------------------------------------------------------------------------------ */
20 type memParts struct {
21 MemParts []memPart `json:"parts"`
24 type memPart struct {
25 Name string
26 Attribs interface{}
27 SPDId int
30 type memTech interface {
32 * Returns the set -> platform mapping for the memory technology. Platforms with the
33 * same SPD requirements should be grouped together into a single set.
35 getSetMap() map[int][]int
38 * Takes the name and attributes of a part, as read from the memory_parts JSON file.
39 * Validates the attributes, returning an error if any attribute has an invalid value.
40 * Stores the name and attributes internally to be used later.
42 addNewPart(string, interface{}) error
45 * Takes the name of a part and a set number.
46 * Retrieves the part's attributes which were stored by addNewPart(). Updates them by
47 * setting any optional attributes which weren't specified in the JSON file to their
48 * default values.
49 * Returns these updated attributes.
51 getSPDAttribs(string, int) (interface{}, error)
54 * Returns the size of an SPD file for this memory technology.
56 getSPDLen() int
59 * Takes an SPD byte index and the attributes of a part.
60 * Returns the value which that SPD byte should be set to based on the attributes.
62 getSPDByte(int, interface{}) byte
65 /* ------------------------------------------------------------------------------------------ */
66 /* Constants */
67 /* ------------------------------------------------------------------------------------------ */
69 const (
70 PlatformTGL = iota
71 PlatformADL
72 PlatformJSL
73 PlatformPCO
74 PlatformCZN
75 PlatformMDN
76 PlatformMTL
77 PlatformPHX
78 PlatformPTL
79 PlatformMax
82 const (
83 SPDManifestFileName = "parts_spd_manifest.generated.txt"
84 PlatformManifestFileName = "platforms_manifest.generated.txt"
87 /* ------------------------------------------------------------------------------------------ */
88 /* Global variables */
89 /* ------------------------------------------------------------------------------------------ */
91 var platformNames = map[int]string{
92 PlatformTGL: "TGL",
93 PlatformADL: "ADL",
94 PlatformJSL: "JSL",
95 PlatformPCO: "PCO",
96 PlatformCZN: "CZN",
97 PlatformMDN: "MDN",
98 PlatformMTL: "MTL",
99 PlatformPHX: "PHX",
100 PlatformPTL: "PTL",
103 var memTechMap = map[string]memTech{
104 "lp4x": lp4x{},
105 "ddr4": ddr4{},
106 "lp5": lp5{},
109 /* ------------------------------------------------------------------------------------------ */
110 /* Conversion Helper Functions */
111 /* ------------------------------------------------------------------------------------------ */
113 func convNsToPs(timeNs int) int {
114 return timeNs * 1000
117 func convMtbToPs(mtb int) int {
118 return mtb * 125
121 func convPsToMtb(timePs int) int {
122 return divRoundUp(timePs, 125)
125 func convPsToMtbByte(timePs int) byte {
126 return byte(convPsToMtb(timePs) & 0xff)
129 func convPsToFtbByte(timePs int) byte {
130 mtb := convPsToMtb(timePs)
131 ftb := timePs - convMtbToPs(mtb)
133 return byte(ftb)
136 func convNsToMtb(timeNs int) int {
137 return convPsToMtb(convNsToPs(timeNs))
140 func convNsToMtbByte(timeNs int) byte {
141 return convPsToMtbByte(convNsToPs(timeNs))
144 func convNsToFtbByte(timeNs int) byte {
145 return convPsToFtbByte(convNsToPs(timeNs))
148 func divRoundUp(dividend int, divisor int) int {
149 return (dividend + divisor - 1) / divisor
152 /* ------------------------------------------------------------------------------------------ */
153 /* Functions */
154 /* ------------------------------------------------------------------------------------------ */
156 func findIndex(dedupedAttribs []interface{}, newSPDAttribs interface{}) int {
157 for i := 0; i < len(dedupedAttribs); i++ {
158 if reflect.DeepEqual(dedupedAttribs[i], newSPDAttribs) {
159 return i
163 return -1
166 func readMemParts(memPartsFilePath string) (memParts, error) {
167 var memParts memParts
169 dataBytes, err := ioutil.ReadFile(memPartsFilePath)
170 if err != nil {
171 return memParts, err
174 // Strip comments from json file
175 re := regexp.MustCompile(`(?m)^\s*//.*`)
176 dataBytes = re.ReplaceAll(dataBytes, []byte(""))
178 if err := json.Unmarshal(dataBytes, &memParts); err != nil {
179 return memParts, err
182 return memParts, nil
185 func createSPD(memAttribs interface{}, t memTech) string {
186 var s string
188 for i := 0; i < t.getSPDLen(); i++ {
189 var b byte = 0
190 if memAttribs != nil {
191 b = t.getSPDByte(i, memAttribs)
194 if (i+1)%16 == 0 {
195 s += fmt.Sprintf("%02X\n", b)
196 } else {
197 s += fmt.Sprintf("%02X ", b)
201 return s
204 func writeSPD(memAttribs interface{}, SPDId int, SPDSetDirName string, t memTech) {
205 s := createSPD(memAttribs, t)
206 SPDFileName := fmt.Sprintf("spd-%d.hex", SPDId)
207 ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDFileName), []byte(s), 0644)
210 func writeEmptySPD(SPDSetDirName string, t memTech) {
211 s := createSPD(nil, t)
212 SPDFileName := "spd-empty.hex"
213 ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDFileName), []byte(s), 0644)
216 func getGeneratedString() string {
217 return fmt.Sprintf("# Generated by:\n# %s\n\n", strings.Join(os.Args[0:], " "))
220 func writeSPDManifest(memPartArray []memPart, SPDSetDirName string) {
221 var s string
223 s += getGeneratedString()
224 for i := 0; i < len(memPartArray); i++ {
225 s += fmt.Sprintf("%s,spd-%d.hex\n", memPartArray[i].Name, memPartArray[i].SPDId)
228 ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDManifestFileName), []byte(s), 0644)
231 func writeSetMap(setMap map[int][]int, SPDDirName string) {
232 var s string
234 s += getGeneratedString()
236 var setNumbers []int
237 for k, _ := range setMap {
238 setNumbers = append(setNumbers, k)
240 sort.Ints(setNumbers)
242 for _, num := range setNumbers {
243 for _, item := range setMap[num] {
244 s += fmt.Sprintf("%s,set-%d\n", platformNames[item], num)
248 ioutil.WriteFile(filepath.Join(SPDDirName, PlatformManifestFileName), []byte(s), 0644)
251 func usage() {
252 fmt.Printf("\nUsage: %s <mem_parts_list_json> <mem_technology>\n\n", os.Args[0])
253 fmt.Printf(" where,\n")
254 fmt.Printf(" mem_parts_list_json = JSON File containing list of memory parts and attributes\n")
255 fmt.Printf(" mem_technology = Memory technology for which to generate SPDs\n")
256 fmt.Printf(" supported technologies: %v\n\n\n",
257 reflect.ValueOf(memTechMap).MapKeys())
260 func main() {
261 if len(os.Args) != 3 {
262 usage()
263 log.Fatal("Incorrect number of arguments")
266 var t memTech
267 memPartsFilePath, memTechnology := os.Args[1], os.Args[2]
269 t, ok := memTechMap[strings.ToLower(memTechnology)]
270 if !ok {
271 log.Fatal("Unsupported memory technology ", memTechnology)
274 SPDDir, err := filepath.Abs(filepath.Dir(memPartsFilePath))
275 if err != nil {
276 log.Fatal(err)
279 memParts, err := readMemParts(memPartsFilePath)
280 if err != nil {
281 log.Fatal(err)
284 memPartExists := make(map[string]bool)
285 for i := 0; i < len(memParts.MemParts); i++ {
286 if memPartExists[memParts.MemParts[i].Name] {
287 log.Fatalf("%s is duplicated in mem_parts_list_json", memParts.MemParts[i].Name)
289 memPartExists[memParts.MemParts[i].Name] = true
291 if err := t.addNewPart(memParts.MemParts[i].Name, memParts.MemParts[i].Attribs); err != nil {
292 log.Fatal(err)
296 setMap := t.getSetMap()
298 for i := 0; i < len(setMap); i++ {
299 var dedupedAttribs []interface{}
301 for j := 0; j < len(memParts.MemParts); j++ {
302 spdAttribs, _ := t.getSPDAttribs(memParts.MemParts[j].Name, i)
303 index := -1
305 if index = findIndex(dedupedAttribs, spdAttribs); index == -1 {
306 dedupedAttribs = append(dedupedAttribs, spdAttribs)
307 index = len(dedupedAttribs) - 1
310 memParts.MemParts[j].SPDId = index + 1
313 SPDSetDir := fmt.Sprintf("%s/set-%d", SPDDir, i)
314 os.MkdirAll(SPDSetDir, os.ModePerm)
316 for j := 0; j < len(dedupedAttribs); j++ {
317 writeSPD(dedupedAttribs[j], j+1, SPDSetDir, t)
320 writeEmptySPD(SPDSetDir, t)
322 writeSPDManifest(memParts.MemParts, SPDSetDir)
325 writeSetMap(setMap, SPDDir)