util/spd_tools: Run go fmt on all .go files
[coreboot.git] / util / spd_tools / ddr4 / gen_part_id.go
blob110b9b23bc9731174775b5875f89e81a445e9aee
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 package main
5 import (
6 "encoding/csv"
7 "fmt"
8 "io"
9 "io/ioutil"
10 "log"
11 "os"
12 "path/filepath"
13 "strconv"
17 * This program allocates DRAM strap IDs for different parts that are being used by the variant.
19 * It expects the following inputs:
20 * Pointer to SPD directory. This is the location where SPD files and SPD Manifest generated by
21 * gen_spd.go are placed.
22 * Pointer to Makefile directory. Makefile.inc generated by this program is placed in this
23 * location.
24 * Text file containing a list of memory parts names used by the board. Each line in the file
25 * is expected to have one memory part name.
27 const (
28 SPDManifestFileName = "ddr4_spd_manifest.generated.txt"
29 MakefileName = "Makefile.inc"
30 DRAMIdFileName = "dram_id.generated.txt"
31 MaxMemoryId = 15
34 func usage() {
35 fmt.Printf("\nUsage: %s <spd_dir> <makefile_dir> <mem_parts_used_file>\n\n", os.Args[0])
36 fmt.Printf(" where,\n")
37 fmt.Printf(" spd_dir = Directory path containing SPD files and manifest generated by gen_spd.go\n")
38 fmt.Printf(" makefile_dir = Directory path where generated Makefile.inc should be placed\n")
39 fmt.Printf(" mem_parts_used_file = CSV file containing list of memory parts used by the board and optional fixed ids\n\n\n")
42 func checkArgs() error {
44 for _, arg := range os.Args[1:] {
45 if _, err := os.Stat(arg); err != nil {
46 return err
50 return nil
53 type usedPart struct {
54 partName string
55 index int
59 * Read input file CSV that contains list of memory part names used by the variant
60 * and an optional assigned id.
62 func readParts(memPartsUsedFileName string) ([]usedPart, error) {
64 f, err := os.Open(memPartsUsedFileName)
65 if err != nil {
66 return nil, err
68 defer f.Close()
69 r := csv.NewReader(f)
70 r.FieldsPerRecord = -1 // Allow variable length records
71 r.TrimLeadingSpace = true
72 r.Comment = '#'
74 parts := []usedPart{}
76 for {
77 fields, err := r.Read()
79 if err == io.EOF {
80 break
83 if err != nil {
84 return nil, err
87 if len(fields) == 1 {
88 parts = append(parts, usedPart{fields[0], -1})
89 } else if len(fields) == 2 {
90 assignedId, err := strconv.Atoi(fields[1])
91 if err != nil {
92 return nil, err
94 if assignedId > MaxMemoryId || assignedId < 0 {
95 return nil, fmt.Errorf("Out of bounds assigned id %d for part %s", assignedId, fields[0])
97 parts = append(parts, usedPart{fields[0], assignedId})
98 } else {
99 return nil, fmt.Errorf("mem_parts_used_file file is incorrectly formatted")
103 return parts, nil
107 * Read SPD manifest file(CSV) generated by gen_spd program and generate two maps:
108 * 1. Part to SPD Map : This maps global memory part name to generated SPD file name
109 * 2. SPD to Index Map: This generates a map of deduplicated SPD file names to index assigned to
110 * that SPD. This function sets index for all SPDs to -1. This index gets
111 * updated as part of genPartIdInfo() depending upon the SPDs actually used
112 * by the variant.
114 func readSPDManifest(SPDDirName string) (map[string]string, map[string]int, error) {
115 f, err := os.Open(filepath.Join(SPDDirName, SPDManifestFileName))
116 if err != nil {
117 return nil, nil, err
119 defer f.Close()
120 r := csv.NewReader(f)
122 partToSPDMap := make(map[string]string)
123 SPDToIndexMap := make(map[string]int)
125 for {
126 fields, err := r.Read()
128 if err == io.EOF {
129 break
132 if err != nil {
133 return nil, nil, err
136 if len(fields) != 2 {
137 return nil, nil, fmt.Errorf("CSV file is incorrectly formatted")
140 partToSPDMap[fields[0]] = fields[1]
141 SPDToIndexMap[fields[1]] = -1
144 return partToSPDMap, SPDToIndexMap, nil
147 /* Print information about memory part used by variant and ID assigned to it. */
148 func appendPartIdInfo(s *string, partName string, index int) {
149 *s += fmt.Sprintf("%-30s %d (%04b)\n", partName, index, int64(index))
152 type partIds struct {
153 SPDFileName string
154 memParts string
158 * For each part used by variant, check if the SPD (as per the manifest) already has an ID
159 * assigned to it. If yes, then add the part name to the list of memory parts supported by the
160 * SPD entry. If not, then assign the next ID to the SPD file and add the part name to the
161 * list of memory parts supported by the SPD entry.
163 * Returns list of partIds that contains spdFileName and supported memory parts for each
164 * assigned ID.
166 func genPartIdInfo(parts []usedPart, partToSPDMap map[string]string, SPDToIndexMap map[string]int, makefileDirName string) ([]partIds, error) {
168 partIdList := []partIds{}
169 var s string
171 // Assign parts with fixed ids first
172 for _, p := range parts {
174 if p.index == -1 {
175 continue
178 if p.partName == "" {
179 return nil, fmt.Errorf("Invalid part entry")
182 SPDFileName, ok := partToSPDMap[p.partName]
183 if !ok {
184 return nil, fmt.Errorf("Failed to find part ", p.partName, " in SPD Manifest. Please add the part to global part list and regenerate SPD Manifest")
187 // Extend partIdList with empty entries if needed
188 for i := len(partIdList) - 1; i < p.index; i++ {
189 partIdList = append(partIdList, partIds{})
192 if partIdList[p.index].SPDFileName != "" {
193 return nil, fmt.Errorf("Part ", p.partName, " is assigned to an already assigned ID ", p.index)
196 partIdList[p.index] = partIds{SPDFileName: SPDFileName, memParts: p.partName}
198 // SPDToIndexMap should point to first assigned index in the used part list
199 if SPDToIndexMap[SPDFileName] < 0 {
200 SPDToIndexMap[SPDFileName] = p.index
204 s += fmt.Sprintf("%-30s %s\n", "DRAM Part Name", "ID to assign")
206 // Assign parts with no fixed id
207 for _, p := range parts {
208 if p.partName == "" {
209 return nil, fmt.Errorf("Invalid part entry")
212 // Add assigned parts to dram id file in the order they appear
213 if p.index != -1 {
214 appendPartIdInfo(&s, p.partName, p.index)
215 continue
218 SPDFileName, ok := partToSPDMap[p.partName]
219 if !ok {
220 return nil, fmt.Errorf("Failed to find part ", p.partName, " in SPD Manifest. Please add the part to global part list and regenerate SPD Manifest")
223 index := SPDToIndexMap[SPDFileName]
224 if index != -1 {
225 partIdList[index].memParts += ", " + p.partName
226 appendPartIdInfo(&s, p.partName, index)
227 continue
230 // Find first empty index
231 for i, partId := range partIdList {
232 if partId.SPDFileName == "" {
233 index = i
234 break
238 // Append new entry
239 if index == -1 {
240 index = len(partIdList)
241 partIdList = append(partIdList, partIds{})
244 SPDToIndexMap[SPDFileName] = index
245 appendPartIdInfo(&s, p.partName, index)
246 partIdList[index] = partIds{SPDFileName: SPDFileName, memParts: p.partName}
249 fmt.Printf("%s", s)
250 err := ioutil.WriteFile(filepath.Join(makefileDirName, DRAMIdFileName), []byte(s), 0644)
252 return partIdList, err
255 var generatedCodeLicense string = "## SPDX-License-Identifier: GPL-2.0-or-later"
256 var autoGeneratedInfo string = "## This is an auto-generated file. Do not edit!!"
259 * This function generates Makefile.inc under the variant directory path and adds assigned SPDs
260 * to SPD_SOURCES.
262 func genMakefile(partIdList []partIds, makefileDirName string) error {
263 var s string
265 s += fmt.Sprintf("%s\n%s\n\n", generatedCodeLicense, autoGeneratedInfo)
266 s += fmt.Sprintf("SPD_SOURCES =\n")
268 for i := 0; i < len(partIdList); i++ {
269 if partIdList[i].SPDFileName == "" {
270 s += fmt.Sprintf("SPD_SOURCES += %s ", "ddr4-spd-empty.hex")
271 s += fmt.Sprintf(" # ID = %d(0b%04b)\n", i, int64(i))
272 } else {
273 s += fmt.Sprintf("SPD_SOURCES += %s ", partIdList[i].SPDFileName)
274 s += fmt.Sprintf(" # ID = %d(0b%04b) ", i, int64(i))
275 s += fmt.Sprintf(" Parts = %04s\n", partIdList[i].memParts)
279 return ioutil.WriteFile(filepath.Join(makefileDirName, MakefileName), []byte(s), 0644)
282 func main() {
283 if len(os.Args) != 4 {
284 usage()
285 log.Fatal("Incorrect number of arguments")
288 SPDDir, MakefileDir, MemPartsUsedFile := os.Args[1], os.Args[2], os.Args[3]
290 partToSPDMap, SPDToIndexMap, err := readSPDManifest(SPDDir)
291 if err != nil {
292 log.Fatal(err)
295 parts, err := readParts(MemPartsUsedFile)
296 if err != nil {
297 log.Fatal(err)
300 partIdList, err := genPartIdInfo(parts, partToSPDMap, SPDToIndexMap, MakefileDir)
301 if err != nil {
302 log.Fatal(err)
305 if err := genMakefile(partIdList, MakefileDir); err != nil {
306 log.Fatal(err)