Merge tag 'v2026.01-rc4' into next

Prepare v2026.01-rc4
This commit is contained in:
Tom Rini
2025-12-08 13:17:27 -06:00
201 changed files with 7926 additions and 376 deletions

View File

@@ -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

View 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
View 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

File diff suppressed because one or more lines are too long

571
tools/cv_bsp_generator/hps.py Executable file
View 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
View 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
View 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

View 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)

View 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.

View 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 + " */"))

View 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

View File

@@ -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 \

View 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 &lt;xypron.glpk@gmx.de&gt;</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