1 /* SPDX-License-Identifier: GPL-2.0-or-later */
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
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.
28 SPDManifestFileName
= "ddr4_spd_manifest.generated.txt"
29 MakefileName
= "Makefile.inc"
30 DRAMIdFileName
= "dram_id.generated.txt"
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 {
53 type usedPart
struct {
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
)
70 r
.FieldsPerRecord
= -1 // Allow variable length records
71 r
.TrimLeadingSpace
= true
77 fields
, err
:= r
.Read()
88 parts
= append(parts
, usedPart
{fields
[0], -1})
89 } else if len(fields
) == 2 {
90 assignedId
, err
:= strconv
.Atoi(fields
[1])
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
})
99 return nil, fmt
.Errorf("mem_parts_used_file file is incorrectly formatted")
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
114 func readSPDManifest(SPDDirName
string) (map[string]string, map[string]int, error
) {
115 f
, err
:= os
.Open(filepath
.Join(SPDDirName
, SPDManifestFileName
))
120 r
:= csv
.NewReader(f
)
122 partToSPDMap
:= make(map[string]string)
123 SPDToIndexMap
:= make(map[string]int)
126 fields
, err
:= r
.Read()
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 {
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
166 func genPartIdInfo(parts
[]usedPart
, partToSPDMap
map[string]string, SPDToIndexMap
map[string]int, makefileDirName
string) ([]partIds
, error
) {
168 partIdList
:= []partIds
{}
171 // Assign parts with fixed ids first
172 for _
, p
:= range parts
{
178 if p
.partName
== "" {
179 return nil, fmt
.Errorf("Invalid part entry")
182 SPDFileName
, ok
:= partToSPDMap
[p
.partName
]
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
214 appendPartIdInfo(&s
, p
.partName
, p
.index
)
218 SPDFileName
, ok
:= partToSPDMap
[p
.partName
]
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
]
225 partIdList
[index
].memParts
+= ", " + p
.partName
226 appendPartIdInfo(&s
, p
.partName
, index
)
230 // Find first empty index
231 for i
, partId
:= range partIdList
{
232 if partId
.SPDFileName
== "" {
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
}
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
262 func genMakefile(partIdList
[]partIds
, makefileDirName
string) error
{
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
))
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)
283 if len(os
.Args
) != 4 {
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
)
295 parts
, err
:= readParts(MemPartsUsedFile
)
300 partIdList
, err
:= genPartIdInfo(parts
, partToSPDMap
, SPDToIndexMap
, MakefileDir
)
305 if err
:= genMakefile(partIdList
, MakefileDir
); err
!= nil {