From bd19527c755963de9c1d231fdacd112e54f33480 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 19 Nov 2025 08:32:58 -0600 Subject: Docker: Update QEMU to 10.0.6 The QEMU project has the 10.0.x series as an LTS release. While we are not doing an LTS ourselves, we can be confident in the changes between 10.0.2 and 10.0.6, so update ourselves. Signed-off-by: Tom Rini --- tools/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 58f2a28daa0..92be7f76341 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -220,7 +220,7 @@ RUN git clone git://git.savannah.gnu.org/grub.git /tmp/grub && \ RUN git clone https://gitlab.com/qemu-project/qemu.git /tmp/qemu && \ cd /tmp/qemu && \ - git checkout v10.0.2 && \ + git checkout v10.0.6 && \ # config user.name and user.email to make 'git am' happy git config user.name u-boot && \ git config user.email u-boot@denx.de && \ -- cgit v1.3.1 From bc4a1e56bfcdd70a5307c91c94dafcf6bb27da93 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 13 Nov 2025 16:09:56 -0600 Subject: Dockerfile: Include python3-tk for FATtools In some cases our tests for exFAT don't run because we fail to be able to create the underlying image. This is in turn because while creation of the image succeeds, it seems that some way of how we invoke FATtools wants to import tkinter, that fails and so the test stops there. Having tkinter available (and then presumably a fallback to non-GUI because it's not available) leads to the tests running as expected. Reviewed-by: Marek Vasut Signed-off-by: Tom Rini --- tools/docker/Dockerfile | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 92be7f76341..f98b42e7357 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -126,6 +126,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ python3-pip \ python3-pyelftools \ python3-sphinx \ + python3-tk \ python3-tomli \ python3-venv \ rpm2cpio \ -- cgit v1.3.1 From 4dfa4c14b8e5b37885f9eb281b3bc230938c5972 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 26 Nov 2025 10:21:54 -0600 Subject: Dockerfile: Update building trace tools slightly We have not been picking a tag for the trace-cmd build process. Currently the tip of libtraceevent fails to build. Address both problems here by picking recent stable tags for libtraceevent and libtracefs (trace-cmd has no recent tags). Further, as it is often reported that this fails to build due to a race, stop using "make -j$(nproc)" as this is also small enough of a set of builds to not be an issue. Signed-off-by: Tom Rini --- tools/docker/Dockerfile | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index f98b42e7357..960e4a7177f 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -311,17 +311,19 @@ RUN git clone https://github.com/stefanberger/swtpm /tmp/swtpm && \ # Build trace-cmd RUN mkdir /tmp/trace && \ - git clone https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git /tmp/trace/libtraceevent && \ + git clone --depth=1 https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git /tmp/trace/libtraceevent \ + -b libtraceevent-1.8.6 && \ cd /tmp/trace/libtraceevent && \ - make -j$(nproc) && \ + make && \ sudo make install && \ - git clone https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git /tmp/trace/libtracefs && \ + git clone --depth=1 https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git /tmp/trace/libtracefs \ + -b libtracefs-1.8.2 && \ cd /tmp/trace/libtracefs && \ - make -j$(nproc) && \ + make && \ sudo make install && \ git clone https://github.com/rostedt/trace-cmd.git /tmp/trace/trace-cmd && \ cd /tmp/trace/trace-cmd && \ - make -j$(nproc) && \ + make && \ sudo make install && \ rm -rf /tmp/trace -- cgit v1.3.1 From 0ae3dc6809ffb6568b5e46d9022829e36d473d36 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 26 Nov 2025 10:30:24 -0600 Subject: CI: Update to latest container - Move to jammy-20251013 tag - Bring in tkinter so that FATtools should run and more tests should be run. - Update to QEMU 10.0.6 - Pick tags for (most of) trace-cmd Signed-off-by: Tom Rini --- .azure-pipelines.yml | 2 +- .gitlab-ci.yml | 2 +- tools/docker/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 3f671dd078d..0c7c38ba730 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -2,7 +2,7 @@ variables: windows_vm: windows-2022 ubuntu_vm: ubuntu-24.04 macos_vm: macOS-14 - ci_runner_image: trini/u-boot-gitlab-ci-runner:jammy-20251001-04Nov2025 + ci_runner_image: trini/u-boot-gitlab-ci-runner:jammy-20251013-26Nov2025 # Ensure we do a shallow clone Agent.Source.Git.ShallowFetchDepth: 1 # Add '-u 0' options for Azure pipelines, otherwise we get "permission diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 86d3c741ea1..e7234e003ea 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,7 +18,7 @@ workflow: # Grab our configured image. The source for this is found # in the u-boot tree at tools/docker/Dockerfile -image: ${MIRROR_DOCKER}/trini/u-boot-gitlab-ci-runner:jammy-20251001-04Nov2025 +image: ${MIRROR_DOCKER}/trini/u-boot-gitlab-ci-runner:jammy-20251013-26Nov2025 # We run some tests in different order, to catch some failures quicker. stages: diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 960e4a7177f..8ab1cff5584 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -2,7 +2,7 @@ # This Dockerfile is used to build an image containing basic stuff to be used # to build U-Boot and run our test suites. -FROM ubuntu:jammy-20251001 +FROM ubuntu:jammy-20251013 LABEL org.opencontainers.image.authors="Tom Rini " LABEL org.opencontainers.image.description=" This image is for building U-Boot inside a container" -- cgit v1.3.1 From 3ba9b1f7bd7e7c47ff2768fc88abeb249400d374 Mon Sep 17 00:00:00 2001 From: Brian Sune Date: Sat, 1 Nov 2025 02:04:19 +0800 Subject: Cyclone V Board handsoff script Since turning from old build flow. New Altera SoCFPGA requires converting handsoff conversion via the python script. This is from official provided, and now sync to U-Boot with better location at tools/cv_xxxx. Meantime, requirement.txt is also provided to further explain the libraries require for these scripts. Signed-off-by: Brian Sune Reviewed-by: Tien Fong Chee --- tools/cv_bsp_generator/cv_bsp_generator.py | 100 +++++ tools/cv_bsp_generator/doc.py | 243 ++++++++++++ tools/cv_bsp_generator/emif.py | 424 +++++++++++++++++++++ tools/cv_bsp_generator/hps.py | 571 +++++++++++++++++++++++++++++ tools/cv_bsp_generator/iocsr.py | 203 ++++++++++ tools/cv_bsp_generator/model.py | 114 ++++++ tools/cv_bsp_generator/renderer.py | 196 ++++++++++ tools/cv_bsp_generator/requirements.txt | 5 + tools/cv_bsp_generator/streamer.py | 102 ++++++ tools/cv_bsp_generator/xmlgrok.py | 32 ++ 10 files changed, 1990 insertions(+) create mode 100755 tools/cv_bsp_generator/cv_bsp_generator.py create mode 100755 tools/cv_bsp_generator/doc.py create mode 100755 tools/cv_bsp_generator/emif.py create mode 100755 tools/cv_bsp_generator/hps.py create mode 100755 tools/cv_bsp_generator/iocsr.py create mode 100755 tools/cv_bsp_generator/model.py create mode 100755 tools/cv_bsp_generator/renderer.py create mode 100644 tools/cv_bsp_generator/requirements.txt create mode 100755 tools/cv_bsp_generator/streamer.py create mode 100755 tools/cv_bsp_generator/xmlgrok.py (limited to 'tools') diff --git a/tools/cv_bsp_generator/cv_bsp_generator.py b/tools/cv_bsp_generator/cv_bsp_generator.py new file mode 100755 index 00000000000..aff597d3978 --- /dev/null +++ b/tools/cv_bsp_generator/cv_bsp_generator.py @@ -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 + +Author: Lee, Kah Jing +""" +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= --output_dir=")) + 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) diff --git a/tools/cv_bsp_generator/doc.py b/tools/cv_bsp_generator/doc.py new file mode 100755 index 00000000000..86c5726c5f1 --- /dev/null +++ b/tools/cv_bsp_generator/doc.py @@ -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 + +Author: Lee, Kah Jing +""" + +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 ")) + 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) diff --git a/tools/cv_bsp_generator/emif.py b/tools/cv_bsp_generator/emif.py new file mode 100755 index 00000000000..143bd2da550 --- /dev/null +++ b/tools/cv_bsp_generator/emif.py @@ -0,0 +1,424 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +""" +SDRAM header file generator + +Process the handoff files from Quartus and convert them to headers +usable by U-Boot. + +Copyright (C) 2022 Intel Corporation + +Author: Lee, Kah Jing +""" + +import os +import re +import xml.dom.minidom +import streamer +import xmlgrok + +class EMIFGrokker(object): + """ parse an emif.xml input and translate to various + outputs + """ + SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_DIR = os.path.dirname(SCRIPT_DIR) + '/src' + SDRAM_FILE_HEADER = '/*\n' + ' * Altera SoCFPGA SDRAM configuration\n' + ' *\n' + ' */\n\n' + SDRAM_SENTINEL = '__SOCFPGA_SDRAM_CONFIG_H__' + SDRAM_MATCH = r'#define (CFG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE|CFG_HPS_SDR_CTRLCFG_CTRLCFG_MEMBL|CFG_HPS_SDR_CTRLCFG_CTRLCFG_ADDRORDER|CFG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN|CFG_HPS_SDR_CTRLCFG_CTRLCFG_ECCCORREN|CFG_HPS_SDR_CTRLCFG_CTRLCFG_REORDEREN|CFG_HPS_SDR_CTRLCFG_CTRLCFG_STARVELIMIT|CFG_HPS_SDR_CTRLCFG_CTRLCFG_DQSTRKEN|CFG_HPS_SDR_CTRLCFG_CTRLCFG_NODMPINS|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCWL|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_AL|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCL|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRRD|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TFAW|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRFC|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TREFI|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRCD|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRP|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWR|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWTR|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRTP|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRAS|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRC|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TMRD|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TCCD|CFG_HPS_SDR_CTRLCFG_DRAMTIMING4_SELFRFSHEXIT|CFG_HPS_SDR_CTRLCFG_DRAMTIMING4_PWRDOWNEXIT|CFG_HPS_SDR_CTRLCFG_LOWPWRTIMING_AUTOPDCYCLES|CFG_HPS_SDR_CTRLCFG_LOWPWRTIMING_CLKDISABLECYCLES|CFG_HPS_SDR_CTRLCFG_DRAMODT_READ|CFG_HPS_SDR_CTRLCFG_DRAMODT_WRITE|CFG_HPS_SDR_CTRLCFG_DRAMADDRW_COLBITS|CFG_HPS_SDR_CTRLCFG_DRAMADDRW_ROWBITS|CFG_HPS_SDR_CTRLCFG_DRAMADDRW_BANKBITS|CFG_HPS_SDR_CTRLCFG_DRAMADDRW_CSBITS|CFG_HPS_SDR_CTRLCFG_DRAMIFWIDTH_IFWIDTH|CFG_HPS_SDR_CTRLCFG_DRAMDEVWIDTH_DEVWIDTH|CFG_HPS_SDR_CTRLCFG_DRAMINTR_INTREN|CFG_HPS_SDR_CTRLCFG_LOWPWREQ_SELFRFSHMASK|CFG_HPS_SDR_CTRLCFG_STATICCFG_MEMBL|CFG_HPS_SDR_CTRLCFG_STATICCFG_USEECCASDATA|CFG_HPS_SDR_CTRLCFG_CTRLWIDTH_CTRLWIDTH|CFG_HPS_SDR_CTRLCFG_CPORTWIDTH_CPORTWIDTH|CFG_HPS_SDR_CTRLCFG_CPORTWMAP_CPORTWMAP|CFG_HPS_SDR_CTRLCFG_CPORTRMAP_CPORTRMAP|CFG_HPS_SDR_CTRLCFG_RFIFOCMAP_RFIFOCMAP|CFG_HPS_SDR_CTRLCFG_WFIFOCMAP_WFIFOCMAP|CFG_HPS_SDR_CTRLCFG_CPORTRDWR_CPORTRDWR|CFG_HPS_SDR_CTRLCFG_PORTCFG_AUTOPCHEN|CFG_HPS_SDR_CTRLCFG_FPGAPORTRST|CFG_HPS_SDR_CTRLCFG_FIFOCFG_SYNCMODE|CFG_HPS_SDR_CTRLCFG_FIFOCFG_INCSYNC|CFG_HPS_SDR_CTRLCFG_MPPRIORITY_USERPRIORITY|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_0_STATICWEIGHT_31_0|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_STATICWEIGHT_49_32|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_SUMOFWEIGHT_13_0|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_2_SUMOFWEIGHT_45_14|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_3_SUMOFWEIGHT_63_46|CFG_HPS_SDR_CTRLCFG_PHYCTRL_PHYCTRL_0|CFG_HPS_SDR_CTRLCFG_MPPACING_0_THRESHOLD1_31_0|CFG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD1_59_32|CFG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD2_3_0|CFG_HPS_SDR_CTRLCFG_MPPACING_2_THRESHOLD2_35_4|CFG_HPS_SDR_CTRLCFG_MPPACING_3_THRESHOLD2_59_36|CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0|CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32|CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64|RW_MGR_ACTIVATE_0_AND_1|RW_MGR_ACTIVATE_0_AND_1_WAIT1|RW_MGR_ACTIVATE_0_AND_1_WAIT2|RW_MGR_ACTIVATE_1|RW_MGR_CLEAR_DQS_ENABLE|RW_MGR_EMR_OCD_ENABLE|RW_MGR_EMR|RW_MGR_EMR2|RW_MGR_EMR3|RW_MGR_GUARANTEED_READ|RW_MGR_GUARANTEED_READ_CONT|RW_MGR_GUARANTEED_WRITE|RW_MGR_GUARANTEED_WRITE_WAIT0|RW_MGR_GUARANTEED_WRITE_WAIT1|RW_MGR_GUARANTEED_WRITE_WAIT2|RW_MGR_GUARANTEED_WRITE_WAIT3|RW_MGR_IDLE|RW_MGR_IDLE_LOOP1|RW_MGR_IDLE_LOOP2|RW_MGR_INIT_RESET_0_CKE_0|RW_MGR_INIT_RESET_1_CKE_0|RW_MGR_INIT_CKE_0|RW_MGR_LFSR_WR_RD_BANK_0|RW_MGR_LFSR_WR_RD_BANK_0_DATA|RW_MGR_LFSR_WR_RD_BANK_0_DQS|RW_MGR_LFSR_WR_RD_BANK_0_NOP|RW_MGR_LFSR_WR_RD_BANK_0_WAIT|RW_MGR_LFSR_WR_RD_BANK_0_WL_1|RW_MGR_LFSR_WR_RD_DM_BANK_0|RW_MGR_LFSR_WR_RD_DM_BANK_0_DATA|RW_MGR_LFSR_WR_RD_DM_BANK_0_DQS|RW_MGR_LFSR_WR_RD_DM_BANK_0_NOP|RW_MGR_LFSR_WR_RD_DM_BANK_0_WAIT|RW_MGR_LFSR_WR_RD_DM_BANK_0_WL_1|RW_MGR_MR_CALIB|RW_MGR_MR_USER|RW_MGR_MR_DLL_RESET|RW_MGR_MRS0_DLL_RESET|RW_MGR_MRS0_DLL_RESET_MIRR|RW_MGR_MRS0_USER|RW_MGR_MRS0_USER_MIRR|RW_MGR_MRS1|RW_MGR_MRS1_MIRR|RW_MGR_MRS2|RW_MGR_MRS2_MIRR|RW_MGR_MRS3|RW_MGR_MRS3_MIRR|RW_MGR_NOP|RW_MGR_PRECHARGE_ALL|RW_MGR_READ_B2B|RW_MGR_READ_B2B_WAIT1|RW_MGR_READ_B2B_WAIT2|RW_MGR_REFRESH|RW_MGR_REFRESH_ALL|RW_MGR_RETURN|RW_MGR_SGLE_READ|RW_MGR_ZQCL|RW_MGR_TRUE_MEM_DATA_MASK_WIDTH|RW_MGR_MEM_ADDRESS_MIRRORING|RW_MGR_MEM_DATA_MASK_WIDTH|RW_MGR_MEM_DATA_WIDTH|RW_MGR_MEM_DQ_PER_READ_DQS|RW_MGR_MEM_DQ_PER_WRITE_DQS|RW_MGR_MEM_IF_READ_DQS_WIDTH|RW_MGR_MEM_IF_WRITE_DQS_WIDTH|RW_MGR_MEM_NUMBER_OF_CS_PER_DIMM|RW_MGR_MEM_NUMBER_OF_RANKS|RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS|RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS|IO_DELAY_PER_DCHAIN_TAP|IO_DELAY_PER_DQS_EN_DCHAIN_TAP|IO_DELAY_PER_OPA_TAP|IO_DLL_CHAIN_LENGTH|IO_DQDQS_OUT_PHASE_MAX|IO_DQS_EN_DELAY_MAX|IO_DQS_EN_DELAY_OFFSET|IO_DQS_EN_PHASE_MAX|IO_DQS_IN_DELAY_MAX|IO_DQS_IN_RESERVE|IO_DQS_OUT_RESERVE|IO_IO_IN_DELAY_MAX|IO_IO_OUT1_DELAY_MAX|IO_IO_OUT2_DELAY_MAX|IO_SHIFT_DQS_EN_WHEN_SHIFT_DQS|AFI_RATE_RATIO|AFI_CLK_FREQ|CALIB_LFIFO_OFFSET|CALIB_VFIFO_OFFSET|ENABLE_SUPER_QUICK_CALIBRATION|MAX_LATENCY_COUNT_WIDTH|READ_VALID_FIFO_SIZE|REG_FILE_INIT_SEQ_SIGNATURE|TINIT_CNTR0_VAL|TINIT_CNTR1_VAL|TINIT_CNTR2_VAL|TRESET_CNTR0_VAL|TRESET_CNTR1_VAL|TRESET_CNTR2_VAL|CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR|CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_BC|CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_DIFF_CHIP)\s+' + + SDRAM_CONFIG_H_FILENAME = "sdram_config.h" + + sdramHTemplate = "" + seqAutoTemplate = "" + seqDefinesTemplate = "" + seqAutoAcTemplate = "" + seqAutoInstTemplate = "" + seqAutoTemplateList = [] + seqDefinesTemplateList = [] + seqAutoAcTemplateList = [] + seqAutoInstTemplateList = [] + + def __init__(self, inputDir, outputDir, emifFileName='emif.xml', hpsFileName='hps.xml'): + """ EMIFGrokker initialization """ + self.inputDir = inputDir + self.outputDir = outputDir + + sdramDir = self.outputDir + if not os.path.isdir(sdramDir): + os.makedirs(sdramDir) + + self.emifFileName = inputDir + os.sep + emifFileName + self.hpsFileName = inputDir + os.sep + hpsFileName + self.emifDom = xml.dom.minidom.parse(self.emifFileName) + self.hpsDom = xml.dom.minidom.parse(self.hpsFileName) + self.sequencerDefinesStream = None + self.seqAutoFileName = inputDir + os.sep + "sequencer_auto.h" + self.seqDefinesFileName = inputDir + os.sep + "sequencer_defines.h" + self.seqAutoACFileName = inputDir + os.sep + "sequencer_auto_ac_init.c" + self.seqAutoInstFileName = inputDir + os.sep + "sequencer_auto_inst_init.c" + + self.createFilesFromEMIF() + + def openSeqFiles(self): + """ files to retrieve values to written to sdram_config.h """ + self.seq_auto_fd = open(self.seqAutoFileName, "r") + self.seq_defines_fd = open(self.seqDefinesFileName, "r") + self.seq_auto_ac_fd = open(self.seqAutoACFileName, "r") + self.seq_auto_inst_fd = open(self.seqAutoInstFileName, "r") + + def closeSeqFiles(self): + """ close files """ + self.seq_auto_fd.close() + self.seq_defines_fd.close() + self.seq_auto_ac_fd.close() + self.seq_auto_inst_fd.close() + + def processSeqAuto(self): + """ process sequencer files to retrieve variable. Regex match is from + qts-filter.sh + """ + # replace underscore & bracket in sequencer_auto.h define + for line in self.seq_auto_fd.readlines(): + if re.match(".*__RW_MGR_", line) and not re.match(".*ac_", line) and not re.match(".*CONTENT_", line): + line = re.sub("__RW_MGR", "RW_MGR", line) + if re.match(self.SDRAM_MATCH, line): + self.seqAutoTemplateList.append(re.sub(r' (\w+)(\s+)(\d+)', r' \1\t\3', line)) + self.seqAutoTemplateList.sort() + self.seqAutoTemplate = ''.join([item for item in self.seqAutoTemplateList]) + + # replace underscore & bracket in sequencer_defines.h define + for line in self.seq_defines_fd.readlines(): + if re.match("^#define (\w+_)", line): + line = re.sub("__", "", line) + if re.match(self.SDRAM_MATCH, line): + self.seqDefinesTemplateList.append(re.sub(r' (\w+)(\s+)(\d+)', r' \1\t\3', line)) + self.seqDefinesTemplateList.sort() + self.seqDefinesTemplate = ''.join([item for item in self.seqDefinesTemplateList]) + + arrayMatchStart = 0 + # replace const variable declaration in sequencer_auto_ac_init.c + for line in self.seq_auto_ac_fd.readlines(): + if re.match("^const.*\[", line) or arrayMatchStart: + if arrayMatchStart == 0: + line = line.strip() + " " + arrayMatchStart = 1 + if re.match("};", line): + arrayMatchStart = 0 + self.seqAutoAcTemplateList.append("};") + continue + line = re.sub("alt_u32", "u32", line) + self.seqAutoAcTemplateList.append(re.sub("\[.*\]", "[]", line)) + self.seqAutoAcTemplate = ''.join([item for item in self.seqAutoAcTemplateList]) + + arrayMatchStart = 0 + # replace const variable declaration in sequencer_auto_inst_init.c + for line in self.seq_auto_inst_fd.readlines(): + if re.match("^const.*\[", line) or arrayMatchStart: + if arrayMatchStart == 0: + line = line.strip() + " " + arrayMatchStart = 1 + if re.match("};", line): + arrayMatchStart = 0 + self.seqAutoInstTemplateList.append("};") + continue + line = re.sub("alt_u32", "u32", line) + self.seqAutoInstTemplateList.append(re.sub("\[.*\]", "[]", line)) + self.seqAutoInstTemplate = ''.join([item for item in self.seqAutoInstTemplateList]) + + def handleSettingNode(self, settingNode): + """ create define string from variable name and value """ + if settingNode.hasAttribute('name') and settingNode.hasAttribute('value'): + name = settingNode.getAttribute('name') + value = settingNode.getAttribute('value') + self.sequencerDefinesStream.write("#define " + name + ' ' + '(' + value + ')' + '\n') + + def updateTemplate(self, name, value): + """ update sdram template """ + pattern = "${" + name + "}" + self.sdramHTemplate = self.sdramHTemplate.replace(pattern, value) + + def handleEMIFControllerNode(self, node): + """ retrieve values from emif.xml for controller node """ + derivedNoDmPins = 0 + derivedCtrlWidth = 0 + derivedEccEn = 0 + derivedEccCorrEn = 0 + + self.mem_if_rd_to_wr_turnaround_oct = 0 + + node = xmlgrok.firstElementChild(node) + while node != None: + name = node.getAttribute('name') + value = node.getAttribute('value') + + if value == "true": + value = "1" + elif value == "false": + value = "0" + + self.updateTemplate(name, value) + + if name == "MEM_IF_DM_PINS_EN": + if value == "1": + derivedNoDmPins = 0 + else: + derivedNoDmPins = 1 + + if name == "MEM_DQ_WIDTH": + if value == "8": + derivedCtrlWidth = 0 + derivedEccEn = 0 + derivedEccCorrEn = 0 + elif value == "16": + derivedCtrlWidth = 1 + derivedEccEn = 0 + derivedEccCorrEn = 0 + elif value == "24": + derivedCtrlWidth = 1 + derivedEccEn = 1 + derivedEccCorrEn = 1 + elif value == "32": + derivedCtrlWidth = 2 + derivedEccEn = 0 + derivedEccCorrEn = 0 + elif value == "40": + derivedCtrlWidth = 2 + derivedEccEn = 1 + derivedEccCorrEn = 1 + + if name == "MEM_IF_RD_TO_WR_TURNAROUND_OCT": + self.mem_if_rd_to_wr_turnaround_oct = int(value) + + node = xmlgrok.nextElementSibling(node) + + self.updateTemplate("DERIVED_NODMPINS", str(derivedNoDmPins)) + self.updateTemplate("DERIVED_CTRLWIDTH", str(derivedCtrlWidth)) + self.updateTemplate("DERIVED_ECCEN", str(derivedEccEn)) + self.updateTemplate("DERIVED_ECCCORREN", str(derivedEccCorrEn)) + + def handleEMIFPllNode(self, node): + """ retrieve values for pll node """ + node = xmlgrok.firstElementChild(node) + while node != None: + name = node.getAttribute('name') + value = node.getAttribute('value') + + self.updateTemplate(name, value) + + node = xmlgrok.nextElementSibling(node) + + def handleEMIFSequencerNode(self, node): + """ retrieve values for sequencer node """ + derivedMemtype = 0 + derivedSelfrfshexit = 0 + + self.afi_rate_ratio = 0 + + node = xmlgrok.firstElementChild(node) + while node != None: + name = node.getAttribute('name') + value = node.getAttribute('value') + + self.updateTemplate(name, value) + + if value.isdigit(): + intValue = int(value) + else: + intValue = 0 + + if name == "DDR2" and intValue != 0: + derivedMemtype = 1 + derivedSelfrfshexit = 200 + elif name == "DDR3" and intValue != 0: + derivedMemtype = 2 + derivedSelfrfshexit = 512 + elif name == "LPDDR1" and intValue != 0: + derivedMemtype = 3 + derivedSelfrfshexit = 200 + elif name == "LPDDR2" and intValue != 0: + derivedMemtype = 4 + derivedSelfrfshexit = 200 + elif name == "AFI_RATE_RATIO" and intValue != 0: + self.afi_rate_ratio = intValue + + node = xmlgrok.nextElementSibling(node) + + self.updateTemplate("DERIVED_MEMTYPE", str(derivedMemtype)) + self.updateTemplate("DERIVED_SELFRFSHEXIT", str(derivedSelfrfshexit)) + + + def handleHpsFpgaInterfaces(self, node): + """ retrieve values for fpga interface """ + node = xmlgrok.firstElementChild(node) + + while node != None: + name = node.getAttribute('name') + value = node.getAttribute('value') + + self.updateTemplate(name, value) + + node = xmlgrok.nextElementSibling(node) + + + def createFilesFromEMIF(self): + """ create sdram_config.h with the template and value read from xml. + Different sequencer files are written to individual section, with + comment at the start. + """ + self.sdramHTemplate ="""\ +#define CFG_HPS_SDR_CTRLCFG_CPORTRDWR_CPORTRDWR 0x5A56A +#define CFG_HPS_SDR_CTRLCFG_CPORTRMAP_CPORTRMAP 0xB00088 +#define CFG_HPS_SDR_CTRLCFG_CPORTWIDTH_CPORTWIDTH 0x44555 +#define CFG_HPS_SDR_CTRLCFG_CPORTWMAP_CPORTWMAP 0x2C011000 +#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_ADDRORDER ${ADDR_ORDER} +#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_DQSTRKEN ${USE_HPS_DQS_TRACKING} +#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_ECCCORREN ${DERIVED_ECCCORREN} +#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN ${DERIVED_ECCEN} +#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_MEMBL ${MEM_BURST_LENGTH} +#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE ${DERIVED_MEMTYPE} +#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_NODMPINS ${DERIVED_NODMPINS} +#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_REORDEREN 1 +#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_STARVELIMIT 10 +#define CFG_HPS_SDR_CTRLCFG_CTRLWIDTH_CTRLWIDTH ${DERIVED_CTRLWIDTH} +#define CFG_HPS_SDR_CTRLCFG_DRAMADDRW_BANKBITS ${MEM_IF_BANKADDR_WIDTH} +#define CFG_HPS_SDR_CTRLCFG_DRAMADDRW_COLBITS ${MEM_IF_COL_ADDR_WIDTH} +#define CFG_HPS_SDR_CTRLCFG_DRAMADDRW_CSBITS ${DEVICE_DEPTH} +#define CFG_HPS_SDR_CTRLCFG_DRAMADDRW_ROWBITS ${MEM_IF_ROW_ADDR_WIDTH} +#define CFG_HPS_SDR_CTRLCFG_DRAMDEVWIDTH_DEVWIDTH 8 +#define CFG_HPS_SDR_CTRLCFG_DRAMIFWIDTH_IFWIDTH ${MEM_DQ_WIDTH} +#define CFG_HPS_SDR_CTRLCFG_DRAMINTR_INTREN 0 +#define CFG_HPS_SDR_CTRLCFG_DRAMODT_READ ${CFG_READ_ODT_CHIP} +#define CFG_HPS_SDR_CTRLCFG_DRAMODT_WRITE ${CFG_WRITE_ODT_CHIP} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_AL 0 +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCL ${MEM_TCL} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCWL ${MEM_WTCL_INT} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TFAW ${MEM_TFAW} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRFC ${MEM_TRFC} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRRD ${MEM_TRRD} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRCD ${MEM_TRCD} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TREFI ${MEM_TREFI} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRP ${MEM_TRP} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWR ${MEM_TWR} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWTR ${MEM_TWTR} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TCCD 4 +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TMRD ${MEM_TMRD_CK} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRAS ${MEM_TRAS} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRC ${MEM_TRC} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRTP ${MEM_TRTP} +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING4_PWRDOWNEXIT 3 +#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING4_SELFRFSHEXIT ${DERIVED_SELFRFSHEXIT} +#define CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR ${DERIVED_CLK_RD_TO_WR} +#define CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_BC ${DERIVED_CLK_RD_TO_WR} +#define CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_DIFF_CHIP ${DERIVED_CLK_RD_TO_WR} +#define CFG_HPS_SDR_CTRLCFG_FIFOCFG_INCSYNC 0 +#define CFG_HPS_SDR_CTRLCFG_FIFOCFG_SYNCMODE 0 +#define CFG_HPS_SDR_CTRLCFG_FPGAPORTRST ${F2SDRAM_RESET_PORT_USED} +#define CFG_HPS_SDR_CTRLCFG_LOWPWREQ_SELFRFSHMASK 3 +#define CFG_HPS_SDR_CTRLCFG_LOWPWRTIMING_AUTOPDCYCLES 0 +#define CFG_HPS_SDR_CTRLCFG_LOWPWRTIMING_CLKDISABLECYCLES 8 +#define CFG_HPS_SDR_CTRLCFG_MPPACING_0_THRESHOLD1_31_0 0x20820820 +#define CFG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD1_59_32 0x8208208 +#define CFG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD2_3_0 0 +#define CFG_HPS_SDR_CTRLCFG_MPPACING_2_THRESHOLD2_35_4 0x41041041 +#define CFG_HPS_SDR_CTRLCFG_MPPACING_3_THRESHOLD2_59_36 0x410410 +#define CFG_HPS_SDR_CTRLCFG_MPPRIORITY_USERPRIORITY 0x0 +#define CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0 0x01010101 +#define CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32 0x01010101 +#define CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64 0x0101 +#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_0_STATICWEIGHT_31_0 0x21084210 +#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_STATICWEIGHT_49_32 0x10441 +#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_SUMOFWEIGHT_13_0 0x78 +#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_2_SUMOFWEIGHT_45_14 0x0 +#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_3_SUMOFWEIGHT_63_46 0x0 +#define CFG_HPS_SDR_CTRLCFG_PHYCTRL_PHYCTRL_0 0x200 +#define CFG_HPS_SDR_CTRLCFG_PORTCFG_AUTOPCHEN 0 +#define CFG_HPS_SDR_CTRLCFG_RFIFOCMAP_RFIFOCMAP 0x760210 +#define CFG_HPS_SDR_CTRLCFG_STATICCFG_MEMBL 2 +#define CFG_HPS_SDR_CTRLCFG_STATICCFG_USEECCASDATA 0 +#define CFG_HPS_SDR_CTRLCFG_WFIFOCMAP_WFIFOCMAP 0x980543 +""" + + # Get a list of all nodes with the emif element name + emifNodeList = self.emifDom.getElementsByTagName('emif') + if len(emifNodeList) > 1: + print ("*** WARNING:" + "Multiple emif Elements found in %s!" % self.emifFileName) + # For each of the emif element nodes, go through the child list + # Note that currently there is only one emif Element + # but this code will handle more than one emif node + # In the future, multiple emif nodes may need additional code + # to combine settings from the multiple emif Elements + for emifNode in emifNodeList: + # Currently, there are only 3 children of the emif Element: + # sequencer, controller, and pll + # but this is left open-ended for future additions to the + # specification for the emif.xml + childNode = xmlgrok.firstElementChild(emifNode) + while childNode != None: + + if childNode.nodeName == 'controller': + self.handleEMIFControllerNode(childNode) + elif childNode.nodeName == 'sequencer': + self.handleEMIFSequencerNode(childNode) + elif childNode.nodeName == 'pll': + self.handleEMIFPllNode(childNode) + + childNode = xmlgrok.nextElementSibling(childNode) + + data_rate_ratio = 2 + dwidth_ratio = self.afi_rate_ratio * data_rate_ratio + if dwidth_ratio == 0: + derivedClkRdToWr = 0 + else: + derivedClkRdToWr = (self.mem_if_rd_to_wr_turnaround_oct / (dwidth_ratio / 2)) + + if (self.mem_if_rd_to_wr_turnaround_oct % (dwidth_ratio / 2)) > 0: + derivedClkRdToWr += 1 + + self.updateTemplate("DERIVED_CLK_RD_TO_WR", str(int(derivedClkRdToWr))) + + # MPFE information are stored in hps.xml despite we generate + # them into sdram_config, so let's load hps.xml + hpsNodeList = self.hpsDom.getElementsByTagName('hps') + + for hpsNode in hpsNodeList: + + childNode = xmlgrok.firstElementChild(hpsNode) + + while childNode != None: + # MPFE info is part of fpga_interfaces + if childNode.nodeName == 'fpga_interfaces': + self.handleHpsFpgaInterfaces(childNode) + + childNode = xmlgrok.nextElementSibling(childNode) + + self.sequencerDefinesStream = streamer.Streamer(self.outputDir + os.sep + EMIFGrokker.SDRAM_CONFIG_H_FILENAME, 'w') + self.sequencerDefinesStream.open() + self.sequencerDefinesStream.writeLicenseHeader() + self.sequencerDefinesStream.write(EMIFGrokker.SDRAM_FILE_HEADER) + ret = self.sequencerDefinesStream.writeSentinelStart(EMIFGrokker.SDRAM_SENTINEL) + if ret == -1: + print("Empty header written. Exiting.") + self.sequencerDefinesStream.write("/* SDRAM configuration */\n") + self.sequencerDefinesStream.write(self.sdramHTemplate) + self.openSeqFiles() + self.processSeqAuto() + + self.sequencerDefinesStream.write("\n") + self.sequencerDefinesStream.write("/* Sequencer auto configuration */\n") + self.sequencerDefinesStream.write(self.seqAutoTemplate) + self.sequencerDefinesStream.write("\n") + self.sequencerDefinesStream.write("/* Sequencer defines configuration */\n") + self.sequencerDefinesStream.write(self.seqDefinesTemplate) + self.sequencerDefinesStream.write("\n") + self.sequencerDefinesStream.write("/* Sequencer ac_rom_init configuration */\n") + self.sequencerDefinesStream.write(self.seqAutoAcTemplate) + self.sequencerDefinesStream.write("\n\n") + self.sequencerDefinesStream.write("/* Sequencer inst_rom_init configuration */\n") + self.sequencerDefinesStream.write(self.seqAutoInstTemplate) + self.sequencerDefinesStream.write("\n") + + ret = self.sequencerDefinesStream.writeSentinelEnd(EMIFGrokker.SDRAM_SENTINEL) + if ret == -1: + print("Empty header written. Exiting.") + self.sequencerDefinesStream.close() + self.closeSeqFiles() diff --git a/tools/cv_bsp_generator/hps.py b/tools/cv_bsp_generator/hps.py new file mode 100755 index 00000000000..d702c5b4891 --- /dev/null +++ b/tools/cv_bsp_generator/hps.py @@ -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 + +Author: Lee, Kah Jing +""" +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() diff --git a/tools/cv_bsp_generator/iocsr.py b/tools/cv_bsp_generator/iocsr.py new file mode 100755 index 00000000000..a6ff5dfd829 --- /dev/null +++ b/tools/cv_bsp_generator/iocsr.py @@ -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 + +Author: Lee, Kah Jing +""" +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() diff --git a/tools/cv_bsp_generator/model.py b/tools/cv_bsp_generator/model.py new file mode 100755 index 00000000000..c30d6246cc4 --- /dev/null +++ b/tools/cv_bsp_generator/model.py @@ -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 + +Author: Lee, Kah Jing +""" +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 node + self.hpsNode = getSingletonElementByTagName(self.dom, "hps") + # Look for 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 nodes + for node in self.hpsSystemNode.getElementsByTagName("config"): + # assume name is the first attribute as in + nameAttrNode = node.attributes.item(0) + if nameAttrNode.nodeName == "name" and nameAttrNode.nodeValue == param: + # assume value is the second attribute as in + valueAttrNode = node.attributes.item(1) + if valueAttrNode.nodeName == "value": + hpsSystemConfigNode = valueAttrNode + break + + if hpsSystemConfigNode == None: + raise ValueError("Can't find 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 node + self.emifNode = getSingletonElementByTagName(self.dom, "emif") + # Look for 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 nodes + for node in self.emifPllNode.getElementsByTagName("define"): + nameAttrNode = node.attributes.item(0) + # assume name is the first attribute as in + if nameAttrNode.nodeName == "name" and nameAttrNode.nodeValue == param: + # assume value is the second attribute as in + 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 diff --git a/tools/cv_bsp_generator/renderer.py b/tools/cv_bsp_generator/renderer.py new file mode 100755 index 00000000000..0ab1e2f2df2 --- /dev/null +++ b/tools/cv_bsp_generator/renderer.py @@ -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 + +Author: Lee, Kah Jing +""" +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) diff --git a/tools/cv_bsp_generator/requirements.txt b/tools/cv_bsp_generator/requirements.txt new file mode 100644 index 00000000000..2ad65d1c331 --- /dev/null +++ b/tools/cv_bsp_generator/requirements.txt @@ -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. + diff --git a/tools/cv_bsp_generator/streamer.py b/tools/cv_bsp_generator/streamer.py new file mode 100755 index 00000000000..19c30aced6a --- /dev/null +++ b/tools/cv_bsp_generator/streamer.py @@ -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 + +Author: Lee, Kah Jing +""" +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 \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 + " */")) diff --git a/tools/cv_bsp_generator/xmlgrok.py b/tools/cv_bsp_generator/xmlgrok.py new file mode 100755 index 00000000000..fae1d745bfd --- /dev/null +++ b/tools/cv_bsp_generator/xmlgrok.py @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +""" +XML node parser + +Copyright (C) 2022 Intel Corporation + +Author: Lee, Kah Jing +""" +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 -- cgit v1.3.1 From 02aa1a56a7cfcb858973ef8965e54cf539060fd9 Mon Sep 17 00:00:00 2001 From: Chukun Pan Date: Tue, 2 Dec 2025 18:00:00 +0800 Subject: binman: fallback to importlib_resources on Python 3.8 Python 3.7 and 3.8 lack the files attribute in importlib.resources. Use importlib_resources to fix build errors with Python 3.8: binman: module 'importlib.resources' has no attribute 'files' Fixes: 538719cb6a77 ("binman: migrate from pkg_resources to importlib") Signed-off-by: Chukun Pan Acked-by: Quentin Schulz [trini: Re-add # pragma: no cover line] Signed-off-by: Tom Rini --- tools/binman/control.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/binman/control.py b/tools/binman/control.py index 1307222591d..816f7c1eba2 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -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 -- cgit v1.3.1 From 56778d4c2787cb0eea35b5e9bb82e4782b17ff41 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 22 Nov 2025 23:17:37 +0100 Subject: tools/logos: Add U-Boot logo with text 'U-Boot' The logo with the text 'U-Boot' has been used in multiple presentations. Up to now it was only available from my upload to wikimedia.org. Make it available in our repository. Link: https://upload.wikimedia.org/wikipedia/commons/9/9e/U-Boot_Logo.svg Signed-off-by: Heinrich Schuchardt --- tools/logos/u-boot_logo_with_text.svg | 280 ++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 tools/logos/u-boot_logo_with_text.svg (limited to 'tools') diff --git a/tools/logos/u-boot_logo_with_text.svg b/tools/logos/u-boot_logo_with_text.svg new file mode 100644 index 00000000000..1527e79a3a9 --- /dev/null +++ b/tools/logos/u-boot_logo_with_text.svg @@ -0,0 +1,280 @@ + + + + + + + U-Boot Logo + + + + image/svg+xml + + U-Boot Logo + + + + Heinrich Schuchardt <xypron.glpk@gmx.de> + + + May 21st, 2018 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.3.1