summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKah Jing Lee <kah.jing.lee@intel.com>2022-10-02 16:36:10 +0800
committerLokanathan, Raaj <raaj.lokanathan@intel.com>2023-01-06 15:50:43 +0800
commite5d8a2774ef76b2ce72082c179d1f1b24875b926 (patch)
treecc65ef66c377659eba3214b64b8b841e294115f3
parent3c21bfbf3be6320772aabd51bebeb166a3ca89e6 (diff)
downloadu-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-xarch/arm/mach-socfpga/cv_bsp_generator/cv_bsp_generator.py100
-rwxr-xr-xarch/arm/mach-socfpga/cv_bsp_generator/doc.py243
-rwxr-xr-xarch/arm/mach-socfpga/cv_bsp_generator/emif.py424
-rwxr-xr-xarch/arm/mach-socfpga/cv_bsp_generator/hps.py561
-rwxr-xr-xarch/arm/mach-socfpga/cv_bsp_generator/iocsr.py203
-rwxr-xr-xarch/arm/mach-socfpga/cv_bsp_generator/model.py114
-rwxr-xr-xarch/arm/mach-socfpga/cv_bsp_generator/renderer.py196
-rwxr-xr-xarch/arm/mach-socfpga/cv_bsp_generator/streamer.py102
-rwxr-xr-xarch/arm/mach-socfpga/cv_bsp_generator/xmlgrok.py32
-rw-r--r--doc/README.socfpga71
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: