summaryrefslogtreecommitdiff
path: root/util/spd_tools/intel/ddr4/gen_part_id.go
diff options
context:
space:
mode:
Diffstat (limited to 'util/spd_tools/intel/ddr4/gen_part_id.go')
-rw-r--r--util/spd_tools/intel/ddr4/gen_part_id.go215
1 files changed, 215 insertions, 0 deletions
diff --git a/util/spd_tools/intel/ddr4/gen_part_id.go b/util/spd_tools/intel/ddr4/gen_part_id.go
new file mode 100644
index 0000000000..f67b4a9434
--- /dev/null
+++ b/util/spd_tools/intel/ddr4/gen_part_id.go
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+package main
+
+import (
+ "encoding/csv"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+/*
+ * This program allocates DRAM strap IDs for different parts that are being used by the variant.
+ *
+ * It expects the following inputs:
+ * Pointer to SPD directory. This is the location where SPD files and SPD Manifest generated by
+ * gen_spd.go are placed.
+ * Pointer to Makefile directory. Makefile.inc generated by this program is placed in this
+ * location.
+ * Text file containing a list of memory parts names used by the board. Each line in the file
+ * is expected to have one memory part name.
+ */
+const (
+ SPDManifestFileName = "spd_manifest.generated.txt"
+ MakefileName = "Makefile.inc"
+ DRAMIdFileName = "dram_id.generated.txt"
+)
+
+func usage() {
+ fmt.Printf("\nUsage: %s <spd_dir> <makefile_dir> <mem_parts_used_file>\n\n", os.Args[0])
+ fmt.Printf(" where,\n")
+ fmt.Printf(" spd_dir = Directory path containing SPD files and manifest generated by gen_spd.go\n")
+ fmt.Printf(" makefile_dir = Directory path where generated Makefile.inc should be placed\n")
+ fmt.Printf(" mem_parts_used_file = File containing list of memory parts used by the board\n\n\n")
+}
+
+func checkArgs() error {
+
+ for _, arg := range os.Args[1:] {
+ if _, err := os.Stat(arg); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+/*
+ * Read input file that contains list of memory part names used by the variant (one on a line)
+ * and split into separate strings for each part name.
+ */
+func readParts(memPartsUsedFileName string) ([]string, error) {
+ lines, err := ioutil.ReadFile(memPartsUsedFileName)
+ if err != nil {
+ return nil, err
+ }
+ str := string(lines)
+ parts := strings.Split(str, "\n")
+
+ return parts, nil
+}
+
+/*
+ * Read SPD manifest file(CSV) generated by gen_spd program and generate two maps:
+ * 1. Part to SPD Map : This maps global memory part name to generated SPD file name
+ * 2. SPD to Index Map: This generates a map of deduplicated SPD file names to index assigned to
+ * that SPD. This function sets index for all SPDs to -1. This index gets
+ * updated as part of genPartIdInfo() depending upon the SPDs actually used
+ * by the variant.
+ */
+func readSPDManifest(SPDDirName string) (map[string]string, map[string]int, error) {
+ f, err := os.Open(filepath.Join(SPDDirName, SPDManifestFileName))
+ if err != nil {
+ return nil, nil, err
+ }
+ defer f.Close()
+ r := csv.NewReader(f)
+
+ partToSPDMap := make(map[string]string)
+ SPDToIndexMap := make(map[string]int)
+
+ for {
+ fields, err := r.Read()
+
+ if err == io.EOF {
+ break
+ }
+
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if len(fields) != 2 {
+ return nil, nil, fmt.Errorf("CSV file is incorrectly formatted")
+ }
+
+ partToSPDMap[fields[0]] = fields[1]
+ SPDToIndexMap[fields[1]] = -1
+ }
+
+ return partToSPDMap, SPDToIndexMap, nil
+}
+
+/* Print information about memory part used by variant and ID assigned to it. */
+func appendPartIdInfo(s *string, partName string, index int) {
+ *s += fmt.Sprintf("%-30s %d (%04b)\n", partName, index, int64(index))
+}
+
+type partIds struct {
+ SPDFileName string
+ memParts string
+}
+
+/*
+ * For each part used by variant, check if the SPD (as per the manifest) already has an ID
+ * assigned to it. If yes, then add the part name to the list of memory parts supported by the
+ * SPD entry. If not, then assign the next ID to the SPD file and add the part name to the
+ * list of memory parts supported by the SPD entry.
+ *
+ * Returns list of partIds that contains spdFileName and supported memory parts for each
+ * assigned ID.
+ */
+func genPartIdInfo(parts []string, partToSPDMap map[string]string, SPDToIndexMap map[string]int, makefileDirName string) ([]partIds, error) {
+ partIdList := []partIds{}
+ curId := 0
+ var s string
+
+ s += fmt.Sprintf("%-30s %s\n", "DRAM Part Name", "ID to assign")
+
+ for _, p := range parts {
+ if p == "" {
+ continue
+ }
+
+ SPDFileName,ok := partToSPDMap[p]
+ if !ok {
+ return nil, fmt.Errorf("Failed to find part ", p, " in SPD Manifest. Please add the part to global part list and regenerate SPD Manifest")
+ }
+
+ index := SPDToIndexMap[SPDFileName]
+ if index != -1 {
+ partIdList[index].memParts += ", " + p
+ appendPartIdInfo(&s, p, index)
+ continue
+ }
+
+ SPDToIndexMap[SPDFileName] = curId
+
+ appendPartIdInfo(&s, p, curId)
+ entry := partIds{SPDFileName: SPDFileName, memParts: p}
+ partIdList = append(partIdList, entry)
+
+ curId++
+ }
+
+ fmt.Printf("%s", s)
+ err := ioutil.WriteFile(filepath.Join(makefileDirName, DRAMIdFileName), []byte(s), 0644)
+
+ return partIdList, err
+}
+
+var generatedCodeLicense string = "## SPDX-License-Identifier: GPL-2.0-or-later"
+var autoGeneratedInfo string = "## This is an auto-generated file. Do not edit!!"
+
+/*
+ * This function generates Makefile.inc under the variant directory path and adds assigned SPDs
+ * to SPD_SOURCES.
+ */
+func genMakefile(partIdList []partIds, makefileDirName string) error {
+ var s string
+
+ s += fmt.Sprintf("%s\n%s\n\n", generatedCodeLicense, autoGeneratedInfo)
+ s += fmt.Sprintf("MEMORY_TYPE = ddr4\n\n")
+ s += fmt.Sprintf("SPD_SOURCES =\n")
+
+ for i := 0; i < len(partIdList); i++ {
+ s += fmt.Sprintf("SPD_SOURCES += %s ", partIdList[i].SPDFileName)
+ s += fmt.Sprintf(" # ID = %d(0b%04b) ", i, int64(i))
+ s += fmt.Sprintf(" Parts = %04s\n", partIdList[i].memParts)
+ }
+
+ return ioutil.WriteFile(filepath.Join(makefileDirName, MakefileName), []byte(s), 0644)
+}
+
+func main() {
+ if len(os.Args) != 4 {
+ usage()
+ log.Fatal("Incorrect number of arguments")
+ }
+
+ SPDDir, MakefileDir, MemPartsUsedFile := os.Args[1], os.Args[2], os.Args[3]
+
+ partToSPDMap, SPDToIndexMap, err := readSPDManifest(SPDDir)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ parts, err := readParts(MemPartsUsedFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ partIdList, err := genPartIdInfo(parts, partToSPDMap, SPDToIndexMap, MakefileDir)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := genMakefile(partIdList, MakefileDir); err != nil {
+ log.Fatal(err)
+ }
+}