diff options
author | Kah Jing Lee <kah.jing.lee@intel.com> | 2022-10-02 16:36:10 +0800 |
---|---|---|
committer | Lokanathan, Raaj <raaj.lokanathan@intel.com> | 2023-01-06 15:50:43 +0800 |
commit | e5d8a2774ef76b2ce72082c179d1f1b24875b926 (patch) | |
tree | cc65ef66c377659eba3214b64b8b841e294115f3 | |
parent | 3c21bfbf3be6320772aabd51bebeb166a3ca89e6 (diff) | |
download | u-boot-socfpga-e5d8a2774ef76b2ce72082c179d1f1b24875b926.tar.gz |
arm: socfpga: Add bsp-generator scripts with qts-filter
HSD#14015480674 & HSD#14015550009:
Remove the requirement on the bsp-create-settings script to generate
uboot header files.
It will 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 to be used for mainline Uboot on FPGA, namely Cyclone V
& Arria V.
Usage of each .py scripts:
cv_bsp_generator.py : main wrapper to generate uboot required files
doc.py : templates for creating documents of generic data model
emif.py : parse handoff files to create sdram_config.h
hps.py : parse hps.xml to create pinmux_config.h file
iocsr.py : process the hiof file from Quartus and generate
iocsr .h usable by U-Boot
model.py : wrapper for XML DOM parser
renderer.py : construction of a specific file format using required
data model, in the case, generate the pll_config.h
streamer.py : generate license, file header and close tag
xmlgrok.py : xml tag navigator
Signed-off-by: Kah Jing Lee <kah.jing.lee@intel.com>
-rwxr-xr-x | arch/arm/mach-socfpga/cv_bsp_generator/cv_bsp_generator.py | 100 | ||||
-rwxr-xr-x | arch/arm/mach-socfpga/cv_bsp_generator/doc.py | 243 | ||||
-rwxr-xr-x | arch/arm/mach-socfpga/cv_bsp_generator/emif.py | 424 | ||||
-rwxr-xr-x | arch/arm/mach-socfpga/cv_bsp_generator/hps.py | 561 | ||||
-rwxr-xr-x | arch/arm/mach-socfpga/cv_bsp_generator/iocsr.py | 203 | ||||
-rwxr-xr-x | arch/arm/mach-socfpga/cv_bsp_generator/model.py | 114 | ||||
-rwxr-xr-x | arch/arm/mach-socfpga/cv_bsp_generator/renderer.py | 196 | ||||
-rwxr-xr-x | arch/arm/mach-socfpga/cv_bsp_generator/streamer.py | 102 | ||||
-rwxr-xr-x | arch/arm/mach-socfpga/cv_bsp_generator/xmlgrok.py | 32 | ||||
-rw-r--r-- | doc/README.socfpga | 71 |
10 files changed, 1986 insertions, 60 deletions
diff --git a/arch/arm/mach-socfpga/cv_bsp_generator/cv_bsp_generator.py b/arch/arm/mach-socfpga/cv_bsp_generator/cv_bsp_generator.py new file mode 100755 index 0000000000..aff597d397 --- /dev/null +++ b/arch/arm/mach-socfpga/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 <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) diff --git a/arch/arm/mach-socfpga/cv_bsp_generator/doc.py b/arch/arm/mach-socfpga/cv_bsp_generator/doc.py new file mode 100755 index 0000000000..86c5726c5f --- /dev/null +++ b/arch/arm/mach-socfpga/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 <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) diff --git a/arch/arm/mach-socfpga/cv_bsp_generator/emif.py b/arch/arm/mach-socfpga/cv_bsp_generator/emif.py new file mode 100755 index 0000000000..df340e0493 --- /dev/null +++ b/arch/arm/mach-socfpga/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 <www.intel.com> + +Author: Lee, Kah Jing <kah.jing.lee@intel.com> +""" + +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 (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE|CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMBL|CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ADDRORDER|CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN|CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCCORREN|CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_REORDEREN|CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_STARVELIMIT|CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_DQSTRKEN|CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_NODMPINS|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCWL|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_AL|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCL|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRRD|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TFAW|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRFC|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TREFI|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRCD|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRP|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWR|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWTR|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRTP|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRAS|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRC|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TMRD|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TCCD|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING4_SELFRFSHEXIT|CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING4_PWRDOWNEXIT|CONFIG_HPS_SDR_CTRLCFG_LOWPWRTIMING_AUTOPDCYCLES|CONFIG_HPS_SDR_CTRLCFG_LOWPWRTIMING_CLKDISABLECYCLES|CONFIG_HPS_SDR_CTRLCFG_DRAMODT_READ|CONFIG_HPS_SDR_CTRLCFG_DRAMODT_WRITE|CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_COLBITS|CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_ROWBITS|CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_BANKBITS|CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_CSBITS|CONFIG_HPS_SDR_CTRLCFG_DRAMIFWIDTH_IFWIDTH|CONFIG_HPS_SDR_CTRLCFG_DRAMDEVWIDTH_DEVWIDTH|CONFIG_HPS_SDR_CTRLCFG_DRAMINTR_INTREN|CONFIG_HPS_SDR_CTRLCFG_LOWPWREQ_SELFRFSHMASK|CONFIG_HPS_SDR_CTRLCFG_STATICCFG_MEMBL|CONFIG_HPS_SDR_CTRLCFG_STATICCFG_USEECCASDATA|CONFIG_HPS_SDR_CTRLCFG_CTRLWIDTH_CTRLWIDTH|CONFIG_HPS_SDR_CTRLCFG_CPORTWIDTH_CPORTWIDTH|CONFIG_HPS_SDR_CTRLCFG_CPORTWMAP_CPORTWMAP|CONFIG_HPS_SDR_CTRLCFG_CPORTRMAP_CPORTRMAP|CONFIG_HPS_SDR_CTRLCFG_RFIFOCMAP_RFIFOCMAP|CONFIG_HPS_SDR_CTRLCFG_WFIFOCMAP_WFIFOCMAP|CONFIG_HPS_SDR_CTRLCFG_CPORTRDWR_CPORTRDWR|CONFIG_HPS_SDR_CTRLCFG_PORTCFG_AUTOPCHEN|CONFIG_HPS_SDR_CTRLCFG_FPGAPORTRST|CONFIG_HPS_SDR_CTRLCFG_FIFOCFG_SYNCMODE|CONFIG_HPS_SDR_CTRLCFG_FIFOCFG_INCSYNC|CONFIG_HPS_SDR_CTRLCFG_MPPRIORITY_USERPRIORITY|CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_0_STATICWEIGHT_31_0|CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_STATICWEIGHT_49_32|CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_SUMOFWEIGHT_13_0|CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_2_SUMOFWEIGHT_45_14|CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_3_SUMOFWEIGHT_63_46|CONFIG_HPS_SDR_CTRLCFG_PHYCTRL_PHYCTRL_0|CONFIG_HPS_SDR_CTRLCFG_MPPACING_0_THRESHOLD1_31_0|CONFIG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD1_59_32|CONFIG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD2_3_0|CONFIG_HPS_SDR_CTRLCFG_MPPACING_2_THRESHOLD2_35_4|CONFIG_HPS_SDR_CTRLCFG_MPPACING_3_THRESHOLD2_59_36|CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0|CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32|CONFIG_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|CONFIG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR|CONFIG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_BC|CONFIG_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 CONFIG_HPS_SDR_CTRLCFG_CPORTRDWR_CPORTRDWR 0x5A56A +#define CONFIG_HPS_SDR_CTRLCFG_CPORTRMAP_CPORTRMAP 0xB00088 +#define CONFIG_HPS_SDR_CTRLCFG_CPORTWIDTH_CPORTWIDTH 0x44555 +#define CONFIG_HPS_SDR_CTRLCFG_CPORTWMAP_CPORTWMAP 0x2C011000 +#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ADDRORDER ${ADDR_ORDER} +#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_DQSTRKEN ${USE_HPS_DQS_TRACKING} +#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCCORREN ${DERIVED_ECCCORREN} +#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN ${DERIVED_ECCEN} +#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMBL ${MEM_BURST_LENGTH} +#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE ${DERIVED_MEMTYPE} +#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_NODMPINS ${DERIVED_NODMPINS} +#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_REORDEREN 1 +#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_STARVELIMIT 10 +#define CONFIG_HPS_SDR_CTRLCFG_CTRLWIDTH_CTRLWIDTH ${DERIVED_CTRLWIDTH} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_BANKBITS ${MEM_IF_BANKADDR_WIDTH} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_COLBITS ${MEM_IF_COL_ADDR_WIDTH} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_CSBITS ${DEVICE_DEPTH} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_ROWBITS ${MEM_IF_ROW_ADDR_WIDTH} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMDEVWIDTH_DEVWIDTH 8 +#define CONFIG_HPS_SDR_CTRLCFG_DRAMIFWIDTH_IFWIDTH ${MEM_DQ_WIDTH} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMINTR_INTREN 0 +#define CONFIG_HPS_SDR_CTRLCFG_DRAMODT_READ ${CFG_READ_ODT_CHIP} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMODT_WRITE ${CFG_WRITE_ODT_CHIP} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_AL 0 +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCL ${MEM_TCL} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCWL ${MEM_WTCL_INT} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TFAW ${MEM_TFAW} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRFC ${MEM_TRFC} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRRD ${MEM_TRRD} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRCD ${MEM_TRCD} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TREFI ${MEM_TREFI} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRP ${MEM_TRP} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWR ${MEM_TWR} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWTR ${MEM_TWTR} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TCCD 4 +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TMRD ${MEM_TMRD_CK} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRAS ${MEM_TRAS} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRC ${MEM_TRC} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRTP ${MEM_TRTP} +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING4_PWRDOWNEXIT 3 +#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING4_SELFRFSHEXIT ${DERIVED_SELFRFSHEXIT} +#define CONFIG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR ${DERIVED_CLK_RD_TO_WR} +#define CONFIG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_BC ${DERIVED_CLK_RD_TO_WR} +#define CONFIG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_DIFF_CHIP ${DERIVED_CLK_RD_TO_WR} +#define CONFIG_HPS_SDR_CTRLCFG_FIFOCFG_INCSYNC 0 +#define CONFIG_HPS_SDR_CTRLCFG_FIFOCFG_SYNCMODE 0 +#define CONFIG_HPS_SDR_CTRLCFG_FPGAPORTRST ${F2SDRAM_RESET_PORT_USED} +#define CONFIG_HPS_SDR_CTRLCFG_LOWPWREQ_SELFRFSHMASK 3 +#define CONFIG_HPS_SDR_CTRLCFG_LOWPWRTIMING_AUTOPDCYCLES 0 +#define CONFIG_HPS_SDR_CTRLCFG_LOWPWRTIMING_CLKDISABLECYCLES 8 +#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_0_THRESHOLD1_31_0 0x20820820 +#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD1_59_32 0x8208208 +#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD2_3_0 0 +#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_2_THRESHOLD2_35_4 0x41041041 +#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_3_THRESHOLD2_59_36 0x410410 +#define CONFIG_HPS_SDR_CTRLCFG_MPPRIORITY_USERPRIORITY 0x0 +#define CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0 0x01010101 +#define CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32 0x01010101 +#define CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64 0x0101 +#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_0_STATICWEIGHT_31_0 0x21084210 +#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_STATICWEIGHT_49_32 0x10441 +#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_SUMOFWEIGHT_13_0 0x78 +#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_2_SUMOFWEIGHT_45_14 0x0 +#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_3_SUMOFWEIGHT_63_46 0x0 +#define CONFIG_HPS_SDR_CTRLCFG_PHYCTRL_PHYCTRL_0 0x200 +#define CONFIG_HPS_SDR_CTRLCFG_PORTCFG_AUTOPCHEN 0 +#define CONFIG_HPS_SDR_CTRLCFG_RFIFOCMAP_RFIFOCMAP 0x760210 +#define CONFIG_HPS_SDR_CTRLCFG_STATICCFG_MEMBL 2 +#define CONFIG_HPS_SDR_CTRLCFG_STATICCFG_USEECCASDATA 0 +#define CONFIG_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/arch/arm/mach-socfpga/cv_bsp_generator/hps.py b/arch/arm/mach-socfpga/cv_bsp_generator/hps.py new file mode 100755 index 0000000000..68f05dc48a --- /dev/null +++ b/arch/arm/mach-socfpga/cv_bsp_generator/hps.py @@ -0,0 +1,561 @@ +# 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 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_ = "CONFIG_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': 'CONFIG_HPS_EMAC0', 'used': 0 } + p['rgmii1'] = { 'name': 'CONFIG_HPS_EMAC1', 'used': 0 } + p['usb0'] = { 'name': 'CONFIG_HPS_USB0', 'used': 0 } + p['usb1'] = { 'name': 'CONFIG_HPS_USB1', 'used': 0 } + p['nand'] = { 'name': 'CONFIG_HPS_NAND', 'used': 0 } + p['sdmmc'] = { 'name': 'CONFIG_HPS_SDMMC', 'used': 0 } + p['CONFIG_HPS_SDMMC_BUSWIDTH'] = { 'name': 'CONFIG_HPS_SDMMC_BUSWIDTH', 'used': 0 } + p['qspi'] = { 'name': 'CONFIG_HPS_QSPI', 'used': 0 } + p['CONFIG_HPS_QSPI_CS3'] = { 'name': 'CONFIG_HPS_QSPI_CS3', 'used': 0 } + p['CONFIG_HPS_QSPI_CS2'] = { 'name': 'CONFIG_HPS_QSPI_CS2', 'used': 0 } + p['CONFIG_HPS_QSPI_CS1'] = { 'name': 'CONFIG_HPS_QSPI_CS1', 'used': 0 } + p['CONFIG_HPS_QSPI_CS0'] = { 'name': 'CONFIG_HPS_QSPI_CS0', 'used': 0 } + p['uart0'] = { 'name': 'CONFIG_HPS_UART0', 'used': 0 } + p['CONFIG_HPS_UART0_TX'] = { 'name': 'CONFIG_HPS_UART0_TX', 'used': 0 } + p['CONFIG_HPS_UART0_CTS'] = { 'name': 'CONFIG_HPS_UART0_CTS', 'used': 0 } + p['CONFIG_HPS_UART0_RTS'] = { 'name': 'CONFIG_HPS_UART0_RTS', 'used': 0 } + p['CONFIG_HPS_UART0_RX'] = { 'name': 'CONFIG_HPS_UART0_RX', 'used': 0 } + p['uart1'] = { 'name': 'CONFIG_HPS_UART1', 'used': 0 } + p['CONFIG_HPS_UART1_TX'] = { 'name': 'CONFIG_HPS_UART1_TX', 'used': 0 } + p['CONFIG_HPS_UART1_CTS'] = { 'name': 'CONFIG_HPS_UART1_CTS', 'used': 0 } + p['CONFIG_HPS_UART1_RTS'] = { 'name': 'CONFIG_HPS_UART1_RTS', 'used': 0 } + p['CONFIG_HPS_UART1_RX'] = { 'name': 'CONFIG_HPS_UART1_RX', 'used': 0 } + p['trace'] = { 'name': 'CONFIG_HPS_TRACE', 'used': 0 } + p['i2c0'] = { 'name': 'CONFIG_HPS_I2C0', 'used': 0 } + p['i2c1'] = { 'name': 'CONFIG_HPS_I2C1', 'used': 0 } + p['i2c2'] = { 'name': 'CONFIG_HPS_I2C2', 'used': 0 } + p['i2c3'] = { 'name': 'CONFIG_HPS_I2C3', 'used': 0 } + p['spim0'] = { 'name': 'CONFIG_HPS_SPIM0', 'used': 0 } + p['spim1'] = { 'name': 'CONFIG_HPS_SPIM1', 'used': 0 } + p['spis0'] = { 'name': 'CONFIG_HPS_SPIS0', 'used': 0 } + p['spis1'] = { 'name': 'CONFIG_HPS_SPIS1', 'used': 0 } + p['can0'] = { 'name': 'CONFIG_HPS_CAN0', 'used': 0 } + p['can1'] = { 'name': 'CONFIG_HPS_CAN1', 'used': 0 } + + p['can1'] = { 'name': 'CONFIG_HPS_CAN1', 'used': 0 } + p['can1'] = { 'name': 'CONFIG_HPS_CAN1', 'used': 0 } + p['can1'] = { 'name': 'CONFIG_HPS_CAN1', 'used': 0 } + p['can1'] = { 'name': 'CONFIG_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 " + unicode(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( unicode("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( unicode("\t" + str(value) + ', /* ' + reg + ' */\n' )) + else: + self.pinmuxHeaderBuffer.write( unicode("\t" + str(value) + ' /* ' + reg + ' */\n' )) + + # Write the close of the pin MUX array in the header + self.pinmuxHeaderBuffer.write( unicode("};" )) + + 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 = io.StringIO() + self.pinmuxConfigBuffer = io.StringIO() + + # 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/arch/arm/mach-socfpga/cv_bsp_generator/iocsr.py b/arch/arm/mach-socfpga/cv_bsp_generator/iocsr.py new file mode 100755 index 0000000000..6aef327d32 --- /dev/null +++ b/arch/arm/mach-socfpga/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 <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 CONFIG_HPS_IOCSR_SCANCHAIN0_LENGTH\t' +\ + str(self.HPSIOCSRDataLength1) + '\n') + self.iocsrHeaderStream.write('#define CONFIG_HPS_IOCSR_SCANCHAIN1_LENGTH\t' +\ + str(self.HPSIOCSRDataLength2) + '\n') + self.iocsrHeaderStream.write('#define CONFIG_HPS_IOCSR_SCANCHAIN2_LENGTH\t' +\ + str(self.HPSIOCSRDataLength3) + '\n') + self.iocsrHeaderStream.write('#define CONFIG_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/arch/arm/mach-socfpga/cv_bsp_generator/model.py b/arch/arm/mach-socfpga/cv_bsp_generator/model.py new file mode 100755 index 0000000000..c30d6246cc --- /dev/null +++ b/arch/arm/mach-socfpga/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 <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 diff --git a/arch/arm/mach-socfpga/cv_bsp_generator/renderer.py b/arch/arm/mach-socfpga/cv_bsp_generator/renderer.py new file mode 100755 index 0000000000..70bd2a028a --- /dev/null +++ b/arch/arm/mach-socfpga/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 <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 = "CONFIG_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 = "CONFIG_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, "CONFIG_HPS_MAINPLLGRP_MPUCLK_CNT", "0") + doc.c_source.define(self.doc, "CONFIG_HPS_MAINPLLGRP_MAINCLK_CNT", "0") + doc.c_source.define(self.doc, "CONFIG_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 = "CONFIG_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 = "CONFIG_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, "CONFIG_HPS_SDRPLLGRP_VCO_DENOM", value ) + value = self.emifModel.getPllDefine("PLL_MEM_CLK_MULT") + doc.c_source.define(self.doc, "CONFIG_HPS_SDRPLLGRP_VCO_NUMER", value ) + doc.c_source.define(self.doc, "CONFIG_HPS_SDRPLLGRP_VCO_SSRC", "0") + doc.c_source.define(self.doc, "CONFIG_HPS_SDRPLLGRP_DDRDQSCLK_CNT", "1") + value = self.emifModel.getPllDefine("PLL_MEM_CLK_PHASE_DEG") + doc.c_source.define(self.doc, "CONFIG_HPS_SDRPLLGRP_DDRDQSCLK_PHASE", value ) + doc.c_source.define(self.doc, "CONFIG_HPS_SDRPLLGRP_DDR2XDQSCLK_CNT", "0") + doc.c_source.define(self.doc, "CONFIG_HPS_SDRPLLGRP_DDR2XDQSCLK_PHASE", "0") + doc.c_source.define(self.doc, "CONFIG_HPS_SDRPLLGRP_DDRDQCLK_CNT", "1") + value = self.emifModel.getPllDefine("PLL_WRITE_CLK_PHASE_DEG") + doc.c_source.define(self.doc, "CONFIG_HPS_SDRPLLGRP_DDRDQCLK_PHASE", value ) + + try: + value = self.hpsModel.getSystemConfig("sdram_pll_c5") + except ValueError: + value = "5" + doc.c_source.define(self.doc, "CONFIG_HPS_SDRPLLGRP_S2FUSER2CLK_CNT", value ) + doc.c_source.define(self.doc, "CONFIG_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 = "CONFIG_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, "CONFIG_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 = "CONFIG_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 = "CONFIG_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/arch/arm/mach-socfpga/cv_bsp_generator/streamer.py b/arch/arm/mach-socfpga/cv_bsp_generator/streamer.py new file mode 100755 index 0000000000..19c30aced6 --- /dev/null +++ b/arch/arm/mach-socfpga/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 <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 + " */")) diff --git a/arch/arm/mach-socfpga/cv_bsp_generator/xmlgrok.py b/arch/arm/mach-socfpga/cv_bsp_generator/xmlgrok.py new file mode 100755 index 0000000000..fae1d745bf --- /dev/null +++ b/arch/arm/mach-socfpga/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 <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 diff --git a/doc/README.socfpga b/doc/README.socfpga index fa4bd32c12..6d882b70c1 100644 --- a/doc/README.socfpga +++ b/doc/README.socfpga @@ -135,70 +135,21 @@ Table of Contents Generate BSP handoff files ~~~~~~~~~~~~~~~~~~~~~~~~~~ - You can run the bsp editor GUI below, or run the following command from the + You can run the py script below, or run the following command from the project directory: - $ /path/to/bsb/tools/bsp-create-settings --type spl --bsp-dir build \ - --preloader-settings-dir hps_isw_handoff/soc_system_hps_0/ \ - --settings build/settings.bsp + $ python ./arch/arm/mach-socfpga/cv_bsp_generator/cv_bsp_generator.py \ + -i <path_to_qpds_handoff>/hps_isw_handoff/soc_system_hps_0 \ + -o board/altera/cyclone5-socdk/qts/ - You should use the bsp "build" directory above (ie, where the settings.bsp file is) - in the following u-boot command to update the board headers. Once these headers - are updated for a given project build, u-boot should be configured for the - project board (eg, de0-nano-sockit) and then build the normal spl build. + The generated files are uboot-compatible. They will be located in \ + board/altera/<platform_type>/qts. These files will be used for SPL \ + generation. - Now you can skip the GUI section. + Argument: - - Using the Qsys GUI - ~~~~~~~~~~~~~~~~~~ - - 1. Navigate to your project directory - 2. Run Quartus II - 3. Open Project (Ctrl+J), select <project_name>.qpf - 4. Run QSys [Tools->QSys] - 4.1 In the Open dialog, select '<project_name>.qsys' - 4.2 In the Open System dialog, wait until completion and press 'Close' - 4.3 In the Qsys window, click on 'Generate HDL...' in bottom right corner - 4.3.1 In the 'Generation' window, click 'Generate' - 4.3.2 In the 'Generate' dialog, wait until completion and click 'Close' - 4.4 In the QSys window, click 'Finish' - 4.4.1 In the 'Quartus II' pop up window, click 'OK' - 5. Back in Quartus II main window, do the following - 5.1 Use Processing -> Start -> Start Analysis & Synthesis (Ctrl+K) - 5.2 Use Processing -> Start Compilation (Ctrl+L) - - ... this may take some time, have patience ... - - 6. Start the embedded command shell as shown in the previous section - - $ /path/to/bsb/tools/bsp-create-settings --type spl --bsp-dir build \ - --preloader-settings-dir hps_isw_handoff/soc_system_hps_0/ \ - --settings build/settings.bsp - - - Post handoff generation - ~~~~~~~~~~~~~~~~~~~~~~~ - - Now that the handoff files are generated, U-Boot can be used to process - the handoff files generated by the bsp-editor. For this, please use the - following script from the u-boot source tree: - - $ ./arch/arm/mach-socfpga/qts-filter.sh \ - <soc_type> \ - <input_qts_dir> \ - <input_bsp_dir> \ - <output_dir> - - Process QTS-generated files into U-Boot compatible ones. - - soc_type - Type of SoC, either 'cyclone5' or 'arria5'. - input_qts_dir - Directory with compiled Quartus project - and containing the Quartus project file (QPF). - input_bsp_dir - Directory with generated bsp containing - the settings.bsp file. - output_dir - Directory to store the U-Boot compatible - headers. + -i - Directory with QPDS handoff path. + -o - Directory to store the U-Boot compatible headers. This will generate (or update) the following 4 files: @@ -208,7 +159,7 @@ Table of Contents sdram_config.h These files should be copied into "qts" directory in the board directory - (see output argument of qts-filter.sh command above). + (see output argument of cv_bsp_generator.py command above). Here is an example for the DE-0 Nano SoC after the above rebuild process: |