Merge tag 'v2026.01-rc4' into next
Prepare v2026.01-rc4
This commit is contained in:
@@ -9,8 +9,9 @@ from collections import OrderedDict
|
||||
import glob
|
||||
try:
|
||||
import importlib.resources as importlib_resources
|
||||
except ImportError: # pragma: no cover
|
||||
# for Python 3.6
|
||||
# for Python 3.6, 3.7 and 3.8
|
||||
importlib_resources.files
|
||||
except (ImportError, AttributeError): # pragma: no cover
|
||||
import importlib_resources
|
||||
import os
|
||||
import re
|
||||
|
||||
100
tools/cv_bsp_generator/cv_bsp_generator.py
Executable file
100
tools/cv_bsp_generator/cv_bsp_generator.py
Executable file
@@ -0,0 +1,100 @@
|
||||
#! /usr/bin/env python
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
"""
|
||||
Bsp preloader header file generator
|
||||
|
||||
Process the handoff files from Quartus and convert them to headers
|
||||
usable by U-Boot. Includes the qts filter.sh capability to generate
|
||||
correct format for headers to be used for mainline Uboot on FPGA,
|
||||
namely Cyclone V & Arria V.
|
||||
|
||||
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||
|
||||
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||
"""
|
||||
import glob
|
||||
import optparse
|
||||
import os
|
||||
import shutil
|
||||
import emif
|
||||
import hps
|
||||
import iocsr
|
||||
import renderer
|
||||
import model
|
||||
import collections
|
||||
import sys
|
||||
|
||||
def printUsage():
|
||||
""" usage string """
|
||||
print ("Usage:\n\t%s\n" % ("sys.argv[0], --input_dir=<path to iswinfo directory> --output_dir=<path store output files>"))
|
||||
exit(1)
|
||||
|
||||
def verifyInputDir(dir):
|
||||
""" check if the input directory exists """
|
||||
if not os.path.isdir(dir):
|
||||
print ("There is no such directory '%s'!\n" % (dir))
|
||||
exit(1)
|
||||
|
||||
def verifyOutputDir(dir):
|
||||
""" check if the output directory exists """
|
||||
if not os.path.isdir(dir):
|
||||
os.makedirs(dir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Do some rudimentary command line processing until it is proven we need something
|
||||
# heavier, such as argparse (preferred, but 2.7+ only) or optparse
|
||||
|
||||
inputDir = '.'
|
||||
outputDir = '.'
|
||||
|
||||
progVersion = '%prog 1.0'
|
||||
progDesc = 'Generate board-specific files for the preloader'
|
||||
optParser = optparse.OptionParser(version=progVersion, description=progDesc)
|
||||
optParser.add_option('-i', '--input-dir', action='store', type='string', dest='inputDir', default='.',
|
||||
help='input-dir is usually the iswinfo directory')
|
||||
optParser.add_option('-o', '--output-dir', action='store', type='string', dest='outputDir', default='.',
|
||||
help='output-dir is usually the directory containing the preloader source')
|
||||
|
||||
(options, args) = optParser.parse_args()
|
||||
|
||||
for arg in args:
|
||||
print ("***WARNING: I don't understand '%s', so I am ignoring it\n" % (arg))
|
||||
|
||||
inputDir = options.inputDir
|
||||
verifyInputDir(inputDir)
|
||||
outputDir = options.outputDir
|
||||
|
||||
verifyOutputDir(outputDir)
|
||||
|
||||
emif = emif.EMIFGrokker(inputDir, outputDir, 'emif.xml')
|
||||
hps = hps.HPSGrokker(inputDir, outputDir)
|
||||
|
||||
pllConfigH = outputDir + "/" + "pll_config.h"
|
||||
print ("Generating file: " + pllConfigH)
|
||||
hpsModel = model.hps.create(inputDir + "/" + "hps.xml")
|
||||
emifModel = model.emif.create(inputDir +"/" + "emif.xml")
|
||||
|
||||
content=str(renderer.pll_config_h(hpsModel, emifModel))
|
||||
f = open(pllConfigH, "w")
|
||||
f.write(content)
|
||||
f.close()
|
||||
|
||||
# For all the .hiof files, make a iocsr_config.[h|c]
|
||||
# Only support single hiof file currently
|
||||
hiof_list = glob.glob(inputDir + os.sep + "*.hiof")
|
||||
if len(hiof_list) < 1:
|
||||
print ("***Error: No .hiof files found in input!")
|
||||
|
||||
elif len(hiof_list) > 1:
|
||||
print ("***Error: We don't handle more than one .hiof file yet")
|
||||
print (" Only the last .hiof file in the list will be converted")
|
||||
print (" hiof files found:")
|
||||
for f in hiof_list:
|
||||
print (" " + f)
|
||||
|
||||
for hiof_file_path in hiof_list:
|
||||
hiof_file = os.path.basename(hiof_file_path)
|
||||
# Avoid IOCSRGrokker having to parse hps.xml to determine
|
||||
# device family for output file name, instead we'll just
|
||||
# get it from HPSGrokker
|
||||
iocsr = iocsr.IOCSRGrokker(hps.getDeviceFamily(), inputDir, outputDir, hiof_file)
|
||||
243
tools/cv_bsp_generator/doc.py
Executable file
243
tools/cv_bsp_generator/doc.py
Executable file
@@ -0,0 +1,243 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
"""
|
||||
Generic document construction classes.
|
||||
|
||||
These classes are templates for creating documents that are not bound
|
||||
to a specific usage or data model.
|
||||
|
||||
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||
|
||||
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||
"""
|
||||
|
||||
class document(object):
|
||||
"""
|
||||
An abstract document class which does not dictate
|
||||
how a document should be constructed or manipulated.
|
||||
|
||||
It's sole purpose is to describe the entire document
|
||||
in smaller units
|
||||
"""
|
||||
|
||||
class entry(object):
|
||||
"""
|
||||
An entry is the smallest unit
|
||||
"""
|
||||
|
||||
def __init__(self, parent):
|
||||
""" entry initialization """
|
||||
if parent != None:
|
||||
parent.add(self)
|
||||
|
||||
class block(entry):
|
||||
"""
|
||||
A block is the smallest collection unit
|
||||
consists of entries and blocks.
|
||||
"""
|
||||
|
||||
def __init__(self, parent):
|
||||
""" block initialization """
|
||||
super(document.block, self).__init__(parent)
|
||||
self.entries = []
|
||||
|
||||
def add(self, entry):
|
||||
""" add entry to block """
|
||||
self.entries.append(entry)
|
||||
|
||||
|
||||
def __init__(self):
|
||||
""" document initialization """
|
||||
self.entries = []
|
||||
|
||||
def add(self, entry):
|
||||
""" add entry to entry list """
|
||||
self.entries.append(entry)
|
||||
|
||||
|
||||
class text(document):
|
||||
"""
|
||||
A simple text document implementation
|
||||
"""
|
||||
|
||||
class string(document.entry):
|
||||
"""
|
||||
The smallest unit of a text file is a string
|
||||
"""
|
||||
|
||||
def __init__(self, parent, stringString=None):
|
||||
""" string initialization """
|
||||
super(text.string, self).__init__(parent)
|
||||
self.stringString = stringString
|
||||
|
||||
def __str__(self):
|
||||
""" convert None to empty string """
|
||||
if (self.stringString != None):
|
||||
return self.stringString
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
class line(string):
|
||||
"""
|
||||
A line is a string with EOL character
|
||||
"""
|
||||
|
||||
def __str__(self):
|
||||
""" convert string with newline """
|
||||
return super(text.line, self).__str__() + "\n"
|
||||
|
||||
class block(document.block):
|
||||
"""
|
||||
A block of text which can be made up of
|
||||
strings or lines
|
||||
"""
|
||||
|
||||
def __str__(self):
|
||||
""" concatenate strings or lines """
|
||||
blockString = ""
|
||||
|
||||
for entry in self.entries:
|
||||
blockString += str(entry)
|
||||
|
||||
return blockString
|
||||
|
||||
|
||||
def __str__(self):
|
||||
""" concatenate strings or lines """
|
||||
textString = ""
|
||||
|
||||
for entry in self.entries:
|
||||
textString += str(entry)
|
||||
|
||||
return textString
|
||||
|
||||
|
||||
class c_source(text):
|
||||
"""
|
||||
A simple C header document implementation
|
||||
"""
|
||||
|
||||
class define(text.string):
|
||||
"""
|
||||
C header define
|
||||
"""
|
||||
|
||||
def __init__(self, parent, id, token=None):
|
||||
""" c header constructor initialization """
|
||||
super(c_source.define, self).__init__(parent, id)
|
||||
self.token = token
|
||||
|
||||
def __str__(self):
|
||||
""" c header to strings """
|
||||
defineString = "#define" + " " + super(c_source.define, self).__str__()
|
||||
|
||||
if self.token != None:
|
||||
defineString += " " + self.token
|
||||
|
||||
defineString += "\n"
|
||||
|
||||
return defineString
|
||||
|
||||
class comment_string(text.string):
|
||||
"""
|
||||
C header comment
|
||||
"""
|
||||
|
||||
def __str__(self):
|
||||
""" c comment """
|
||||
return "/*" + " " + super(c_source.comment_string, self).__str__() + " " + "*/"
|
||||
|
||||
class comment_line(comment_string):
|
||||
"""
|
||||
C header comment with newline
|
||||
"""
|
||||
|
||||
def __str__(self):
|
||||
""" c comment with newline """
|
||||
return super(c_source.comment_line, self).__str__() + "\n"
|
||||
|
||||
class block(text.block):
|
||||
"""
|
||||
A simple C block string implementation
|
||||
"""
|
||||
|
||||
def __init__(self, parent, prologue=None, epilogue=None):
|
||||
""" ifdef block string implementation """
|
||||
super(c_source.block, self).__init__(parent)
|
||||
|
||||
self.prologue = None
|
||||
self.epilogue = None
|
||||
|
||||
if prologue != None:
|
||||
self.prologue = prologue
|
||||
|
||||
if epilogue != None:
|
||||
self.epilogue = epilogue
|
||||
|
||||
def __str__(self):
|
||||
""" convert ifdef to string """
|
||||
blockString = ""
|
||||
|
||||
if self.prologue != None:
|
||||
blockString += str(self.prologue)
|
||||
|
||||
blockString += super(c_source.block, self).__str__()
|
||||
|
||||
if self.epilogue != None:
|
||||
blockString += str(self.epilogue)
|
||||
|
||||
return blockString
|
||||
|
||||
class comment_block(block):
|
||||
"""
|
||||
A simple C header block comment implementation
|
||||
"""
|
||||
|
||||
def __init__(self, parent, comments):
|
||||
""" block comment initialization """
|
||||
super(c_source.comment_block, self).__init__(parent, "/*\n", " */\n")
|
||||
for comment in comments.split("\n"):
|
||||
self.add(comment)
|
||||
|
||||
def add(self, entry):
|
||||
""" add line to block comment """
|
||||
super(c_source.block, self).add(" * " + entry + "\n")
|
||||
|
||||
class ifndef_block(block):
|
||||
"""
|
||||
A simple C header ifndef implementation
|
||||
"""
|
||||
|
||||
def __init__(self, parent, id):
|
||||
""" ifndef block initialization """
|
||||
prologue = text.line(None, "#ifndef" + " " + id)
|
||||
epilogue = text.block(None)
|
||||
text.string(epilogue, "#endif")
|
||||
text.string(epilogue, " ")
|
||||
c_source.comment_line(epilogue, id)
|
||||
super(c_source.ifndef_block, self).__init__(parent, prologue, epilogue)
|
||||
|
||||
|
||||
class generated_c_source(c_source):
|
||||
"""
|
||||
Caller to generate c format files using the helper classes
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
""" Generate c header file with license, copyright, comment,
|
||||
ifdef block
|
||||
"""
|
||||
super(generated_c_source, self).__init__()
|
||||
|
||||
self.entries.append(c_source.comment_line(None, "SPDX-License-Identifier: BSD-3-Clause"))
|
||||
self.entries.append(c_source.comment_block(None, "Copyright (C) 2022 Intel Corporation <www.intel.com>"))
|
||||
self.entries.append(c_source.comment_block(None, "Altera SoCFPGA Clock and PLL configuration"))
|
||||
self.entries.append(text.line(None))
|
||||
|
||||
self.body = c_source.ifndef_block(None, filename)
|
||||
self.body.add(c_source.define(None, filename))
|
||||
self.entries.append(self.body)
|
||||
|
||||
def add(self, entry):
|
||||
""" add content to be written into c header file """
|
||||
self.body.add(entry)
|
||||
424
tools/cv_bsp_generator/emif.py
Executable file
424
tools/cv_bsp_generator/emif.py
Executable file
File diff suppressed because one or more lines are too long
571
tools/cv_bsp_generator/hps.py
Executable file
571
tools/cv_bsp_generator/hps.py
Executable file
@@ -0,0 +1,571 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
"""
|
||||
Pinmux header file generator
|
||||
|
||||
Process the hps.xml from Quartus and convert them to headers
|
||||
usable by U-Boot.
|
||||
|
||||
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||
|
||||
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import streamer
|
||||
import xmlgrok
|
||||
import xml.dom.minidom
|
||||
import collections
|
||||
import io
|
||||
from io import StringIO
|
||||
|
||||
class CompatStringIO(io.StringIO):
|
||||
def write(self, s):
|
||||
if hasattr(s, 'decode'):
|
||||
# Use unicode for python2 to keep compatible
|
||||
return int(super(CompatStringIO, self).write(s.decode('utf-8')))
|
||||
else:
|
||||
return super(CompatStringIO, self).write(s)
|
||||
def getvalue(self):
|
||||
return str(super(CompatStringIO, self).getvalue())
|
||||
|
||||
class HPSGrokker(object):
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
TEMPLATE_DIR = os.path.dirname(SCRIPT_DIR) + '/src'
|
||||
|
||||
MAKEFILE_FILENAME = "Makefile"
|
||||
makefileTemplate = ""
|
||||
RESET_CONFIG_H_FILENAME = "reset_config.h"
|
||||
resetConfigHTemplate = ""
|
||||
|
||||
# If no device family is specified, assume Cyclone V.
|
||||
derivedDeviceFamily = "cyclone5"
|
||||
|
||||
# Assume FPGA DMA 0-7 are not in use by default
|
||||
# Note: there appears to be a weird mismatch between sopcinfo
|
||||
# value vs hps.xml value of DMA_Enable of string_list hw.tcl
|
||||
# type, where sopcinfo uses comma as separator e.g.
|
||||
# "No,No,No,..." while hps.xml uses space as separator.
|
||||
dmaEnable = "No No No No No No No No"
|
||||
|
||||
def __init__(self, inputDir, outputDir, hpsFileName='hps.xml'):
|
||||
""" HPSGrokker initialization """
|
||||
self.inputDir = inputDir
|
||||
self.outputDir = outputDir
|
||||
self.hpsInFileName = inputDir + os.sep + hpsFileName
|
||||
self.dom = xml.dom.minidom.parse(self.hpsInFileName)
|
||||
self.peripheralStream = None
|
||||
self.pinmuxConfigBuffer = None
|
||||
self.pinmuxHeaderBuffer = None
|
||||
self.pinmuxHeaderFile = None
|
||||
self.pinmuxArraySize = 0
|
||||
self.config_hps_ = "CFG_HPS_"
|
||||
self.clockStream = None
|
||||
self.pinmux_regs = self.get_default_pinmux_regs()
|
||||
self.pinmux_configs = self.get_default_pinmux_configs()
|
||||
self.pinmux_config_h = None
|
||||
|
||||
self.createFilesFromHPS()
|
||||
|
||||
def get_default_pinmux_regs(self):
|
||||
""" Set default pinmux values """
|
||||
p = collections.OrderedDict()
|
||||
|
||||
p['EMACIO0'] = 0
|
||||
p['EMACIO1'] = 0
|
||||
p['EMACIO2'] = 0
|
||||
p['EMACIO3'] = 0
|
||||
p['EMACIO4'] = 0
|
||||
p['EMACIO5'] = 0
|
||||
p['EMACIO6'] = 0
|
||||
p['EMACIO7'] = 0
|
||||
p['EMACIO8'] = 0
|
||||
p['EMACIO9'] = 0
|
||||
p['EMACIO10'] = 0
|
||||
p['EMACIO11'] = 0
|
||||
p['EMACIO12'] = 0
|
||||
p['EMACIO13'] = 0
|
||||
p['EMACIO14'] = 0
|
||||
p['EMACIO15'] = 0
|
||||
p['EMACIO16'] = 0
|
||||
p['EMACIO17'] = 0
|
||||
p['EMACIO18'] = 0
|
||||
p['EMACIO19'] = 0
|
||||
p['FLASHIO0'] = 0
|
||||
p['FLASHIO1'] = 0
|
||||
p['FLASHIO2'] = 0
|
||||
p['FLASHIO3'] = 0
|
||||
p['FLASHIO4'] = 0
|
||||
p['FLASHIO5'] = 0
|
||||
p['FLASHIO6'] = 0
|
||||
p['FLASHIO7'] = 0
|
||||
p['FLASHIO8'] = 0
|
||||
p['FLASHIO9'] = 0
|
||||
p['FLASHIO10'] = 0
|
||||
p['FLASHIO11'] = 0
|
||||
p['GENERALIO0'] = 0
|
||||
p['GENERALIO1'] = 0
|
||||
p['GENERALIO2'] = 0
|
||||
p['GENERALIO3'] = 0
|
||||
p['GENERALIO4'] = 0
|
||||
p['GENERALIO5'] = 0
|
||||
p['GENERALIO6'] = 0
|
||||
p['GENERALIO7'] = 0
|
||||
p['GENERALIO8'] = 0
|
||||
p['GENERALIO9'] = 0
|
||||
p['GENERALIO10'] = 0
|
||||
p['GENERALIO11'] = 0
|
||||
p['GENERALIO12'] = 0
|
||||
p['GENERALIO13'] = 0
|
||||
p['GENERALIO14'] = 0
|
||||
p['GENERALIO15'] = 0
|
||||
p['GENERALIO16'] = 0
|
||||
p['GENERALIO17'] = 0
|
||||
p['GENERALIO18'] = 0
|
||||
p['GENERALIO19'] = 0
|
||||
p['GENERALIO20'] = 0
|
||||
p['GENERALIO21'] = 0
|
||||
p['GENERALIO22'] = 0
|
||||
p['GENERALIO23'] = 0
|
||||
p['GENERALIO24'] = 0
|
||||
p['GENERALIO25'] = 0
|
||||
p['GENERALIO26'] = 0
|
||||
p['GENERALIO27'] = 0
|
||||
p['GENERALIO28'] = 0
|
||||
p['GENERALIO29'] = 0
|
||||
p['GENERALIO30'] = 0
|
||||
p['GENERALIO31'] = 0
|
||||
p['MIXED1IO0'] = 0
|
||||
p['MIXED1IO1'] = 0
|
||||
p['MIXED1IO2'] = 0
|
||||
p['MIXED1IO3'] = 0
|
||||
p['MIXED1IO4'] = 0
|
||||
p['MIXED1IO5'] = 0
|
||||
p['MIXED1IO6'] = 0
|
||||
p['MIXED1IO7'] = 0
|
||||
p['MIXED1IO8'] = 0
|
||||
p['MIXED1IO9'] = 0
|
||||
p['MIXED1IO10'] = 0
|
||||
p['MIXED1IO11'] = 0
|
||||
p['MIXED1IO12'] = 0
|
||||
p['MIXED1IO13'] = 0
|
||||
p['MIXED1IO14'] = 0
|
||||
p['MIXED1IO15'] = 0
|
||||
p['MIXED1IO16'] = 0
|
||||
p['MIXED1IO17'] = 0
|
||||
p['MIXED1IO18'] = 0
|
||||
p['MIXED1IO19'] = 0
|
||||
p['MIXED1IO20'] = 0
|
||||
p['MIXED1IO21'] = 0
|
||||
p['MIXED2IO0'] = 0
|
||||
p['MIXED2IO1'] = 0
|
||||
p['MIXED2IO2'] = 0
|
||||
p['MIXED2IO3'] = 0
|
||||
p['MIXED2IO4'] = 0
|
||||
p['MIXED2IO5'] = 0
|
||||
p['MIXED2IO6'] = 0
|
||||
p['MIXED2IO7'] = 0
|
||||
p['GPLINMUX48'] = 0
|
||||
p['GPLINMUX49'] = 0
|
||||
p['GPLINMUX50'] = 0
|
||||
p['GPLINMUX51'] = 0
|
||||
p['GPLINMUX52'] = 0
|
||||
p['GPLINMUX53'] = 0
|
||||
p['GPLINMUX54'] = 0
|
||||
p['GPLINMUX55'] = 0
|
||||
p['GPLINMUX56'] = 0
|
||||
p['GPLINMUX57'] = 0
|
||||
p['GPLINMUX58'] = 0
|
||||
p['GPLINMUX59'] = 0
|
||||
p['GPLINMUX60'] = 0
|
||||
p['GPLINMUX61'] = 0
|
||||
p['GPLINMUX62'] = 0
|
||||
p['GPLINMUX63'] = 0
|
||||
p['GPLINMUX64'] = 0
|
||||
p['GPLINMUX65'] = 0
|
||||
p['GPLINMUX66'] = 0
|
||||
p['GPLINMUX67'] = 0
|
||||
p['GPLINMUX68'] = 0
|
||||
p['GPLINMUX69'] = 0
|
||||
p['GPLINMUX70'] = 0
|
||||
p['GPLMUX0'] = 1
|
||||
p['GPLMUX1'] = 1
|
||||
p['GPLMUX2'] = 1
|
||||
p['GPLMUX3'] = 1
|
||||
p['GPLMUX4'] = 1
|
||||
p['GPLMUX5'] = 1
|
||||
p['GPLMUX6'] = 1
|
||||
p['GPLMUX7'] = 1
|
||||
p['GPLMUX8'] = 1
|
||||
p['GPLMUX9'] = 1
|
||||
p['GPLMUX10'] = 1
|
||||
p['GPLMUX11'] = 1
|
||||
p['GPLMUX12'] = 1
|
||||
p['GPLMUX13'] = 1
|
||||
p['GPLMUX14'] = 1
|
||||
p['GPLMUX15'] = 1
|
||||
p['GPLMUX16'] = 1
|
||||
p['GPLMUX17'] = 1
|
||||
p['GPLMUX18'] = 1
|
||||
p['GPLMUX19'] = 1
|
||||
p['GPLMUX20'] = 1
|
||||
p['GPLMUX21'] = 1
|
||||
p['GPLMUX22'] = 1
|
||||
p['GPLMUX23'] = 1
|
||||
p['GPLMUX24'] = 1
|
||||
p['GPLMUX25'] = 1
|
||||
p['GPLMUX26'] = 1
|
||||
p['GPLMUX27'] = 1
|
||||
p['GPLMUX28'] = 1
|
||||
p['GPLMUX29'] = 1
|
||||
p['GPLMUX30'] = 1
|
||||
p['GPLMUX31'] = 1
|
||||
p['GPLMUX32'] = 1
|
||||
p['GPLMUX33'] = 1
|
||||
p['GPLMUX34'] = 1
|
||||
p['GPLMUX35'] = 1
|
||||
p['GPLMUX36'] = 1
|
||||
p['GPLMUX37'] = 1
|
||||
p['GPLMUX38'] = 1
|
||||
p['GPLMUX39'] = 1
|
||||
p['GPLMUX40'] = 1
|
||||
p['GPLMUX41'] = 1
|
||||
p['GPLMUX42'] = 1
|
||||
p['GPLMUX43'] = 1
|
||||
p['GPLMUX44'] = 1
|
||||
p['GPLMUX45'] = 1
|
||||
p['GPLMUX46'] = 1
|
||||
p['GPLMUX47'] = 1
|
||||
p['GPLMUX48'] = 1
|
||||
p['GPLMUX49'] = 1
|
||||
p['GPLMUX50'] = 1
|
||||
p['GPLMUX51'] = 1
|
||||
p['GPLMUX52'] = 1
|
||||
p['GPLMUX53'] = 1
|
||||
p['GPLMUX54'] = 1
|
||||
p['GPLMUX55'] = 1
|
||||
p['GPLMUX56'] = 1
|
||||
p['GPLMUX57'] = 1
|
||||
p['GPLMUX58'] = 1
|
||||
p['GPLMUX59'] = 1
|
||||
p['GPLMUX60'] = 1
|
||||
p['GPLMUX61'] = 1
|
||||
p['GPLMUX62'] = 1
|
||||
p['GPLMUX63'] = 1
|
||||
p['GPLMUX64'] = 1
|
||||
p['GPLMUX65'] = 1
|
||||
p['GPLMUX66'] = 1
|
||||
p['GPLMUX67'] = 1
|
||||
p['GPLMUX68'] = 1
|
||||
p['GPLMUX69'] = 1
|
||||
p['GPLMUX70'] = 1
|
||||
p['NANDUSEFPGA'] = 0
|
||||
p['UART0USEFPGA'] = 0
|
||||
p['RGMII1USEFPGA'] = 0
|
||||
p['SPIS0USEFPGA'] = 0
|
||||
p['CAN0USEFPGA'] = 0
|
||||
p['I2C0USEFPGA'] = 0
|
||||
p['SDMMCUSEFPGA'] = 0
|
||||
p['QSPIUSEFPGA'] = 0
|
||||
p['SPIS1USEFPGA'] = 0
|
||||
p['RGMII0USEFPGA'] = 0
|
||||
p['UART1USEFPGA'] = 0
|
||||
p['CAN1USEFPGA'] = 0
|
||||
p['USB1USEFPGA'] = 0
|
||||
p['I2C3USEFPGA'] = 0
|
||||
p['I2C2USEFPGA'] = 0
|
||||
p['I2C1USEFPGA'] = 0
|
||||
p['SPIM1USEFPGA'] = 0
|
||||
p['USB0USEFPGA'] = 0
|
||||
p['SPIM0USEFPGA'] = 0
|
||||
|
||||
return p
|
||||
|
||||
|
||||
def get_default_pinmux_configs(self):
|
||||
""" Get default pinmux values """
|
||||
p = collections.OrderedDict()
|
||||
|
||||
p['rgmii0'] = { 'name': 'CFG_HPS_EMAC0', 'used': 0 }
|
||||
p['rgmii1'] = { 'name': 'CFG_HPS_EMAC1', 'used': 0 }
|
||||
p['usb0'] = { 'name': 'CFG_HPS_USB0', 'used': 0 }
|
||||
p['usb1'] = { 'name': 'CFG_HPS_USB1', 'used': 0 }
|
||||
p['nand'] = { 'name': 'CFG_HPS_NAND', 'used': 0 }
|
||||
p['sdmmc'] = { 'name': 'CFG_HPS_SDMMC', 'used': 0 }
|
||||
p['CFG_HPS_SDMMC_BUSWIDTH'] = { 'name': 'CFG_HPS_SDMMC_BUSWIDTH', 'used': 0 }
|
||||
p['qspi'] = { 'name': 'CFG_HPS_QSPI', 'used': 0 }
|
||||
p['CFG_HPS_QSPI_CS3'] = { 'name': 'CFG_HPS_QSPI_CS3', 'used': 0 }
|
||||
p['CFG_HPS_QSPI_CS2'] = { 'name': 'CFG_HPS_QSPI_CS2', 'used': 0 }
|
||||
p['CFG_HPS_QSPI_CS1'] = { 'name': 'CFG_HPS_QSPI_CS1', 'used': 0 }
|
||||
p['CFG_HPS_QSPI_CS0'] = { 'name': 'CFG_HPS_QSPI_CS0', 'used': 0 }
|
||||
p['uart0'] = { 'name': 'CFG_HPS_UART0', 'used': 0 }
|
||||
p['CFG_HPS_UART0_TX'] = { 'name': 'CFG_HPS_UART0_TX', 'used': 0 }
|
||||
p['CFG_HPS_UART0_CTS'] = { 'name': 'CFG_HPS_UART0_CTS', 'used': 0 }
|
||||
p['CFG_HPS_UART0_RTS'] = { 'name': 'CFG_HPS_UART0_RTS', 'used': 0 }
|
||||
p['CFG_HPS_UART0_RX'] = { 'name': 'CFG_HPS_UART0_RX', 'used': 0 }
|
||||
p['uart1'] = { 'name': 'CFG_HPS_UART1', 'used': 0 }
|
||||
p['CFG_HPS_UART1_TX'] = { 'name': 'CFG_HPS_UART1_TX', 'used': 0 }
|
||||
p['CFG_HPS_UART1_CTS'] = { 'name': 'CFG_HPS_UART1_CTS', 'used': 0 }
|
||||
p['CFG_HPS_UART1_RTS'] = { 'name': 'CFG_HPS_UART1_RTS', 'used': 0 }
|
||||
p['CFG_HPS_UART1_RX'] = { 'name': 'CFG_HPS_UART1_RX', 'used': 0 }
|
||||
p['trace'] = { 'name': 'CFG_HPS_TRACE', 'used': 0 }
|
||||
p['i2c0'] = { 'name': 'CFG_HPS_I2C0', 'used': 0 }
|
||||
p['i2c1'] = { 'name': 'CFG_HPS_I2C1', 'used': 0 }
|
||||
p['i2c2'] = { 'name': 'CFG_HPS_I2C2', 'used': 0 }
|
||||
p['i2c3'] = { 'name': 'CFG_HPS_I2C3', 'used': 0 }
|
||||
p['spim0'] = { 'name': 'CFG_HPS_SPIM0', 'used': 0 }
|
||||
p['spim1'] = { 'name': 'CFG_HPS_SPIM1', 'used': 0 }
|
||||
p['spis0'] = { 'name': 'CFG_HPS_SPIS0', 'used': 0 }
|
||||
p['spis1'] = { 'name': 'CFG_HPS_SPIS1', 'used': 0 }
|
||||
p['can0'] = { 'name': 'CFG_HPS_CAN0', 'used': 0 }
|
||||
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||
|
||||
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||
|
||||
return p
|
||||
|
||||
def updateTemplate(self, name, value):
|
||||
""" Update Makefile & reset_config.h """
|
||||
pattern = "${" + name + "}"
|
||||
self.makefileTemplate = self.makefileTemplate.replace(pattern, value)
|
||||
self.resetConfigHTemplate = self.resetConfigHTemplate.replace(pattern, value)
|
||||
|
||||
def romanToInteger(self, roman):
|
||||
"""
|
||||
Convert roman numerals to integer
|
||||
Since we only support I,V,X, the
|
||||
supported range is 1-39
|
||||
"""
|
||||
table = { 'I':1 , 'V':5, 'X':10 }
|
||||
|
||||
literals = list(roman)
|
||||
|
||||
value = 0
|
||||
i = 0
|
||||
|
||||
while(i < (len(literals) - 1)):
|
||||
current = table[literals[i]]
|
||||
next = table[literals[i + 1]]
|
||||
if (current < next):
|
||||
value += (next - current)
|
||||
i += 2
|
||||
else:
|
||||
value += current
|
||||
i += 1
|
||||
|
||||
if (i < (len(literals))):
|
||||
value += table[literals[i]]
|
||||
|
||||
return value
|
||||
|
||||
def getDeviceFamily(self):
|
||||
""" Get device family """
|
||||
return self.derivedDeviceFamily
|
||||
|
||||
def getDeviceFamilyName(self, deviceFamily):
|
||||
""" Get device family name """
|
||||
p = re.compile('^(\w+)\s+(\w+)$')
|
||||
m = p.match(deviceFamily)
|
||||
return m.group(1).lower() + str(self.romanToInteger(m.group(2)))
|
||||
|
||||
def handleHPSSystemNode(self, systemNode):
|
||||
""" handleHPSPeripheralsNode(peripheralsNode)
|
||||
peripheralsNode is a peripherals element node in hps.xml
|
||||
peripheralsNode is a list of peripheralNodes
|
||||
"""
|
||||
configNode = xmlgrok.firstElementChild(systemNode)
|
||||
while configNode != None:
|
||||
|
||||
name = configNode.getAttribute('name')
|
||||
value = configNode.getAttribute('value')
|
||||
|
||||
self.updateTemplate(name, value)
|
||||
|
||||
if name == "DEVICE_FAMILY":
|
||||
self.derivedDeviceFamily = self.getDeviceFamilyName(value)
|
||||
|
||||
if name == "DMA_Enable":
|
||||
self.dmaEnable = value
|
||||
|
||||
configNode = xmlgrok.nextElementSibling(configNode)
|
||||
|
||||
def handleHPSPeripheralNode(self, peripheralNode):
|
||||
""" This node of the hps.xml may contain a name, value pair
|
||||
We need to:
|
||||
emit a #define for the peripheral for is 'used' state
|
||||
emit a #define for that pair, if it is marked 'used'
|
||||
"""
|
||||
peripheralNode = xmlgrok.firstElementChild(peripheralNode)
|
||||
|
||||
while peripheralNode != None:
|
||||
if peripheralNode.hasAttribute('name') and peripheralNode.hasAttribute('used'):
|
||||
newLine = "\n"
|
||||
name = peripheralNode.getAttribute('name')
|
||||
used = peripheralNode.getAttribute('used')
|
||||
|
||||
if used == 'true' or used == True:
|
||||
used = 1
|
||||
elif used == 'false' or used == False:
|
||||
used = 0
|
||||
|
||||
configs = collections.OrderedDict()
|
||||
|
||||
configNode = xmlgrok.firstElementChild(peripheralNode)
|
||||
while configNode != None:
|
||||
config_define_name = configNode.getAttribute('name')
|
||||
config_define_value = configNode.getAttribute('value')
|
||||
configs[config_define_name] = config_define_value
|
||||
configNode = xmlgrok.nextElementSibling(configNode)
|
||||
if configNode == None:
|
||||
newLine += newLine
|
||||
self.pinmuxConfigBuffer.write("#define " + str(config_define_name) + ' ' + '(' + str(config_define_value) + ')' + newLine)
|
||||
|
||||
entry = self.pinmux_configs[name]
|
||||
define_name = entry['name']
|
||||
|
||||
if (len(configs) > 0):
|
||||
self.pinmux_configs[name] = { 'name': define_name, 'used': used, 'configs': configs }
|
||||
else:
|
||||
self.pinmux_configs[name] = { 'name': define_name, 'used': used }
|
||||
|
||||
# skip the parent peripheral node
|
||||
# since only need to define child config node(s)
|
||||
peripheralNode = xmlgrok.nextElementSibling(peripheralNode)
|
||||
|
||||
def handleHPSPinmuxNode(self, pinmuxNode):
|
||||
""" For a pinmuxNode, we may emit a #define for the name, value pair
|
||||
"""
|
||||
if pinmuxNode.hasAttribute('name') and pinmuxNode.hasAttribute('value'):
|
||||
self.pinmuxArraySize += 1
|
||||
name = pinmuxNode.getAttribute('name')
|
||||
value = pinmuxNode.getAttribute('value')
|
||||
|
||||
def handleHPSPinmuxesNode(self, pinmuxesNode):
|
||||
""" PinmuxesNode is a list of pinmuxNodes
|
||||
"""
|
||||
self.pinmuxHeaderBuffer.write(str("const u8 sys_mgr_init_table[] = {\n"))
|
||||
|
||||
pinmuxNode = xmlgrok.firstElementChild(pinmuxesNode)
|
||||
while pinmuxNode != None:
|
||||
if pinmuxNode.hasAttribute('name') and pinmuxNode.hasAttribute('value'):
|
||||
self.pinmuxArraySize += 1
|
||||
name = pinmuxNode.getAttribute('name')
|
||||
value = pinmuxNode.getAttribute('value')
|
||||
self.pinmux_regs[name] = value
|
||||
pinmuxNode = xmlgrok.nextElementSibling(pinmuxNode)
|
||||
|
||||
reg_count = 0
|
||||
pinmux_regs_count = len(self.pinmux_regs)
|
||||
for reg, value in self.pinmux_regs.items():
|
||||
reg_count += 1
|
||||
if reg_count < pinmux_regs_count:
|
||||
self.pinmuxHeaderBuffer.write(str("\t" + str(value) + ', /* ' + reg + ' */\n' ))
|
||||
else:
|
||||
self.pinmuxHeaderBuffer.write(str("\t" + str(value) + ' /* ' + reg + ' */\n' ))
|
||||
|
||||
# Write the close of the pin MUX array in the header
|
||||
self.pinmuxHeaderBuffer.write(str("};" ))
|
||||
|
||||
def handleHPSClockNode(self, clockNode):
|
||||
""" A clockNode may emit a #define for the name, frequency pair
|
||||
"""
|
||||
if clockNode.hasAttribute('name') and clockNode.hasAttribute('frequency'):
|
||||
name = clockNode.getAttribute('name')
|
||||
frequency = clockNode.getAttribute('frequency')
|
||||
self.clockStream.write("#define " + name + ' ' + '(' + frequency + ')' + '\n')
|
||||
|
||||
def handleHPSClocksNode(self, clocksNode):
|
||||
""" A list of clockNodes is call clocksNode
|
||||
"""
|
||||
self.clockStream = streamer.Streamer(self.outputDir + os.sep + clocksNode.nodeName + '.h', 'w')
|
||||
self.clockStream.open()
|
||||
clockNode = xmlgrok.firstElementChild(clocksNode)
|
||||
while clockNode != None:
|
||||
self.handleHPSClockNode(clockNode)
|
||||
clockNode = xmlgrok.nextElementSibling(clockNode)
|
||||
|
||||
self.clockStream.close()
|
||||
|
||||
def handleHpsFpgaInterfaces(self, node):
|
||||
""" Update FPGA Interface registers """
|
||||
node = xmlgrok.firstElementChild(node)
|
||||
|
||||
while node != None:
|
||||
name = node.getAttribute('name')
|
||||
used = node.getAttribute('used')
|
||||
|
||||
if used == 'true':
|
||||
reset = 0
|
||||
else:
|
||||
reset = 1
|
||||
|
||||
if name == 'F2H_AXI_SLAVE':
|
||||
self.updateTemplate("DERIVED_RESET_ASSERT_FPGA2HPS", str(reset))
|
||||
elif name == 'H2F_AXI_MASTER':
|
||||
self.updateTemplate("DERIVED_RESET_ASSERT_HPS2FPGA", str(reset))
|
||||
elif name == 'LWH2F_AXI_MASTER':
|
||||
self.updateTemplate("DERIVED_RESET_ASSERT_LWHPS2FPGA", str(reset))
|
||||
|
||||
node = xmlgrok.nextElementSibling(node)
|
||||
|
||||
def createFilesFromHPS(self):
|
||||
""" Parse xml and create pinmux_config.h """
|
||||
# Unfortunately we can't determine the file name before
|
||||
# parsing the XML, so let's build up the source file
|
||||
# content in string buffer
|
||||
self.pinmuxHeaderBuffer = CompatStringIO()
|
||||
self.pinmuxConfigBuffer = CompatStringIO()
|
||||
|
||||
# Get a list of all nodes with the hps element name
|
||||
hpsNodeList = self.dom.getElementsByTagName('hps')
|
||||
if len(hpsNodeList) > 1:
|
||||
print ("*** WARNING:" + "Multiple hps Elements found in %s!" % self.hpsInFileName)
|
||||
# For each of the hps element nodes, go through the child list
|
||||
# Note that currently there is only one hps Element
|
||||
# but this code will handle more than one hps node
|
||||
# In the future, multiple hps nodes may need additional code
|
||||
# to combine settings from the multiple hps Elements
|
||||
for hpsNode in hpsNodeList:
|
||||
# Currently, there are only 3 children of the hps Element:
|
||||
# peripherals, pin_muxes, and clocks
|
||||
# but this is left open-ended for future additions to the
|
||||
# specification for the hps.xml
|
||||
childNode = xmlgrok.firstElementChild(hpsNode)
|
||||
while childNode != None:
|
||||
if childNode.nodeName == 'pin_muxes':
|
||||
self.handleHPSPinmuxesNode(childNode)
|
||||
elif childNode.nodeName == 'system':
|
||||
self.handleHPSSystemNode(childNode)
|
||||
elif childNode.nodeName == 'fpga_interfaces':
|
||||
self.handleHpsFpgaInterfaces(childNode)
|
||||
elif childNode.nodeName == 'peripherals':
|
||||
self.handleHPSPeripheralNode(childNode)
|
||||
else:
|
||||
print ("***Error:Found unexpected HPS child node:%s" % childNode.nodeName)
|
||||
childNode = xmlgrok.nextElementSibling(childNode)
|
||||
|
||||
self.updateTemplate("DERIVED_DEVICE_FAMILY", self.derivedDeviceFamily)
|
||||
|
||||
# Now we write string buffers into files once we know the device family
|
||||
self.pinmux_config_h = 'pinmux_config.h'
|
||||
self.pinmux_config_src = 'pinmux_config_' + self.derivedDeviceFamily + '.c'
|
||||
|
||||
# Create pinmux_config .h
|
||||
headerDefine = "__SOCFPGA_PINMUX_CONFIG_H__"
|
||||
self.pinmuxHeaderFile = streamer.Streamer(self.outputDir + os.sep + self.pinmux_config_h, 'w')
|
||||
self.pinmuxHeaderFile.open()
|
||||
self.pinmuxHeaderFile.writeLicenseHeader()
|
||||
self.pinmuxHeaderFile.write('/*\n * Altera SoCFPGA PinMux configuration\n */\n\n')
|
||||
|
||||
self.pinmuxHeaderFile.write("#ifndef " + headerDefine + "\n")
|
||||
self.pinmuxHeaderFile.write("#define " + headerDefine + "\n\n")
|
||||
self.pinmuxHeaderFile.write(self.pinmuxHeaderBuffer.getvalue())
|
||||
self.pinmuxHeaderFile.write("\n#endif /* " + headerDefine + " */\n")
|
||||
self.pinmuxHeaderFile.close()
|
||||
|
||||
# Free up string buffers
|
||||
self.pinmuxHeaderBuffer.close()
|
||||
self.pinmuxConfigBuffer.close()
|
||||
203
tools/cv_bsp_generator/iocsr.py
Executable file
203
tools/cv_bsp_generator/iocsr.py
Executable file
@@ -0,0 +1,203 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
"""
|
||||
IOCSR header file generator
|
||||
|
||||
Process the hiof file from Quartus and generate iocsr header
|
||||
usable by U-Boot.
|
||||
|
||||
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||
|
||||
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||
"""
|
||||
import os
|
||||
import struct
|
||||
import streamer
|
||||
|
||||
class IOCSRGrokker(object):
|
||||
""" Decode the .hiof file and produce some C source code
|
||||
"""
|
||||
IOCSR_ROOT_FILENAME = 'iocsr_config'
|
||||
IOCSR_SENTINEL = '__SOCFPGA_IOCSR_CONFIG_H__'
|
||||
IOCSR_FILE_EXTENSION_MAX_LEN = 6
|
||||
PTAG_HPS_IOCSR_INFO = 39
|
||||
PTAG_HPS_IOCSR = 40
|
||||
PTAG_DEVICE_NAME = 2
|
||||
PTAG_TERMINATION = 8
|
||||
|
||||
def __init__(self, deviceFamily, inputDir, outputDir, hiofSrcFileName):
|
||||
""" IOCSRGrokker Initialization """
|
||||
self.deviceFamily = deviceFamily
|
||||
self.inputDir = inputDir
|
||||
self.outputDir = outputDir
|
||||
self.hiofInFileName = hiofSrcFileName
|
||||
self.iocsrFileName = self.IOCSR_ROOT_FILENAME
|
||||
self.headerOut = None
|
||||
self.sourceOut = None
|
||||
self.createFilesFromHIOF()
|
||||
|
||||
@staticmethod
|
||||
def byteArrayToStr(bytes):
|
||||
""" Convert a list of bytes into a string
|
||||
"""
|
||||
# We don't like nulls
|
||||
bytes = bytes.replace('\x00', '')
|
||||
s = ''
|
||||
for b in bytes:
|
||||
s += b
|
||||
return s
|
||||
|
||||
@staticmethod
|
||||
def getLengthData(bytes):
|
||||
"""
|
||||
@param: bytes is a chunk of bytes that we need to decode
|
||||
There will be a ptag that we may care about.
|
||||
If we care about it, we will get the length of the chunk
|
||||
that the ptag cares about.
|
||||
@rtype: a pair, length of chunk and the chunk itself
|
||||
@return: length of the ptag chunk we care about
|
||||
@return: data chunk that ptag indicates we need to decode
|
||||
"""
|
||||
blockSize = len(bytes)
|
||||
i = 0
|
||||
bitlength = 0
|
||||
length = 0
|
||||
data = []
|
||||
|
||||
while i < blockSize:
|
||||
byte = struct.unpack('B', bytes[i:i+1])[0]
|
||||
i += 1
|
||||
|
||||
if byte == 1:
|
||||
bitlength = struct.unpack('I', bytes[i:i+4])[0]
|
||||
i += 4
|
||||
elif byte == 2:
|
||||
length = struct.unpack('I', bytes[i:i+4])[0]
|
||||
i += 4
|
||||
|
||||
elif byte == 5:
|
||||
j = 0
|
||||
while i < blockSize:
|
||||
data.append(struct.unpack('I', bytes[i:i+4])[0])
|
||||
i += 4
|
||||
j += 1
|
||||
|
||||
else:
|
||||
i += 4
|
||||
|
||||
return (bitlength, data)
|
||||
|
||||
|
||||
def verifyRead(self, tagWeRead, tagWeExpected):
|
||||
""" verify the hiof value with tag expected """
|
||||
if tagWeRead != tagWeExpected:
|
||||
print ("***Error: Expected ptag of %02d, but got %02d" % (tagWeExpected, tagWeRead))
|
||||
|
||||
def createFilesFromHIOF(self):
|
||||
""" read the hiof file to create iocsr_config.h """
|
||||
self.hiofStream = streamer.Streamer(self.inputDir + os.sep + self.hiofInFileName, 'rb')
|
||||
self.iocsrHeaderStream = streamer.Streamer(self.outputDir + os.sep + self.iocsrFileName + '.h', 'w')
|
||||
self.hiofStream.open()
|
||||
self.iocsrHeaderStream.open()
|
||||
self.iocsrHeaderStream.writeLicenseHeader()
|
||||
self.iocsrHeaderStream.write('/*\n * Altera SoCFPGA IOCSR configuration\n */\n\n')
|
||||
ret = self.iocsrHeaderStream.writeSentinelStart(IOCSRGrokker.IOCSR_SENTINEL)
|
||||
if ret == -1:
|
||||
print("Empty header written. Exiting.")
|
||||
|
||||
# Read the file extension (typically .hiof)
|
||||
# and the file version
|
||||
self.fileExtension = self.hiofStream.readBytesAsString(IOCSRGrokker.IOCSR_FILE_EXTENSION_MAX_LEN)
|
||||
self.fileVersion = self.hiofStream.readUnsignedInt()
|
||||
|
||||
# Now read the ptags
|
||||
# Device name is first
|
||||
self.programmerTag = self.hiofStream.readUnsignedShort()
|
||||
self.verifyRead(self.programmerTag, self.PTAG_DEVICE_NAME)
|
||||
self.deviceNameLength = self.hiofStream.readUnsignedInt()
|
||||
self.deviceName = self.hiofStream.readBytesAsString(self.deviceNameLength)
|
||||
|
||||
# Basic information of the HIOF files
|
||||
# This is not used by the preloader generator, but we read it and ignore the
|
||||
# contents.
|
||||
programmerTag = self.hiofStream.readUnsignedShort()
|
||||
self.verifyRead(programmerTag, self.PTAG_HPS_IOCSR_INFO)
|
||||
basicHPSIOCSRInfoLength = self.hiofStream.readUnsignedInt()
|
||||
self.hiofStream.read(basicHPSIOCSRInfoLength)
|
||||
|
||||
# Actual content of IOCSR information
|
||||
self.programmerTag1 = self.hiofStream.readUnsignedShort()
|
||||
self.verifyRead(self.programmerTag1, self.PTAG_HPS_IOCSR)
|
||||
self.HPSIOCSRLength1 = self.hiofStream.readUnsignedInt()
|
||||
self.HPSIOCSRBytes1 = self.hiofStream.read(self.HPSIOCSRLength1)
|
||||
self.HPSIOCSRDataLength1, self.HPSIOCSRData1 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes1)
|
||||
|
||||
# Actual content of IOCSR information
|
||||
self.programmerTag2 = self.hiofStream.readUnsignedShort()
|
||||
self.verifyRead(self.programmerTag2, self.PTAG_HPS_IOCSR)
|
||||
self.HPSIOCSRLength2 = self.hiofStream.readUnsignedInt()
|
||||
self.HPSIOCSRBytes2 = self.hiofStream.read(self.HPSIOCSRLength2)
|
||||
self.HPSIOCSRDataLength2, self.HPSIOCSRData2 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes2)
|
||||
|
||||
# Actual content of IOCSR information
|
||||
self.programmerTag3 = self.hiofStream.readUnsignedShort()
|
||||
self.verifyRead(self.programmerTag3, self.PTAG_HPS_IOCSR)
|
||||
self.HPSIOCSRLength3 = self.hiofStream.readUnsignedInt()
|
||||
self.HPSIOCSRBytes3 = self.hiofStream.read(self.HPSIOCSRLength3)
|
||||
self.HPSIOCSRDataLength3, self.HPSIOCSRData3 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes3)
|
||||
|
||||
# Actual content of IOCSR information
|
||||
self.programmerTag4 = self.hiofStream.readUnsignedShort()
|
||||
self.verifyRead(self.programmerTag4, self.PTAG_HPS_IOCSR)
|
||||
self.HPSIOCSRLength4 = self.hiofStream.readUnsignedInt()
|
||||
self.HPSIOCSRBytes4 = self.hiofStream.read(self.HPSIOCSRLength4)
|
||||
self.HPSIOCSRDataLength4, self.HPSIOCSRData4 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes4)
|
||||
|
||||
# Now we should see the end of the hiof input
|
||||
programmerTag = self.hiofStream.readUnsignedShort()
|
||||
if 8 != programmerTag:
|
||||
print ("I didn't find the end of the .hiof file when I expected to!")
|
||||
|
||||
self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN0_LENGTH\t' +\
|
||||
str(self.HPSIOCSRDataLength1) + '\n')
|
||||
self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN1_LENGTH\t' +\
|
||||
str(self.HPSIOCSRDataLength2) + '\n')
|
||||
self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN2_LENGTH\t' +\
|
||||
str(self.HPSIOCSRDataLength3) + '\n')
|
||||
self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN3_LENGTH\t' +\
|
||||
str(self.HPSIOCSRDataLength4) + '\n')
|
||||
|
||||
self.iocsrHeaderStream.write("\n")
|
||||
|
||||
self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain0_table[] = {\n')
|
||||
for value in self.HPSIOCSRData1:
|
||||
hv = '0x%08X' % (value)
|
||||
self.iocsrHeaderStream.write('\t' + hv + ',\n')
|
||||
self.iocsrHeaderStream.write('};\n')
|
||||
self.iocsrHeaderStream.write('\n')
|
||||
|
||||
self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain1_table[] = {\n')
|
||||
for value in self.HPSIOCSRData2:
|
||||
hv = '0x%08X' % (value)
|
||||
self.iocsrHeaderStream.write('\t' + hv + ',\n')
|
||||
self.iocsrHeaderStream.write('};\n')
|
||||
self.iocsrHeaderStream.write('\n')
|
||||
|
||||
self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain2_table[] = {\n')
|
||||
for value in self.HPSIOCSRData3:
|
||||
hv = '0x%08X' % (value)
|
||||
self.iocsrHeaderStream.write('\t' + hv + ',\n')
|
||||
self.iocsrHeaderStream.write('};\n')
|
||||
self.iocsrHeaderStream.write('\n')
|
||||
|
||||
self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain3_table[] = {\n')
|
||||
for value in self.HPSIOCSRData4:
|
||||
hv = '0x%08X' % (value)
|
||||
self.iocsrHeaderStream.write('\t' + hv + ',\n')
|
||||
self.iocsrHeaderStream.write('};\n')
|
||||
self.iocsrHeaderStream.write('\n\n')
|
||||
|
||||
ret = self.iocsrHeaderStream.writeSentinelEnd(IOCSRGrokker.IOCSR_SENTINEL)
|
||||
if ret == -1:
|
||||
print("Empty header written. Exiting.")
|
||||
|
||||
self.iocsrHeaderStream.close()
|
||||
114
tools/cv_bsp_generator/model.py
Executable file
114
tools/cv_bsp_generator/model.py
Executable file
@@ -0,0 +1,114 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
"""
|
||||
Data models for XML files required for generating a preloader.
|
||||
|
||||
These classes encapsulate the complexities of XML DOM in order to
|
||||
make retrieving data from XML files easier and more reliable.
|
||||
By shielding data model deserialization from data consumers,
|
||||
it'd be easier to switch to other formats such as JSON if required.
|
||||
|
||||
There are some assumptions about how these XML files are structured
|
||||
such as the hierarchy of elements and ordering of attributes, these
|
||||
are relatively safe assumptions for as long as the XML files are
|
||||
always generated by HPS megawizard (isw.tcl) and are not hand-edited.
|
||||
|
||||
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||
|
||||
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||
"""
|
||||
import xml.dom.minidom
|
||||
|
||||
def getSingletonElementByTagName(parent, tagName):
|
||||
"""
|
||||
Find tag by name and ensure that there is exactly one match
|
||||
"""
|
||||
nodes = parent.getElementsByTagName(tagName)
|
||||
|
||||
if len(nodes) == 0:
|
||||
raise Exception("Can't find element: " + tagName)
|
||||
elif len(nodes) > 1:
|
||||
raise Exception("Unexpected multiple matches for singleton element: " + tagName)
|
||||
else:
|
||||
return nodes[0]
|
||||
|
||||
class hps(object):
|
||||
"""
|
||||
Data model for hps.xml
|
||||
"""
|
||||
@staticmethod
|
||||
def create(file):
|
||||
""" hps model """
|
||||
return hps(file)
|
||||
|
||||
def __init__(self, file):
|
||||
""" hps model initialization """
|
||||
self.dom = xml.dom.minidom.parse(file)
|
||||
|
||||
try:
|
||||
# Look for <hps> node
|
||||
self.hpsNode = getSingletonElementByTagName(self.dom, "hps")
|
||||
# Look for <hps><system> node
|
||||
self.hpsSystemNode = getSingletonElementByTagName(self.hpsNode, "system")
|
||||
except Exception:
|
||||
raise Exception("Can't initialize from file: " + file)
|
||||
|
||||
def getSystemConfig(self, param):
|
||||
""" parse system configuration tag """
|
||||
hpsSystemConfigNode = None
|
||||
|
||||
# Look for <hps><system><config ...> nodes
|
||||
for node in self.hpsSystemNode.getElementsByTagName("config"):
|
||||
# assume name is the first attribute as in <config name="..." ...>
|
||||
nameAttrNode = node.attributes.item(0)
|
||||
if nameAttrNode.nodeName == "name" and nameAttrNode.nodeValue == param:
|
||||
# assume value is the second attribute as in <config name="..." value="...">
|
||||
valueAttrNode = node.attributes.item(1)
|
||||
if valueAttrNode.nodeName == "value":
|
||||
hpsSystemConfigNode = valueAttrNode
|
||||
break
|
||||
|
||||
if hpsSystemConfigNode == None:
|
||||
raise ValueError("Can't find <hps><system><config> node: " + param)
|
||||
|
||||
return hpsSystemConfigNode.nodeValue
|
||||
|
||||
class emif(object):
|
||||
"""
|
||||
Data model for emif.xml.
|
||||
"""
|
||||
@staticmethod
|
||||
def create(file):
|
||||
""" emif model """
|
||||
return emif(file)
|
||||
|
||||
def __init__(self, file):
|
||||
""" emif model initialization """
|
||||
self.dom = xml.dom.minidom.parse(file)
|
||||
|
||||
try:
|
||||
# Look for <emif> node
|
||||
self.emifNode = getSingletonElementByTagName(self.dom, "emif")
|
||||
# Look for <emif><pll> node
|
||||
self.emifPllNode = getSingletonElementByTagName(self.emifNode, "pll")
|
||||
except Exception:
|
||||
raise Exception("Can't initialize from file: " + file)
|
||||
|
||||
def getPllDefine(self, param):
|
||||
""" parse pll define tag """
|
||||
emifPllDefineNode = None
|
||||
|
||||
# Look for <emif><pll><define ...> nodes
|
||||
for node in self.emifPllNode.getElementsByTagName("define"):
|
||||
nameAttrNode = node.attributes.item(0)
|
||||
# assume name is the first attribute as in <define name="..." ...>
|
||||
if nameAttrNode.nodeName == "name" and nameAttrNode.nodeValue == param:
|
||||
# assume value is the second attribute as in <config name="..." value="...">
|
||||
valueAttrNode = node.attributes.item(1)
|
||||
if valueAttrNode.nodeName == "value":
|
||||
emifPllDefineNode = valueAttrNode
|
||||
break
|
||||
|
||||
if emifPllDefineNode == None:
|
||||
raise Exception("Can't find EMIF PLL define node: " + param)
|
||||
|
||||
return emifPllDefineNode.nodeValue
|
||||
196
tools/cv_bsp_generator/renderer.py
Executable file
196
tools/cv_bsp_generator/renderer.py
Executable file
@@ -0,0 +1,196 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
"""
|
||||
Document renderer class for preloader source files
|
||||
|
||||
Each document renderer takes care of a full construction of
|
||||
a specific file format using the required data model.
|
||||
|
||||
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||
|
||||
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||
"""
|
||||
import collections
|
||||
import doc
|
||||
|
||||
class pll_config_h:
|
||||
"""
|
||||
pll_config.h renderer.
|
||||
"""
|
||||
|
||||
def __init__(self, hpsModel, emifModel):
|
||||
""" renderer initialization """
|
||||
self.hpsModel = hpsModel
|
||||
self.emifModel = emifModel
|
||||
self.doc = doc.generated_c_source("__SOCFPGA_PLL_CONFIG_H__")
|
||||
|
||||
def createContent(self):
|
||||
""" add the content based on settings parsed. eventually it will be
|
||||
written to pll_config.h file
|
||||
"""
|
||||
doc.c_source.line(self.doc)
|
||||
id = "CFG_HPS_DBCTRL_STAYOSC1"
|
||||
valueString = self.hpsModel.getSystemConfig("dbctrl_stayosc1")
|
||||
# Unfortunately hps.xml never tells us the data type of values
|
||||
# attributes. Here we workaround this type of problem, often
|
||||
# this is case-by-case, i.e. having to know which parameter that
|
||||
# we're dealing with, hence this ugly parameter-specific
|
||||
# if-statement needs here to workaround the data type inconsistency
|
||||
if valueString.lower() == "true":
|
||||
value = "1"
|
||||
else:
|
||||
value = "0"
|
||||
doc.c_source.define(self.doc, id, value )
|
||||
doc.c_source.line(self.doc)
|
||||
self.addMainPllSettings()
|
||||
doc.c_source.line(self.doc)
|
||||
self.addPeriphPllSettings()
|
||||
doc.c_source.line(self.doc)
|
||||
self.addSdramPllSettings()
|
||||
doc.c_source.line(self.doc)
|
||||
self.addClockFreq()
|
||||
doc.c_source.line(self.doc)
|
||||
self.addAlteraSettings()
|
||||
doc.c_source.line(self.doc)
|
||||
|
||||
def addMainPllSettings(self):
|
||||
""" add pll settings to the file """
|
||||
paramMap = collections.OrderedDict()
|
||||
paramMap["VCO_DENOM"] = "main_pll_n"
|
||||
paramMap["VCO_NUMER"] = "main_pll_m"
|
||||
|
||||
for key in paramMap.keys():
|
||||
id = "CFG_HPS_MAINPLLGRP_" + key
|
||||
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||
doc.c_source.define(self.doc, id, value )
|
||||
|
||||
# main_pll_c0, main_pll_c1, main_pll_c2 are fixed counters,
|
||||
doc.c_source.define(self.doc, "CFG_HPS_MAINPLLGRP_MPUCLK_CNT", "0")
|
||||
doc.c_source.define(self.doc, "CFG_HPS_MAINPLLGRP_MAINCLK_CNT", "0")
|
||||
doc.c_source.define(self.doc, "CFG_HPS_MAINPLLGRP_DBGATCLK_CNT", "0")
|
||||
|
||||
paramMap = collections.OrderedDict()
|
||||
|
||||
paramMap["MAINQSPICLK_CNT"] = "main_pll_c3"
|
||||
paramMap["MAINNANDSDMMCCLK_CNT"] = "main_pll_c4"
|
||||
paramMap["CFGS2FUSER0CLK_CNT"] = "main_pll_c5"
|
||||
paramMap["MAINDIV_L3MPCLK"] = "l3_mp_clk_div"
|
||||
paramMap["MAINDIV_L3SPCLK"] = "l3_sp_clk_div"
|
||||
paramMap["MAINDIV_L4MPCLK"] = "l4_mp_clk_div"
|
||||
paramMap["MAINDIV_L4SPCLK"] = "l4_sp_clk_div"
|
||||
paramMap["DBGDIV_DBGATCLK"] = "dbg_at_clk_div"
|
||||
paramMap["DBGDIV_DBGCLK"] = "dbg_clk_div"
|
||||
paramMap["TRACEDIV_TRACECLK"] = "dbg_trace_clk_div"
|
||||
paramMap["L4SRC_L4MP"] = "l4_mp_clk_source"
|
||||
paramMap["L4SRC_L4SP"] = "l4_sp_clk_source"
|
||||
|
||||
for key in paramMap.keys():
|
||||
id = "CFG_HPS_MAINPLLGRP_" + key
|
||||
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||
doc.c_source.define(self.doc, id, value )
|
||||
|
||||
def addPeriphPllSettings(self):
|
||||
""" add peripheral pll settings to the file """
|
||||
paramMap = collections.OrderedDict()
|
||||
paramMap["VCO_DENOM"] = "periph_pll_n"
|
||||
paramMap["VCO_NUMER"] = "periph_pll_m"
|
||||
paramMap["VCO_PSRC"] = "periph_pll_source"
|
||||
paramMap["EMAC0CLK_CNT"] = "periph_pll_c0"
|
||||
paramMap["EMAC1CLK_CNT"] = "periph_pll_c1"
|
||||
paramMap["PERQSPICLK_CNT"] = "periph_pll_c2"
|
||||
paramMap["PERNANDSDMMCCLK_CNT"] = "periph_pll_c3"
|
||||
paramMap["PERBASECLK_CNT"] = "periph_pll_c4"
|
||||
paramMap["S2FUSER1CLK_CNT"] = "periph_pll_c5"
|
||||
paramMap["DIV_USBCLK"] = "usb_mp_clk_div"
|
||||
paramMap["DIV_SPIMCLK"] = "spi_m_clk_div"
|
||||
paramMap["DIV_CAN0CLK"] = "can0_clk_div"
|
||||
paramMap["DIV_CAN1CLK"] = "can1_clk_div"
|
||||
paramMap["GPIODIV_GPIODBCLK"] = "gpio_db_clk_div"
|
||||
paramMap["SRC_SDMMC"] = "sdmmc_clk_source"
|
||||
paramMap["SRC_NAND"] = "nand_clk_source"
|
||||
paramMap["SRC_QSPI"] = "qspi_clk_source"
|
||||
|
||||
for key in paramMap.keys():
|
||||
id = "CFG_HPS_PERPLLGRP_" + key
|
||||
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||
doc.c_source.define(self.doc, id, value )
|
||||
|
||||
def addSdramPllSettings(self):
|
||||
""" add sdram pll settings to the file """
|
||||
value = self.emifModel.getPllDefine("PLL_MEM_CLK_DIV")
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_VCO_DENOM", value )
|
||||
value = self.emifModel.getPllDefine("PLL_MEM_CLK_MULT")
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_VCO_NUMER", value )
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_VCO_SSRC", "0")
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQSCLK_CNT", "1")
|
||||
value = self.emifModel.getPllDefine("PLL_MEM_CLK_PHASE_DEG")
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQSCLK_PHASE", value )
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDR2XDQSCLK_CNT", "0")
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDR2XDQSCLK_PHASE", "0")
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQCLK_CNT", "1")
|
||||
value = self.emifModel.getPllDefine("PLL_WRITE_CLK_PHASE_DEG")
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQCLK_PHASE", value )
|
||||
|
||||
try:
|
||||
value = self.hpsModel.getSystemConfig("sdram_pll_c5")
|
||||
except ValueError:
|
||||
value = "5"
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_S2FUSER2CLK_CNT", value )
|
||||
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_S2FUSER2CLK_PHASE", "0")
|
||||
|
||||
def addClockFreq(self):
|
||||
""" add clock frequency settings to the file """
|
||||
paramMap = collections.OrderedDict()
|
||||
paramMap["OSC1"] = "eosc1_clk_hz"
|
||||
paramMap["OSC2"] = "eosc2_clk_hz"
|
||||
paramMap["F2S_SDR_REF"] = "F2SCLK_SDRAMCLK_FREQ"
|
||||
paramMap["F2S_PER_REF"] = "F2SCLK_PERIPHCLK_FREQ"
|
||||
paramMap["MAINVCO"] = "main_pll_vco_hz"
|
||||
paramMap["PERVCO"] = "periph_pll_vco_hz"
|
||||
|
||||
for key in paramMap.keys():
|
||||
id = "CFG_HPS_CLK_" + key + "_HZ"
|
||||
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||
doc.c_source.define(self.doc, id, value )
|
||||
|
||||
eosc1 = int(self.hpsModel.getSystemConfig("eosc1_clk_hz"))
|
||||
eosc2 = int(self.hpsModel.getSystemConfig("eosc2_clk_hz"))
|
||||
m = int(self.emifModel.getPllDefine("PLL_MEM_CLK_MULT"))
|
||||
n = int(self.emifModel.getPllDefine("PLL_MEM_CLK_DIV"))
|
||||
vco = int(round(eosc1 * (m + 1) / (n + 1)))
|
||||
doc.c_source.define(self.doc, "CFG_HPS_CLK_SDRVCO_HZ", str(vco) )
|
||||
|
||||
paramMap = collections.OrderedDict()
|
||||
paramMap["EMAC0"] = "emac0_clk_hz"
|
||||
paramMap["EMAC1"] = "emac1_clk_hz"
|
||||
paramMap["USBCLK"] = "usb_mp_clk_hz"
|
||||
paramMap["NAND"] = "nand_clk_hz"
|
||||
paramMap["SDMMC"] = "sdmmc_clk_hz"
|
||||
paramMap["QSPI"] = "qspi_clk_hz"
|
||||
paramMap["SPIM"] = "spi_m_clk_hz"
|
||||
paramMap["CAN0"] = "can0_clk_hz"
|
||||
paramMap["CAN1"] = "can1_clk_hz"
|
||||
paramMap["GPIODB"] = "gpio_db_clk_hz"
|
||||
paramMap["L4_MP"] = "l4_mp_clk_hz"
|
||||
paramMap["L4_SP"] = "l4_sp_clk_hz"
|
||||
|
||||
for key in paramMap.keys():
|
||||
id = "CFG_HPS_CLK_" + key + "_HZ"
|
||||
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||
doc.c_source.define(self.doc, id, value )
|
||||
|
||||
def addAlteraSettings(self):
|
||||
""" add Altera-related settings to the file """
|
||||
paramMap = collections.OrderedDict()
|
||||
paramMap["MPUCLK"] = "main_pll_c0_internal"
|
||||
paramMap["MAINCLK"] = "main_pll_c1_internal"
|
||||
paramMap["DBGATCLK"] = "main_pll_c2_internal"
|
||||
|
||||
for key in paramMap.keys():
|
||||
id = "CFG_HPS_ALTERAGRP_" + key
|
||||
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||
doc.c_source.define(self.doc, id, value )
|
||||
|
||||
def __str__(self):
|
||||
""" convert to string """
|
||||
self.createContent()
|
||||
return str(self.doc)
|
||||
5
tools/cv_bsp_generator/requirements.txt
Normal file
5
tools/cv_bsp_generator/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
# requirements.txt for cv_bsp_generator.py
|
||||
# All dependencies are either standard library modules
|
||||
# or local Python files included in this BSP tool.
|
||||
# No external pip packages are required.
|
||||
|
||||
102
tools/cv_bsp_generator/streamer.py
Executable file
102
tools/cv_bsp_generator/streamer.py
Executable file
@@ -0,0 +1,102 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
"""
|
||||
Generate license, file header and close tag.
|
||||
|
||||
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||
|
||||
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||
"""
|
||||
import os
|
||||
import struct
|
||||
import doc
|
||||
|
||||
class Streamer(object):
|
||||
""" Streamer class to generate license, header, and close tag.
|
||||
"""
|
||||
def __init__(self, fileName, mode='r'):
|
||||
""" Streamer initialization """
|
||||
self.fileName = fileName
|
||||
self.mode = mode
|
||||
self.file = None
|
||||
self.sentinel = None
|
||||
if '+' in mode or 'w' in mode or 'a' in mode:
|
||||
self.fileMode = 'write'
|
||||
else:
|
||||
self.fileMode = 'read'
|
||||
|
||||
def close(self):
|
||||
""" file close """
|
||||
if self.file != None:
|
||||
self.file.close()
|
||||
self.file = None
|
||||
|
||||
def open(self):
|
||||
""" file open """
|
||||
if self.fileName != None:
|
||||
if self.file == None:
|
||||
if self.fileMode == 'write':
|
||||
print ("Generating file: %s..." % self.fileName)
|
||||
else:
|
||||
print ("Reading file: %s..." % self.fileName)
|
||||
self.file = open(self.fileName, self.mode)
|
||||
|
||||
def read(self, numBytes):
|
||||
""" file read number of bytes """
|
||||
if self.file == None:
|
||||
print ("***Error: Attempted to read from unopened file %s" \
|
||||
% (self.fileName))
|
||||
exit(-1)
|
||||
|
||||
else:
|
||||
return self.file.read(numBytes)
|
||||
|
||||
def readUnsignedInt(self):
|
||||
""" read unsigned integer """
|
||||
return struct.unpack('I', self.read(4))[0]
|
||||
|
||||
def readUnsignedShort(self):
|
||||
""" read unsigned short """
|
||||
return struct.unpack('H', self.read(2))[0]
|
||||
|
||||
def readBytesAsString(self, numBytes):
|
||||
""" Read some bytes from a binary file
|
||||
and interpret the data values as a String
|
||||
"""
|
||||
bytes = self.read(numBytes)
|
||||
s = bytes.decode('utf-8')
|
||||
|
||||
return s
|
||||
|
||||
def write(self, str):
|
||||
""" file write """
|
||||
if self.file == None:
|
||||
print ("***Error: Attempted to write to unopened file %s" \
|
||||
% (self.fileName))
|
||||
exit(-1)
|
||||
|
||||
else:
|
||||
self.file.write("%s" % str)
|
||||
|
||||
def writeLicenseHeader(self):
|
||||
""" write license & copyright """
|
||||
# format the license header
|
||||
licenseHeader = "/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */\n"
|
||||
self.file.write("%s" % licenseHeader)
|
||||
copyrightHeader = "/*\n * Copyright (C) 2022 Intel Corporation <www.intel.com>\n *\n */\n"
|
||||
self.file.write("%s" % copyrightHeader)
|
||||
|
||||
def writeSentinelStart(self, sentinel):
|
||||
""" start header """
|
||||
if sentinel == None:
|
||||
return -1
|
||||
self.sentinel = sentinel
|
||||
self.file.write("%s\n%s\n\n" % (\
|
||||
"#ifndef " + self.sentinel,
|
||||
"#define " + self.sentinel))
|
||||
|
||||
def writeSentinelEnd(self, sentinel):
|
||||
""" end header """
|
||||
if sentinel == None:
|
||||
return -1
|
||||
self.sentinel = sentinel
|
||||
self.file.write("\n%s\n" % ("#endif /* " + self.sentinel + " */"))
|
||||
32
tools/cv_bsp_generator/xmlgrok.py
Executable file
32
tools/cv_bsp_generator/xmlgrok.py
Executable file
@@ -0,0 +1,32 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
"""
|
||||
XML node parser
|
||||
|
||||
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||
|
||||
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||
"""
|
||||
import xml.dom
|
||||
|
||||
def isElementNode(XMLNode):
|
||||
""" check if the node is element node """
|
||||
return XMLNode.nodeType == xml.dom.Node.ELEMENT_NODE
|
||||
|
||||
def firstElementChild(XMLNode):
|
||||
""" Calling firstChild on an Node of type Element often (always?)
|
||||
returns a Node of Text type. How annoying! Return the first Element
|
||||
child
|
||||
"""
|
||||
child = XMLNode.firstChild
|
||||
while child != None and not isElementNode(child):
|
||||
child = nextElementSibling(child)
|
||||
return child
|
||||
|
||||
def nextElementSibling(XMLNode):
|
||||
""" nextElementSibling will return the next sibling of XMLNode that is
|
||||
an Element Node Type
|
||||
"""
|
||||
sib = XMLNode.nextSibling
|
||||
while sib != None and not isElementNode(sib):
|
||||
sib = sib.nextSibling
|
||||
return sib
|
||||
@@ -129,6 +129,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
python3-pip \
|
||||
python3-pyelftools \
|
||||
python3-sphinx \
|
||||
python3-tk \
|
||||
python3-tomli \
|
||||
python3-venv \
|
||||
rpm2cpio \
|
||||
|
||||
280
tools/logos/u-boot_logo_with_text.svg
Normal file
280
tools/logos/u-boot_logo_with_text.svg
Normal file
@@ -0,0 +1,280 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- SPDX-License-Identifier: CC-BY-SA-4.0 -->
|
||||
|
||||
<!-- Copyright (c) 2018, Heinrich Schuchardt <xypron.glpk@gmx.de> -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="186"
|
||||
height="244"
|
||||
viewBox="0 0 186 244"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="u-boot_logo.svg"
|
||||
inkscape:export-filename="tools/logos/u-boot_logo.png"
|
||||
inkscape:export-xdpi="41.290001"
|
||||
inkscape:export-ydpi="41.290001">
|
||||
<title
|
||||
id="title30">U-Boot Logo</title>
|
||||
<metadata
|
||||
id="metadata31">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>U-Boot Logo</dc:title>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Heinrich Schuchardt <xypron.glpk@gmx.de></dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:date>May 21st, 2018</dc:date>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs29" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
id="namedview27"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.1213203"
|
||||
inkscape:cx="40"
|
||||
inkscape:cy="66.333333"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="flowRoot840" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,58)">
|
||||
<circle
|
||||
style="fill:#004466;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path835"
|
||||
cx="93"
|
||||
cy="35"
|
||||
r="93" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffcc88;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
d="M 116,18 A 20,20 0 0 1 96,-2 20,20 0 0 1 116,-22 v 11 a 9,9 0 0 0 -9,9 9,9 0 0 0 9,9 z"
|
||||
id="path4136-6-6-1-6-3-5" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffcc88;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
d="m 116,8 a 10,10 0 0 1 -10,-10 10,10 0 0 1 10,-10 v 1 a 9,9 0 0 0 -9,9 9,9 0 0 0 9,9 z"
|
||||
id="path4136-6-6-1-6-3-5-1-9" />
|
||||
<ellipse
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4136-6-6-1-6-3-5-1-2"
|
||||
cx="116"
|
||||
cy="-16.5"
|
||||
rx="4"
|
||||
ry="5.5" />
|
||||
<circle
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4352"
|
||||
cx="86"
|
||||
cy="8"
|
||||
r="10" />
|
||||
<circle
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4352-1"
|
||||
cx="126"
|
||||
cy="8"
|
||||
r="10" />
|
||||
<rect
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="rect4399"
|
||||
width="39"
|
||||
height="20"
|
||||
x="86.5"
|
||||
y="-2" />
|
||||
<rect
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="rect4660"
|
||||
width="60"
|
||||
height="9.5"
|
||||
x="76"
|
||||
y="8.5" />
|
||||
<circle
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4549-5"
|
||||
cx="36"
|
||||
cy="23"
|
||||
r="15" />
|
||||
<circle
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4549-5-5"
|
||||
cx="36"
|
||||
cy="63"
|
||||
r="15" />
|
||||
<ellipse
|
||||
style="fill:#ffcc88;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
id="path4136-6-6"
|
||||
cx="15"
|
||||
cy="33"
|
||||
rx="4"
|
||||
ry="10" />
|
||||
<ellipse
|
||||
style="fill:#ffcc88;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
id="path4136-6-6-1"
|
||||
cx="15"
|
||||
cy="53"
|
||||
rx="4"
|
||||
ry="10" />
|
||||
<rect
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
id="rect4213"
|
||||
width="65"
|
||||
height="4"
|
||||
x="11"
|
||||
y="41" />
|
||||
<ellipse
|
||||
style="fill:#ffcc88;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
id="path4136"
|
||||
cx="100.5"
|
||||
cy="42.5"
|
||||
rx="74.5"
|
||||
ry="34.5" />
|
||||
<ellipse
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4416"
|
||||
cx="70"
|
||||
cy="37.5"
|
||||
rx="15"
|
||||
ry="12.5" />
|
||||
<ellipse
|
||||
style="fill:#ffcc88;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4416-9"
|
||||
cx="70"
|
||||
cy="37.5"
|
||||
rx="14"
|
||||
ry="11.5" />
|
||||
<ellipse
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4416-0"
|
||||
cx="70"
|
||||
cy="37.5"
|
||||
rx="11"
|
||||
ry="8.5" />
|
||||
<ellipse
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4416-94"
|
||||
cx="110"
|
||||
cy="37.5"
|
||||
rx="15"
|
||||
ry="12.5" />
|
||||
<ellipse
|
||||
style="fill:#ffcc88;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4416-9-1"
|
||||
cx="110"
|
||||
cy="37.5"
|
||||
rx="14"
|
||||
ry="11.5" />
|
||||
<ellipse
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4416-0-1"
|
||||
cx="110"
|
||||
cy="37.5"
|
||||
rx="11"
|
||||
ry="8.5" />
|
||||
<ellipse
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4416-94-2"
|
||||
cx="150"
|
||||
cy="37.5"
|
||||
rx="15"
|
||||
ry="12.5" />
|
||||
<ellipse
|
||||
style="fill:#ffcc88;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4416-9-1-2"
|
||||
cx="150"
|
||||
cy="37.5"
|
||||
rx="14"
|
||||
ry="11.5" />
|
||||
<ellipse
|
||||
style="fill:#dd9955;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="path4416-0-1-9"
|
||||
cx="150"
|
||||
cy="37.5"
|
||||
rx="11"
|
||||
ry="8.5" />
|
||||
<g
|
||||
aria-label="U-Boot"
|
||||
transform="matrix(1.4316296,0,0,1.4316493,154.42725,-33.934324)"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#004466;fill-opacity:1;stroke:none"
|
||||
id="flowRoot840">
|
||||
<g
|
||||
id="g3123">
|
||||
<path
|
||||
style="stroke-width:0.99455768"
|
||||
id="path1717"
|
||||
d="m -107.86816,123.89647 h 3.9218 v 17.71485 q 0,4.6875 1.68078,6.75781 1.68077,2.05078 5.44802,2.05078 3.747933,0 5.428707,-2.05078 1.680773,-2.07031 1.680773,-6.75781 v -17.71485 h 3.921806 v 18.20313 q 0,5.70312 -2.80129,8.61328 -2.78197,2.91016 -8.229996,2.91016 -5.46734,0 -8.26863,-2.91016 -2.78197,-2.91016 -2.78197,-8.61328 z"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path1719"
|
||||
style="fill:#dd9955;fill-opacity:1;stroke-width:0.99455768"
|
||||
d="m -80.415526,140.49804 h 10.413069 v 3.20312 h -10.413069 z"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="stroke-width:0.99455768"
|
||||
id="path1721"
|
||||
d="m -60.28488,139.13085 v 10.68359 h 6.259433 q 3.149036,0 4.655936,-1.30859 1.526221,-1.32813 1.526221,-4.04297 0,-2.73437 -1.526221,-4.02344 -1.5069,-1.30859 -4.655936,-1.30859 z m 0,-11.99219 v 8.78906 h 5.776453 q 2.859247,0 4.250232,-1.07421 1.410304,-1.09375 1.410304,-3.32032 0,-2.20703 -1.410304,-3.30078 -1.390985,-1.09375 -4.250232,-1.09375 z m -3.902486,-3.24219 h 9.968727 q 4.462744,0 6.877649,1.875 2.414905,1.875 2.414905,5.33204 0,2.67578 -1.236432,4.25781 -1.236431,1.58203 -3.632016,1.97265 2.878566,0.625 4.462744,2.61719 1.603496,1.97266 1.603496,4.94141 0,3.90625 -2.627416,6.03515 -2.627417,2.12891 -7.476545,2.12891 h -10.355112 z"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="stroke-width:0.99455768"
|
||||
id="path1723"
|
||||
d="m -28.813841,133.70116 q -2.859247,0 -4.520701,2.26563 -1.661455,2.24609 -1.661455,6.17187 0,3.92578 1.642136,6.19141 1.661454,2.24609 4.54002,2.24609 2.839928,0 4.501383,-2.26562 1.661454,-2.26563 1.661454,-6.17188 0,-3.88672 -1.661454,-6.15234 -1.661455,-2.28516 -4.501383,-2.28516 z m 0,-3.04687 q 4.636617,0 7.283354,3.04687 2.646735,3.04688 2.646735,8.4375 0,5.3711 -2.646735,8.4375 -2.646737,3.04688 -7.283354,3.04688 -4.655936,0 -7.302672,-3.04688 -2.627416,-3.0664 -2.627416,-8.4375 0,-5.39062 2.627416,-8.4375 2.646736,-3.04687 7.302672,-3.04687 z"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="stroke-width:0.99455768"
|
||||
id="path1725"
|
||||
d="m -4.6068351,133.70116 q -2.8592473,0 -4.5207018,2.26563 -1.6614541,2.24609 -1.6614541,6.17187 0,3.92578 1.6421348,6.19141 1.6614545,2.24609 4.5400211,2.24609 2.839928,0 4.50138246,-2.26562 1.66145444,-2.26563 1.66145444,-6.17188 0,-3.88672 -1.66145444,-6.15234 -1.66145446,-2.28516 -4.50138246,-2.28516 z m 0,-3.04687 q 4.63661713,0 7.2833528,3.04687 2.6467357,3.04688 2.6467357,8.4375 0,5.3711 -2.6467357,8.4375 -2.64673567,3.04688 -7.2833528,3.04688 -4.6559365,0 -7.3026719,-3.04688 -2.627417,-3.0664 -2.627417,-8.4375 0,-5.39062 2.627417,-8.4375 2.6467354,-3.04687 7.3026719,-3.04687 z"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="stroke-width:0.99455768"
|
||||
id="path1727"
|
||||
d="m 14.731723,124.97069 v 6.21094 h 7.321991 v 2.79297 h -7.321991 v 11.875 q 0,2.67578 0.714811,3.4375 0.734132,0.76172 2.955843,0.76172 h 3.651337 v 3.00781 h -3.651337 q -4.114997,0 -5.679855,-1.54297 -1.564858,-1.5625 -1.564858,-5.66406 v -11.875 H 8.5495661 v -2.79297 h 2.6080979 v -6.21094 z"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
Reference in New Issue
Block a user