blob: 6cc910272f81a8e46a5dbe686a88bed5f6b47977 [file] [log] [blame]
Reka Norman0e792742021-09-08 18:50:58 +10001/* SPDX-License-Identifier: GPL-2.0-or-later */
2package main
3
4import (
5 "encoding/json"
6 "fmt"
7 "io/ioutil"
8 "log"
9 "os"
10 "path/filepath"
11 "reflect"
12 "regexp"
Reka Norman8f690dd2021-09-20 12:19:16 +100013 "sort"
Reka Norman0e792742021-09-08 18:50:58 +100014 "strings"
15)
16
17/* ------------------------------------------------------------------------------------------ */
18/* Program-defined types */
19/* ------------------------------------------------------------------------------------------ */
20type memParts struct {
21 MemParts []memPart `json:"parts"`
22}
23
24type memPart struct {
25 Name string
26 Attribs interface{}
27 SPDId int
28}
29
30type memTech interface {
Reka Normane6a1ebe2021-11-08 11:18:42 +110031 /*
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.
34 */
Reka Norman0e792742021-09-08 18:50:58 +100035 getSetMap() map[int][]int
Reka Normane6a1ebe2021-11-08 11:18:42 +110036
37 /*
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.
41 */
Reka Norman0e792742021-09-08 18:50:58 +100042 addNewPart(string, interface{}) error
Reka Normane6a1ebe2021-11-08 11:18:42 +110043
44 /*
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.
50 */
Reka Norman0e792742021-09-08 18:50:58 +100051 getSPDAttribs(string, int) (interface{}, error)
Reka Normane6a1ebe2021-11-08 11:18:42 +110052
53 /*
54 * Returns the size of an SPD file for this memory technology.
55 */
Reka Norman0e792742021-09-08 18:50:58 +100056 getSPDLen() int
Reka Normane6a1ebe2021-11-08 11:18:42 +110057
58 /*
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.
61 */
Reka Norman0e792742021-09-08 18:50:58 +100062 getSPDByte(int, interface{}) byte
63}
64
65/* ------------------------------------------------------------------------------------------ */
66/* Constants */
67/* ------------------------------------------------------------------------------------------ */
68
69const (
70 PlatformTGL = iota
71 PlatformADL
72 PlatformJSL
73 PlatformPCO
Reka Norman0e792742021-09-08 18:50:58 +100074 PlatformCZN
75 PlatformMax
76)
77
78const (
79 SPDManifestFileName = "parts_spd_manifest.generated.txt"
80 PlatformManifestFileName = "platforms_manifest.generated.txt"
81)
82
83/* ------------------------------------------------------------------------------------------ */
84/* Global variables */
85/* ------------------------------------------------------------------------------------------ */
86
87var platformNames = map[int]string{
88 PlatformTGL: "TGL",
89 PlatformADL: "ADL",
90 PlatformJSL: "JSL",
91 PlatformPCO: "PCO",
Reka Norman0e792742021-09-08 18:50:58 +100092 PlatformCZN: "CZN",
93}
94
Reka Norman2c439ad2021-10-07 16:08:18 +110095var memTechMap = map[string]memTech{
96 "lp4x": lp4x{},
97 "ddr4": ddr4{},
98 "lp5": lp5{},
99}
100
Reka Norman0e792742021-09-08 18:50:58 +1000101/* ------------------------------------------------------------------------------------------ */
102/* Conversion Helper Functions */
103/* ------------------------------------------------------------------------------------------ */
104
105func convNsToPs(timeNs int) int {
106 return timeNs * 1000
107}
108
109func convMtbToPs(mtb int) int {
110 return mtb * 125
111}
112
113func convPsToMtb(timePs int) int {
114 return divRoundUp(timePs, 125)
115}
116
117func convPsToMtbByte(timePs int) byte {
118 return byte(convPsToMtb(timePs) & 0xff)
119}
120
121func convPsToFtbByte(timePs int) byte {
122 mtb := convPsToMtb(timePs)
123 ftb := timePs - convMtbToPs(mtb)
124
125 return byte(ftb)
126}
127
128func convNsToMtb(timeNs int) int {
129 return convPsToMtb(convNsToPs(timeNs))
130}
131
132func convNsToMtbByte(timeNs int) byte {
133 return convPsToMtbByte(convNsToPs(timeNs))
134}
135
136func convNsToFtbByte(timeNs int) byte {
137 return convPsToFtbByte(convNsToPs(timeNs))
138}
139
140func divRoundUp(dividend int, divisor int) int {
141 return (dividend + divisor - 1) / divisor
142}
143
144/* ------------------------------------------------------------------------------------------ */
145/* Functions */
146/* ------------------------------------------------------------------------------------------ */
147
148func findIndex(dedupedAttribs []interface{}, newSPDAttribs interface{}) int {
149 for i := 0; i < len(dedupedAttribs); i++ {
150 if reflect.DeepEqual(dedupedAttribs[i], newSPDAttribs) {
151 return i
152 }
153 }
154
155 return -1
156}
157
158func readMemParts(memPartsFilePath string) (memParts, error) {
159 var memParts memParts
160
161 dataBytes, err := ioutil.ReadFile(memPartsFilePath)
162 if err != nil {
163 return memParts, err
164 }
165
166 // Strip comments from json file
167 re := regexp.MustCompile(`(?m)^\s*//.*`)
168 dataBytes = re.ReplaceAll(dataBytes, []byte(""))
169
170 if err := json.Unmarshal(dataBytes, &memParts); err != nil {
171 return memParts, err
172 }
173
174 return memParts, nil
175}
176
177func createSPD(memAttribs interface{}, t memTech) string {
178 var s string
179
180 for i := 0; i < t.getSPDLen(); i++ {
181 var b byte = 0
182 if memAttribs != nil {
183 b = t.getSPDByte(i, memAttribs)
184 }
185
186 if (i+1)%16 == 0 {
187 s += fmt.Sprintf("%02X\n", b)
188 } else {
189 s += fmt.Sprintf("%02X ", b)
190 }
191 }
192
193 return s
194}
195
196func writeSPD(memAttribs interface{}, SPDId int, SPDSetDirName string, t memTech) {
197 s := createSPD(memAttribs, t)
198 SPDFileName := fmt.Sprintf("spd-%d.hex", SPDId)
199 ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDFileName), []byte(s), 0644)
200}
201
202func writeEmptySPD(SPDSetDirName string, t memTech) {
203 s := createSPD(nil, t)
204 SPDFileName := "spd-empty.hex"
205 ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDFileName), []byte(s), 0644)
206}
207
208func getGeneratedString() string {
209 return fmt.Sprintf("# Generated by:\n# %s\n\n", strings.Join(os.Args[0:], " "))
210}
211
212func writeSPDManifest(memPartArray []memPart, SPDSetDirName string) {
213 var s string
214
215 s += getGeneratedString()
216 for i := 0; i < len(memPartArray); i++ {
217 s += fmt.Sprintf("%s,spd-%d.hex\n", memPartArray[i].Name, memPartArray[i].SPDId)
218 }
219
220 ioutil.WriteFile(filepath.Join(SPDSetDirName, SPDManifestFileName), []byte(s), 0644)
221}
222
223func writeSetMap(setMap map[int][]int, SPDDirName string) {
224 var s string
225
226 s += getGeneratedString()
227
Reka Norman8f690dd2021-09-20 12:19:16 +1000228 var setNumbers []int
229 for k, _ := range setMap {
230 setNumbers = append(setNumbers, k)
231 }
232 sort.Ints(setNumbers)
233
234 for _, num := range setNumbers {
235 for _, item := range setMap[num] {
236 s += fmt.Sprintf("%s,set-%d\n", platformNames[item], num)
Reka Norman0e792742021-09-08 18:50:58 +1000237 }
238 }
239
240 ioutil.WriteFile(filepath.Join(SPDDirName, PlatformManifestFileName), []byte(s), 0644)
241}
242
243func usage() {
244 fmt.Printf("\nUsage: %s <mem_parts_list_json> <mem_technology>\n\n", os.Args[0])
245 fmt.Printf(" where,\n")
246 fmt.Printf(" mem_parts_list_json = JSON File containing list of memory parts and attributes\n")
Reka Norman2c439ad2021-10-07 16:08:18 +1100247 fmt.Printf(" mem_technology = Memory technology for which to generate SPDs\n")
248 fmt.Printf(" supported technologies: %v\n\n\n",
249 reflect.ValueOf(memTechMap).MapKeys())
Reka Norman0e792742021-09-08 18:50:58 +1000250}
251
252func main() {
253 if len(os.Args) != 3 {
254 usage()
255 log.Fatal("Incorrect number of arguments")
256 }
257
258 var t memTech
259 memPartsFilePath, memTechnology := os.Args[1], os.Args[2]
260
Reka Norman2c439ad2021-10-07 16:08:18 +1100261 t, ok := memTechMap[strings.ToLower(memTechnology)]
262 if !ok {
Reka Norman0e792742021-09-08 18:50:58 +1000263 log.Fatal("Unsupported memory technology ", memTechnology)
264 }
265
266 SPDDir, err := filepath.Abs(filepath.Dir(memPartsFilePath))
267 if err != nil {
268 log.Fatal(err)
269 }
270
271 memParts, err := readMemParts(memPartsFilePath)
272 if err != nil {
273 log.Fatal(err)
274 }
275
276 memPartExists := make(map[string]bool)
277 for i := 0; i < len(memParts.MemParts); i++ {
278 if memPartExists[memParts.MemParts[i].Name] {
279 log.Fatalf("%s is duplicated in mem_parts_list_json", memParts.MemParts[i].Name)
280 }
281 memPartExists[memParts.MemParts[i].Name] = true
282
283 if err := t.addNewPart(memParts.MemParts[i].Name, memParts.MemParts[i].Attribs); err != nil {
284 log.Fatal(err)
285 }
286 }
287
288 setMap := t.getSetMap()
289
290 for i := 0; i < len(setMap); i++ {
291 var dedupedAttribs []interface{}
292
293 for j := 0; j < len(memParts.MemParts); j++ {
294 spdAttribs, _ := t.getSPDAttribs(memParts.MemParts[j].Name, i)
295 index := -1
296
297 if index = findIndex(dedupedAttribs, spdAttribs); index == -1 {
298 dedupedAttribs = append(dedupedAttribs, spdAttribs)
299 index = len(dedupedAttribs) - 1
300 }
301
302 memParts.MemParts[j].SPDId = index + 1
303 }
304
305 SPDSetDir := fmt.Sprintf("%s/set-%d", SPDDir, i)
306 os.MkdirAll(SPDSetDir, os.ModePerm)
307
308 for j := 0; j < len(dedupedAttribs); j++ {
309 writeSPD(dedupedAttribs[j], j+1, SPDSetDir, t)
310 }
311
312 writeEmptySPD(SPDSetDir, t)
313
314 writeSPDManifest(memParts.MemParts, SPDSetDir)
315 }
316
317 writeSetMap(setMap, SPDDir)
318}