[PATCH v1] Cyclone V Board handsoff script
    Brian Sune 
    briansune at gmail.com
       
    Thu Oct 30 01:33:59 CET 2025
    
    
  
Since turning from old build flow.
New Altera SoCFPGA requires converting handsoff
conversion via the python script. This is from
official provided, and now sync to U-Boot
Signed-off-by: Brian Sune <briansune at gmail.com>
---
 .../cv_bsp_generator/cv_bsp_generator.py      | 100 +++
 arch/arm/mach-socfpga/cv_bsp_generator/doc.py | 243 ++++++++
 .../arm/mach-socfpga/cv_bsp_generator/emif.py | 424 +++++++++++++
 arch/arm/mach-socfpga/cv_bsp_generator/hps.py | 571 ++++++++++++++++++
 .../mach-socfpga/cv_bsp_generator/iocsr.py    | 203 +++++++
 .../mach-socfpga/cv_bsp_generator/model.py    | 114 ++++
 .../mach-socfpga/cv_bsp_generator/renderer.py | 196 ++++++
 .../mach-socfpga/cv_bsp_generator/streamer.py | 102 ++++
 .../mach-socfpga/cv_bsp_generator/xmlgrok.py  |  32 +
 9 files changed, 1985 insertions(+)
 create mode 100755 arch/arm/mach-socfpga/cv_bsp_generator/cv_bsp_generator.py
 create mode 100755 arch/arm/mach-socfpga/cv_bsp_generator/doc.py
 create mode 100755 arch/arm/mach-socfpga/cv_bsp_generator/emif.py
 create mode 100755 arch/arm/mach-socfpga/cv_bsp_generator/hps.py
 create mode 100755 arch/arm/mach-socfpga/cv_bsp_generator/iocsr.py
 create mode 100755 arch/arm/mach-socfpga/cv_bsp_generator/model.py
 create mode 100755 arch/arm/mach-socfpga/cv_bsp_generator/renderer.py
 create mode 100755 arch/arm/mach-socfpga/cv_bsp_generator/streamer.py
 create mode 100755 arch/arm/mach-socfpga/cv_bsp_generator/xmlgrok.py
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 00000000000..aff597d3978
--- /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 at 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 00000000000..86c5726c5f1
--- /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 at 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 00000000000..143bd2da550
--- /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 at 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 (CFG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE|CFG_HPS_SDR_CTRLCFG_CTRLCFG_MEMBL|CFG_HPS_SDR_CTRLCFG_CTRLCFG_ADDRORDER|CFG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN|CFG_HPS_SDR_CTRLCFG_CTRLCFG_ECCCORREN|CFG_HPS_SDR_CTRLCFG_CTRLCFG_REORDEREN|CFG_HPS_SDR_CTRLCFG_CTRLCFG_STARVELIMIT|CFG_HPS_SDR_CTRLCFG_CTRLCFG_DQSTRKEN|CFG_HPS_SDR_CTRLCFG_CTRLCFG_NODMPINS|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCWL|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_AL|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCL|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRRD|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TFAW|CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRFC|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TREFI|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRCD|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRP|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWR|CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWTR|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRTP|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRAS|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRC|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TMRD|CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TCCD|CFG_HPS_SDR_CTRLCFG_DRAMTIMING4_SELFRFSHEXIT|CFG_HPS_SDR_CTRLCFG_DRAMTIMING4_PWRDOWNEXIT|CFG_HPS_SDR_CTRLCFG_LOWPWRTIMING_AUTOPDCYCLES|CFG_HPS_SDR_CTRLCFG_LOWPWRTIMING_CLKDISABLECYCLES|CFG_HPS_SDR_CTRLCFG_DRAMODT_READ|CFG_HPS_SDR_CTRLCFG_DRAMODT_WRITE|CFG_HPS_SDR_CTRLCFG_DRAMADDRW_COLBITS|CFG_HPS_SDR_CTRLCFG_DRAMADDRW_ROWBITS|CFG_HPS_SDR_CTRLCFG_DRAMADDRW_BANKBITS|CFG_HPS_SDR_CTRLCFG_DRAMADDRW_CSBITS|CFG_HPS_SDR_CTRLCFG_DRAMIFWIDTH_IFWIDTH|CFG_HPS_SDR_CTRLCFG_DRAMDEVWIDTH_DEVWIDTH|CFG_HPS_SDR_CTRLCFG_DRAMINTR_INTREN|CFG_HPS_SDR_CTRLCFG_LOWPWREQ_SELFRFSHMASK|CFG_HPS_SDR_CTRLCFG_STATICCFG_MEMBL|CFG_HPS_SDR_CTRLCFG_STATICCFG_USEECCASDATA|CFG_HPS_SDR_CTRLCFG_CTRLWIDTH_CTRLWIDTH|CFG_HPS_SDR_CTRLCFG_CPORTWIDTH_CPORTWIDTH|CFG_HPS_SDR_CTRLCFG_CPORTWMAP_CPORTWMAP|CFG_HPS_SDR_CTRLCFG_CPORTRMAP_CPORTRMAP|CFG_HPS_SDR_CTRLCFG_RFIFOCMAP_RFIFOCMAP|CFG_HPS_SDR_CTRLCFG_WFIFOCMAP_WFIFOCMAP|CFG_HPS_SDR_CTRLCFG_CPORTRDWR_CPORTRDWR|CFG_HPS_SDR_CTRLCFG_PORTCFG_AUTOPCHEN|CFG_HPS_SDR_CTRLCFG_FPGAPORTRST|CFG_HPS_SDR_CTRLCFG_FIFOCFG_SYNCMODE|CFG_HPS_SDR_CTRLCFG_FIFOCFG_INCSYNC|CFG_HPS_SDR_CTRLCFG_MPPRIORITY_USERPRIORITY|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_0_STATICWEIGHT_31_0|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_STATICWEIGHT_49_32|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_SUMOFWEIGHT_13_0|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_2_SUMOFWEIGHT_45_14|CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_3_SUMOFWEIGHT_63_46|CFG_HPS_SDR_CTRLCFG_PHYCTRL_PHYCTRL_0|CFG_HPS_SDR_CTRLCFG_MPPACING_0_THRESHOLD1_31_0|CFG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD1_59_32|CFG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD2_3_0|CFG_HPS_SDR_CTRLCFG_MPPACING_2_THRESHOLD2_35_4|CFG_HPS_SDR_CTRLCFG_MPPACING_3_THRESHOLD2_59_36|CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0|CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32|CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64|RW_MGR_ACTIVATE_0_AND_1|RW_MGR_ACTIVATE_0_AND_1_WAIT1|RW_MGR_ACTIVATE_0_AND_1_WAIT2|RW_MGR_ACTIVATE_1|RW_MGR_CLEAR_DQS_ENABLE|RW_MGR_EMR_OCD_ENABLE|RW_MGR_EMR|RW_MGR_EMR2|RW_MGR_EMR3|RW_MGR_GUARANTEED_READ|RW_MGR_GUARANTEED_READ_CONT|RW_MGR_GUARANTEED_WRITE|RW_MGR_GUARANTEED_WRITE_WAIT0|RW_MGR_GUARANTEED_WRITE_WAIT1|RW_MGR_GUARANTEED_WRITE_WAIT2|RW_MGR_GUARANTEED_WRITE_WAIT3|RW_MGR_IDLE|RW_MGR_IDLE_LOOP1|RW_MGR_IDLE_LOOP2|RW_MGR_INIT_RESET_0_CKE_0|RW_MGR_INIT_RESET_1_CKE_0|RW_MGR_INIT_CKE_0|RW_MGR_LFSR_WR_RD_BANK_0|RW_MGR_LFSR_WR_RD_BANK_0_DATA|RW_MGR_LFSR_WR_RD_BANK_0_DQS|RW_MGR_LFSR_WR_RD_BANK_0_NOP|RW_MGR_LFSR_WR_RD_BANK_0_WAIT|RW_MGR_LFSR_WR_RD_BANK_0_WL_1|RW_MGR_LFSR_WR_RD_DM_BANK_0|RW_MGR_LFSR_WR_RD_DM_BANK_0_DATA|RW_MGR_LFSR_WR_RD_DM_BANK_0_DQS|RW_MGR_LFSR_WR_RD_DM_BANK_0_NOP|RW_MGR_LFSR_WR_RD_DM_BANK_0_WAIT|RW_MGR_LFSR_WR_RD_DM_BANK_0_WL_1|RW_MGR_MR_CALIB|RW_MGR_MR_USER|RW_MGR_MR_DLL_RESET|RW_MGR_MRS0_DLL_RESET|RW_MGR_MRS0_DLL_RESET_MIRR|RW_MGR_MRS0_USER|RW_MGR_MRS0_USER_MIRR|RW_MGR_MRS1|RW_MGR_MRS1_MIRR|RW_MGR_MRS2|RW_MGR_MRS2_MIRR|RW_MGR_MRS3|RW_MGR_MRS3_MIRR|RW_MGR_NOP|RW_MGR_PRECHARGE_ALL|RW_MGR_READ_B2B|RW_MGR_READ_B2B_WAIT1|RW_MGR_READ_B2B_WAIT2|RW_MGR_REFRESH|RW_MGR_REFRESH_ALL|RW_MGR_RETURN|RW_MGR_SGLE_READ|RW_MGR_ZQCL|RW_MGR_TRUE_MEM_DATA_MASK_WIDTH|RW_MGR_MEM_ADDRESS_MIRRORING|RW_MGR_MEM_DATA_MASK_WIDTH|RW_MGR_MEM_DATA_WIDTH|RW_MGR_MEM_DQ_PER_READ_DQS|RW_MGR_MEM_DQ_PER_WRITE_DQS|RW_MGR_MEM_IF_READ_DQS_WIDTH|RW_MGR_MEM_IF_WRITE_DQS_WIDTH|RW_MGR_MEM_NUMBER_OF_CS_PER_DIMM|RW_MGR_MEM_NUMBER_OF_RANKS|RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS|RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS|IO_DELAY_PER_DCHAIN_TAP|IO_DELAY_PER_DQS_EN_DCHAIN_TAP|IO_DELAY_PER_OPA_TAP|IO_DLL_CHAIN_LENGTH|IO_DQDQS_OUT_PHASE_MAX|IO_DQS_EN_DELAY_MAX|IO_DQS_EN_DELAY_OFFSET|IO_DQS_EN_PHASE_MAX|IO_DQS_IN_DELAY_MAX|IO_DQS_IN_RESERVE|IO_DQS_OUT_RESERVE|IO_IO_IN_DELAY_MAX|IO_IO_OUT1_DELAY_MAX|IO_IO_OUT2_DELAY_MAX|IO_SHIFT_DQS_EN_WHEN_SHIFT_DQS|AFI_RATE_RATIO|AFI_CLK_FREQ|CALIB_LFIFO_OFFSET|CALIB_VFIFO_OFFSET|ENABLE_SUPER_QUICK_CALIBRATION|MAX_LATENCY_COUNT_WIDTH|READ_VALID_FIFO_SIZE|REG_FILE_INIT_SEQ_SIGNATURE|TINIT_CNTR0_VAL|TINIT_CNTR1_VAL|TINIT_CNTR2_VAL|TRESET_CNTR0_VAL|TRESET_CNTR1_VAL|TRESET_CNTR2_VAL|CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR|CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_BC|CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_DIFF_CHIP)\s+'
+
+    SDRAM_CONFIG_H_FILENAME = "sdram_config.h"
+
+    sdramHTemplate = ""
+    seqAutoTemplate = ""
+    seqDefinesTemplate = ""
+    seqAutoAcTemplate = ""
+    seqAutoInstTemplate = ""
+    seqAutoTemplateList = []
+    seqDefinesTemplateList = []
+    seqAutoAcTemplateList = []
+    seqAutoInstTemplateList = []
+
+    def __init__(self, inputDir, outputDir, emifFileName='emif.xml', hpsFileName='hps.xml'):
+        """ EMIFGrokker initialization """
+        self.inputDir = inputDir
+        self.outputDir = outputDir
+
+        sdramDir = self.outputDir
+        if not os.path.isdir(sdramDir):
+            os.makedirs(sdramDir)
+
+        self.emifFileName = inputDir + os.sep + emifFileName
+        self.hpsFileName = inputDir + os.sep + hpsFileName
+        self.emifDom = xml.dom.minidom.parse(self.emifFileName)
+        self.hpsDom = xml.dom.minidom.parse(self.hpsFileName)
+        self.sequencerDefinesStream = None
+        self.seqAutoFileName = inputDir + os.sep +  "sequencer_auto.h"
+        self.seqDefinesFileName = inputDir + os.sep + "sequencer_defines.h"
+        self.seqAutoACFileName = inputDir + os.sep + "sequencer_auto_ac_init.c"
+        self.seqAutoInstFileName = inputDir + os.sep + "sequencer_auto_inst_init.c"
+
+        self.createFilesFromEMIF()
+
+    def openSeqFiles(self):
+        """ files to retrieve values to written to sdram_config.h """
+        self.seq_auto_fd = open(self.seqAutoFileName, "r")
+        self.seq_defines_fd = open(self.seqDefinesFileName, "r")
+        self.seq_auto_ac_fd = open(self.seqAutoACFileName, "r")
+        self.seq_auto_inst_fd = open(self.seqAutoInstFileName, "r")
+
+    def closeSeqFiles(self):
+        """ close files """
+        self.seq_auto_fd.close()
+        self.seq_defines_fd.close()
+        self.seq_auto_ac_fd.close()
+        self.seq_auto_inst_fd.close()
+
+    def processSeqAuto(self):
+        """ process sequencer files to retrieve variable. Regex match is from
+        qts-filter.sh
+        """
+        # replace underscore & bracket in sequencer_auto.h define
+        for line in self.seq_auto_fd.readlines():
+            if re.match(".*__RW_MGR_", line) and not re.match(".*ac_", line) and not re.match(".*CONTENT_", line):
+                line = re.sub("__RW_MGR", "RW_MGR", line)
+                if re.match(self.SDRAM_MATCH, line):
+                    self.seqAutoTemplateList.append(re.sub(r' (\w+)(\s+)(\d+)', r' \1\t\3', line))
+        self.seqAutoTemplateList.sort()
+        self.seqAutoTemplate = ''.join([item for item in self.seqAutoTemplateList])
+
+        # replace underscore & bracket in sequencer_defines.h define
+        for line in self.seq_defines_fd.readlines():
+            if re.match("^#define (\w+_)", line):
+                line = re.sub("__", "", line)
+                if re.match(self.SDRAM_MATCH, line):
+                    self.seqDefinesTemplateList.append(re.sub(r' (\w+)(\s+)(\d+)', r' \1\t\3', line))
+        self.seqDefinesTemplateList.sort()
+        self.seqDefinesTemplate = ''.join([item for item in self.seqDefinesTemplateList])
+
+        arrayMatchStart = 0
+        # replace const variable declaration in sequencer_auto_ac_init.c
+        for line in self.seq_auto_ac_fd.readlines():
+            if re.match("^const.*\[", line) or arrayMatchStart:
+                if arrayMatchStart == 0:
+                    line = line.strip() + " "
+                arrayMatchStart = 1
+                if re.match("};", line):
+                    arrayMatchStart = 0
+                    self.seqAutoAcTemplateList.append("};")
+                    continue
+                line = re.sub("alt_u32", "u32", line)
+                self.seqAutoAcTemplateList.append(re.sub("\[.*\]", "[]", line))
+        self.seqAutoAcTemplate = ''.join([item for item in self.seqAutoAcTemplateList])
+
+        arrayMatchStart = 0
+        # replace const variable declaration in sequencer_auto_inst_init.c
+        for line in self.seq_auto_inst_fd.readlines():
+            if re.match("^const.*\[", line) or arrayMatchStart:
+                if arrayMatchStart == 0:
+                    line = line.strip() + " "
+                arrayMatchStart = 1
+                if re.match("};", line):
+                    arrayMatchStart = 0
+                    self.seqAutoInstTemplateList.append("};")
+                    continue
+                line = re.sub("alt_u32", "u32", line)
+                self.seqAutoInstTemplateList.append(re.sub("\[.*\]", "[]", line))
+        self.seqAutoInstTemplate = ''.join([item for item in self.seqAutoInstTemplateList])
+
+    def handleSettingNode(self, settingNode):
+        """ create define string from variable name and value """
+        if settingNode.hasAttribute('name') and settingNode.hasAttribute('value'):
+            name = settingNode.getAttribute('name')
+            value = settingNode.getAttribute('value')
+            self.sequencerDefinesStream.write("#define " + name + ' ' + '(' + value + ')' + '\n')
+
+    def updateTemplate(self, name, value):
+        """ update sdram template """
+        pattern = "${" + name + "}"
+        self.sdramHTemplate = self.sdramHTemplate.replace(pattern, value)
+
+    def handleEMIFControllerNode(self, node):
+        """ retrieve values from emif.xml for controller node """
+        derivedNoDmPins = 0
+        derivedCtrlWidth = 0
+        derivedEccEn = 0
+        derivedEccCorrEn = 0
+
+        self.mem_if_rd_to_wr_turnaround_oct = 0
+
+        node = xmlgrok.firstElementChild(node)
+        while node != None:
+            name = node.getAttribute('name')
+            value = node.getAttribute('value')
+
+            if value == "true":
+                value = "1"
+            elif value == "false":
+                value = "0"
+
+            self.updateTemplate(name, value)
+
+            if name == "MEM_IF_DM_PINS_EN":
+                if value == "1":
+                    derivedNoDmPins = 0
+                else:
+                    derivedNoDmPins = 1
+
+            if name == "MEM_DQ_WIDTH":
+                if value == "8":
+                    derivedCtrlWidth = 0
+                    derivedEccEn = 0
+                    derivedEccCorrEn = 0
+                elif value == "16":
+                    derivedCtrlWidth = 1
+                    derivedEccEn = 0
+                    derivedEccCorrEn = 0
+                elif value == "24":
+                    derivedCtrlWidth = 1
+                    derivedEccEn = 1
+                    derivedEccCorrEn = 1
+                elif value == "32":
+                    derivedCtrlWidth = 2
+                    derivedEccEn = 0
+                    derivedEccCorrEn = 0
+                elif value == "40":
+                    derivedCtrlWidth = 2
+                    derivedEccEn = 1
+                    derivedEccCorrEn = 1
+
+            if name == "MEM_IF_RD_TO_WR_TURNAROUND_OCT":
+                self.mem_if_rd_to_wr_turnaround_oct = int(value)
+
+            node = xmlgrok.nextElementSibling(node)
+
+        self.updateTemplate("DERIVED_NODMPINS", str(derivedNoDmPins))
+        self.updateTemplate("DERIVED_CTRLWIDTH", str(derivedCtrlWidth))
+        self.updateTemplate("DERIVED_ECCEN", str(derivedEccEn))
+        self.updateTemplate("DERIVED_ECCCORREN", str(derivedEccCorrEn))
+
+    def handleEMIFPllNode(self, node):
+        """ retrieve values for pll node """
+        node = xmlgrok.firstElementChild(node)
+        while node != None:
+            name = node.getAttribute('name')
+            value = node.getAttribute('value')
+
+            self.updateTemplate(name, value)
+
+            node = xmlgrok.nextElementSibling(node)
+
+    def handleEMIFSequencerNode(self, node):
+        """ retrieve values for sequencer node """
+        derivedMemtype = 0
+        derivedSelfrfshexit = 0
+
+        self.afi_rate_ratio = 0
+
+        node = xmlgrok.firstElementChild(node)
+        while node != None:
+            name = node.getAttribute('name')
+            value = node.getAttribute('value')
+
+            self.updateTemplate(name, value)
+
+            if value.isdigit():
+                intValue = int(value)
+            else:
+                intValue = 0
+
+            if name == "DDR2" and intValue != 0:
+                derivedMemtype = 1
+                derivedSelfrfshexit = 200
+            elif name == "DDR3" and intValue != 0:
+                derivedMemtype = 2
+                derivedSelfrfshexit = 512
+            elif name == "LPDDR1" and intValue != 0:
+                derivedMemtype = 3
+                derivedSelfrfshexit = 200
+            elif name == "LPDDR2" and intValue != 0:
+                derivedMemtype = 4
+                derivedSelfrfshexit = 200
+            elif name == "AFI_RATE_RATIO" and intValue != 0:
+                self.afi_rate_ratio = intValue
+
+            node = xmlgrok.nextElementSibling(node)
+
+        self.updateTemplate("DERIVED_MEMTYPE", str(derivedMemtype))
+        self.updateTemplate("DERIVED_SELFRFSHEXIT", str(derivedSelfrfshexit))
+
+
+    def handleHpsFpgaInterfaces(self, node):
+        """ retrieve values for fpga interface """
+        node = xmlgrok.firstElementChild(node)
+
+        while node != None:
+            name = node.getAttribute('name')
+            value = node.getAttribute('value')
+
+            self.updateTemplate(name, value)
+
+            node = xmlgrok.nextElementSibling(node)
+
+
+    def createFilesFromEMIF(self):
+        """ create sdram_config.h with the template and value read from xml.
+        Different sequencer files are written to individual section, with
+        comment at the start.
+        """
+        self.sdramHTemplate ="""\
+#define CFG_HPS_SDR_CTRLCFG_CPORTRDWR_CPORTRDWR		0x5A56A
+#define CFG_HPS_SDR_CTRLCFG_CPORTRMAP_CPORTRMAP		0xB00088
+#define CFG_HPS_SDR_CTRLCFG_CPORTWIDTH_CPORTWIDTH		0x44555
+#define CFG_HPS_SDR_CTRLCFG_CPORTWMAP_CPORTWMAP		0x2C011000
+#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_ADDRORDER		${ADDR_ORDER}
+#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_DQSTRKEN			${USE_HPS_DQS_TRACKING}
+#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_ECCCORREN		${DERIVED_ECCCORREN}
+#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN			${DERIVED_ECCEN}
+#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_MEMBL			${MEM_BURST_LENGTH}
+#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE			${DERIVED_MEMTYPE}
+#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_NODMPINS			${DERIVED_NODMPINS}
+#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_REORDEREN		1
+#define CFG_HPS_SDR_CTRLCFG_CTRLCFG_STARVELIMIT		10
+#define CFG_HPS_SDR_CTRLCFG_CTRLWIDTH_CTRLWIDTH		${DERIVED_CTRLWIDTH}
+#define CFG_HPS_SDR_CTRLCFG_DRAMADDRW_BANKBITS		${MEM_IF_BANKADDR_WIDTH}
+#define CFG_HPS_SDR_CTRLCFG_DRAMADDRW_COLBITS		${MEM_IF_COL_ADDR_WIDTH}
+#define CFG_HPS_SDR_CTRLCFG_DRAMADDRW_CSBITS			${DEVICE_DEPTH}
+#define CFG_HPS_SDR_CTRLCFG_DRAMADDRW_ROWBITS		${MEM_IF_ROW_ADDR_WIDTH}
+#define CFG_HPS_SDR_CTRLCFG_DRAMDEVWIDTH_DEVWIDTH		8
+#define CFG_HPS_SDR_CTRLCFG_DRAMIFWIDTH_IFWIDTH		${MEM_DQ_WIDTH}
+#define CFG_HPS_SDR_CTRLCFG_DRAMINTR_INTREN			0
+#define CFG_HPS_SDR_CTRLCFG_DRAMODT_READ			${CFG_READ_ODT_CHIP}
+#define CFG_HPS_SDR_CTRLCFG_DRAMODT_WRITE			${CFG_WRITE_ODT_CHIP}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_AL			0
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCL			${MEM_TCL}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCWL			${MEM_WTCL_INT}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TFAW			${MEM_TFAW}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRFC			${MEM_TRFC}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRRD			${MEM_TRRD}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRCD		${MEM_TRCD}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TREFI		${MEM_TREFI}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRP		${MEM_TRP}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWR		${MEM_TWR}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWTR		${MEM_TWTR}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TCCD			4
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TMRD			${MEM_TMRD_CK}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRAS			${MEM_TRAS}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRC			${MEM_TRC}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRTP			${MEM_TRTP}
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING4_PWRDOWNEXIT		3
+#define CFG_HPS_SDR_CTRLCFG_DRAMTIMING4_SELFRFSHEXIT		${DERIVED_SELFRFSHEXIT}
+#define CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR ${DERIVED_CLK_RD_TO_WR}
+#define CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_BC ${DERIVED_CLK_RD_TO_WR}
+#define CFG_HPS_SDR_CTRLCFG_EXTRATIME1_CFG_EXTRA_CTL_CLK_RD_TO_WR_DIFF_CHIP ${DERIVED_CLK_RD_TO_WR}
+#define CFG_HPS_SDR_CTRLCFG_FIFOCFG_INCSYNC			0
+#define CFG_HPS_SDR_CTRLCFG_FIFOCFG_SYNCMODE			0
+#define CFG_HPS_SDR_CTRLCFG_FPGAPORTRST			${F2SDRAM_RESET_PORT_USED}
+#define CFG_HPS_SDR_CTRLCFG_LOWPWREQ_SELFRFSHMASK		3
+#define CFG_HPS_SDR_CTRLCFG_LOWPWRTIMING_AUTOPDCYCLES	0
+#define CFG_HPS_SDR_CTRLCFG_LOWPWRTIMING_CLKDISABLECYCLES	8
+#define CFG_HPS_SDR_CTRLCFG_MPPACING_0_THRESHOLD1_31_0	0x20820820
+#define CFG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD1_59_32	0x8208208
+#define CFG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD2_3_0	0
+#define CFG_HPS_SDR_CTRLCFG_MPPACING_2_THRESHOLD2_35_4	0x41041041
+#define CFG_HPS_SDR_CTRLCFG_MPPACING_3_THRESHOLD2_59_36	0x410410
+#define CFG_HPS_SDR_CTRLCFG_MPPRIORITY_USERPRIORITY		0x0
+#define CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0 0x01010101
+#define CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32 0x01010101
+#define CFG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64 0x0101
+#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_0_STATICWEIGHT_31_0	0x21084210
+#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_STATICWEIGHT_49_32	0x10441
+#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_SUMOFWEIGHT_13_0	0x78
+#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_2_SUMOFWEIGHT_45_14	0x0
+#define CFG_HPS_SDR_CTRLCFG_MPWIEIGHT_3_SUMOFWEIGHT_63_46	0x0
+#define CFG_HPS_SDR_CTRLCFG_PHYCTRL_PHYCTRL_0		0x200
+#define CFG_HPS_SDR_CTRLCFG_PORTCFG_AUTOPCHEN		0
+#define CFG_HPS_SDR_CTRLCFG_RFIFOCMAP_RFIFOCMAP		0x760210
+#define CFG_HPS_SDR_CTRLCFG_STATICCFG_MEMBL			2
+#define CFG_HPS_SDR_CTRLCFG_STATICCFG_USEECCASDATA		0
+#define CFG_HPS_SDR_CTRLCFG_WFIFOCMAP_WFIFOCMAP		0x980543
+"""
+
+        # Get a list of all nodes with the emif element name
+        emifNodeList = self.emifDom.getElementsByTagName('emif')
+        if len(emifNodeList) > 1:
+            print ("*** WARNING:" + "Multiple emif Elements found in %s!" % self.emifFileName)
+        # For each of the emif element nodes, go through the child list
+        # Note that currently there is only one emif Element
+        # but this code will handle more than one emif node
+        # In the future, multiple emif nodes may need additional code
+        # to combine settings from the multiple emif Elements
+        for emifNode in emifNodeList:
+            # Currently, there are only 3 children of the emif Element:
+            #     sequencer, controller, and pll
+            # but this is left open-ended for future additions to the
+            # specification for the emif.xml
+            childNode = xmlgrok.firstElementChild(emifNode)
+            while childNode != None:
+
+                if childNode.nodeName == 'controller':
+                    self.handleEMIFControllerNode(childNode)
+                elif childNode.nodeName == 'sequencer':
+                    self.handleEMIFSequencerNode(childNode)
+                elif childNode.nodeName == 'pll':
+                    self.handleEMIFPllNode(childNode)
+
+                childNode = xmlgrok.nextElementSibling(childNode)
+
+        data_rate_ratio = 2
+        dwidth_ratio = self.afi_rate_ratio * data_rate_ratio
+        if dwidth_ratio == 0:
+            derivedClkRdToWr = 0
+        else:
+            derivedClkRdToWr = (self.mem_if_rd_to_wr_turnaround_oct / (dwidth_ratio / 2))
+
+            if (self.mem_if_rd_to_wr_turnaround_oct % (dwidth_ratio / 2)) > 0:
+                derivedClkRdToWr += 1
+
+        self.updateTemplate("DERIVED_CLK_RD_TO_WR", str(int(derivedClkRdToWr)))
+
+        # MPFE information are stored in hps.xml despite we generate
+        # them into sdram_config, so let's load hps.xml
+        hpsNodeList = self.hpsDom.getElementsByTagName('hps')
+
+        for hpsNode in hpsNodeList:
+
+            childNode = xmlgrok.firstElementChild(hpsNode)
+
+            while childNode != None:
+                # MPFE info is part of fpga_interfaces
+                if childNode.nodeName == 'fpga_interfaces':
+                    self.handleHpsFpgaInterfaces(childNode)
+
+                childNode = xmlgrok.nextElementSibling(childNode)
+
+        self.sequencerDefinesStream = streamer.Streamer(self.outputDir + os.sep + EMIFGrokker.SDRAM_CONFIG_H_FILENAME, 'w')
+        self.sequencerDefinesStream.open()
+        self.sequencerDefinesStream.writeLicenseHeader()
+        self.sequencerDefinesStream.write(EMIFGrokker.SDRAM_FILE_HEADER)
+        ret = self.sequencerDefinesStream.writeSentinelStart(EMIFGrokker.SDRAM_SENTINEL)
+        if ret == -1:
+            print("Empty header written. Exiting.")
+        self.sequencerDefinesStream.write("/* SDRAM configuration */\n")
+        self.sequencerDefinesStream.write(self.sdramHTemplate)
+        self.openSeqFiles()
+        self.processSeqAuto()
+
+        self.sequencerDefinesStream.write("\n")
+        self.sequencerDefinesStream.write("/* Sequencer auto configuration */\n")
+        self.sequencerDefinesStream.write(self.seqAutoTemplate)
+        self.sequencerDefinesStream.write("\n")
+        self.sequencerDefinesStream.write("/* Sequencer defines configuration */\n")
+        self.sequencerDefinesStream.write(self.seqDefinesTemplate)
+        self.sequencerDefinesStream.write("\n")
+        self.sequencerDefinesStream.write("/* Sequencer ac_rom_init configuration */\n")
+        self.sequencerDefinesStream.write(self.seqAutoAcTemplate)
+        self.sequencerDefinesStream.write("\n\n")
+        self.sequencerDefinesStream.write("/* Sequencer inst_rom_init configuration */\n")
+        self.sequencerDefinesStream.write(self.seqAutoInstTemplate)
+        self.sequencerDefinesStream.write("\n")
+
+        ret = self.sequencerDefinesStream.writeSentinelEnd(EMIFGrokker.SDRAM_SENTINEL)
+        if ret == -1:
+            print("Empty header written. Exiting.")
+        self.sequencerDefinesStream.close()
+        self.closeSeqFiles()
diff --git a/arch/arm/mach-socfpga/cv_bsp_generator/hps.py b/arch/arm/mach-socfpga/cv_bsp_generator/hps.py
new file mode 100755
index 00000000000..d702c5b4891
--- /dev/null
+++ b/arch/arm/mach-socfpga/cv_bsp_generator/hps.py
@@ -0,0 +1,571 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+"""
+Pinmux header file generator
+
+Process the hps.xml from Quartus and convert them to headers
+usable by U-Boot.
+
+Copyright (C) 2022 Intel Corporation <www.intel.com>
+
+Author: Lee, Kah Jing <kah.jing.lee at intel.com>
+"""
+import os
+import re
+import streamer
+import xmlgrok
+import xml.dom.minidom
+import collections
+import io
+from io import StringIO
+
+class CompatStringIO(io.StringIO):
+    def write(self, s):
+        if hasattr(s, 'decode'):
+            # Use unicode for python2 to keep compatible
+            return int(super(CompatStringIO, self).write(s.decode('utf-8')))
+        else:
+            return super(CompatStringIO, self).write(s)
+    def getvalue(self):
+        return str(super(CompatStringIO, self).getvalue())
+
+class HPSGrokker(object):
+
+    SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
+    TEMPLATE_DIR = os.path.dirname(SCRIPT_DIR) + '/src'
+
+    MAKEFILE_FILENAME = "Makefile"
+    makefileTemplate = ""
+    RESET_CONFIG_H_FILENAME = "reset_config.h"
+    resetConfigHTemplate = ""
+
+    # If no device family is specified, assume Cyclone V.
+    derivedDeviceFamily = "cyclone5"
+
+    # Assume FPGA DMA 0-7 are not in use by default
+    # Note: there appears to be a weird mismatch between sopcinfo
+    # value vs hps.xml value of DMA_Enable of string_list hw.tcl
+    # type, where sopcinfo uses comma as separator e.g.
+    # "No,No,No,..." while hps.xml uses space as separator.
+    dmaEnable = "No No No No No No No No"
+
+    def __init__(self, inputDir, outputDir, hpsFileName='hps.xml'):
+        """ HPSGrokker initialization """
+        self.inputDir = inputDir
+        self.outputDir = outputDir
+        self.hpsInFileName = inputDir + os.sep + hpsFileName
+        self.dom = xml.dom.minidom.parse(self.hpsInFileName)
+        self.peripheralStream = None
+        self.pinmuxConfigBuffer = None
+        self.pinmuxHeaderBuffer = None
+        self.pinmuxHeaderFile = None
+        self.pinmuxArraySize = 0
+        self.config_hps_ = "CFG_HPS_"
+        self.clockStream = None
+        self.pinmux_regs = self.get_default_pinmux_regs()
+        self.pinmux_configs = self.get_default_pinmux_configs()
+        self.pinmux_config_h = None
+
+        self.createFilesFromHPS()
+
+    def get_default_pinmux_regs(self):
+        """ Set default pinmux values """
+        p = collections.OrderedDict()
+
+        p['EMACIO0'] = 0
+        p['EMACIO1'] = 0
+        p['EMACIO2'] = 0
+        p['EMACIO3'] = 0
+        p['EMACIO4'] = 0
+        p['EMACIO5'] = 0
+        p['EMACIO6'] = 0
+        p['EMACIO7'] = 0
+        p['EMACIO8'] = 0
+        p['EMACIO9'] = 0
+        p['EMACIO10'] = 0
+        p['EMACIO11'] = 0
+        p['EMACIO12'] = 0
+        p['EMACIO13'] = 0
+        p['EMACIO14'] = 0
+        p['EMACIO15'] = 0
+        p['EMACIO16'] = 0
+        p['EMACIO17'] = 0
+        p['EMACIO18'] = 0
+        p['EMACIO19'] = 0
+        p['FLASHIO0'] = 0
+        p['FLASHIO1'] = 0
+        p['FLASHIO2'] = 0
+        p['FLASHIO3'] = 0
+        p['FLASHIO4'] = 0
+        p['FLASHIO5'] = 0
+        p['FLASHIO6'] = 0
+        p['FLASHIO7'] = 0
+        p['FLASHIO8'] = 0
+        p['FLASHIO9'] = 0
+        p['FLASHIO10'] = 0
+        p['FLASHIO11'] = 0
+        p['GENERALIO0'] = 0
+        p['GENERALIO1'] = 0
+        p['GENERALIO2'] = 0
+        p['GENERALIO3'] = 0
+        p['GENERALIO4'] = 0
+        p['GENERALIO5'] = 0
+        p['GENERALIO6'] = 0
+        p['GENERALIO7'] = 0
+        p['GENERALIO8'] = 0
+        p['GENERALIO9'] = 0
+        p['GENERALIO10'] = 0
+        p['GENERALIO11'] = 0
+        p['GENERALIO12'] = 0
+        p['GENERALIO13'] = 0
+        p['GENERALIO14'] = 0
+        p['GENERALIO15'] = 0
+        p['GENERALIO16'] = 0
+        p['GENERALIO17'] = 0
+        p['GENERALIO18'] = 0
+        p['GENERALIO19'] = 0
+        p['GENERALIO20'] = 0
+        p['GENERALIO21'] = 0
+        p['GENERALIO22'] = 0
+        p['GENERALIO23'] = 0
+        p['GENERALIO24'] = 0
+        p['GENERALIO25'] = 0
+        p['GENERALIO26'] = 0
+        p['GENERALIO27'] = 0
+        p['GENERALIO28'] = 0
+        p['GENERALIO29'] = 0
+        p['GENERALIO30'] = 0
+        p['GENERALIO31'] = 0
+        p['MIXED1IO0'] = 0
+        p['MIXED1IO1'] = 0
+        p['MIXED1IO2'] = 0
+        p['MIXED1IO3'] = 0
+        p['MIXED1IO4'] = 0
+        p['MIXED1IO5'] = 0
+        p['MIXED1IO6'] = 0
+        p['MIXED1IO7'] = 0
+        p['MIXED1IO8'] = 0
+        p['MIXED1IO9'] = 0
+        p['MIXED1IO10'] = 0
+        p['MIXED1IO11'] = 0
+        p['MIXED1IO12'] = 0
+        p['MIXED1IO13'] = 0
+        p['MIXED1IO14'] = 0
+        p['MIXED1IO15'] = 0
+        p['MIXED1IO16'] = 0
+        p['MIXED1IO17'] = 0
+        p['MIXED1IO18'] = 0
+        p['MIXED1IO19'] = 0
+        p['MIXED1IO20'] = 0
+        p['MIXED1IO21'] = 0
+        p['MIXED2IO0'] = 0
+        p['MIXED2IO1'] = 0
+        p['MIXED2IO2'] = 0
+        p['MIXED2IO3'] = 0
+        p['MIXED2IO4'] = 0
+        p['MIXED2IO5'] = 0
+        p['MIXED2IO6'] = 0
+        p['MIXED2IO7'] = 0
+        p['GPLINMUX48'] = 0
+        p['GPLINMUX49'] = 0
+        p['GPLINMUX50'] = 0
+        p['GPLINMUX51'] = 0
+        p['GPLINMUX52'] = 0
+        p['GPLINMUX53'] = 0
+        p['GPLINMUX54'] = 0
+        p['GPLINMUX55'] = 0
+        p['GPLINMUX56'] = 0
+        p['GPLINMUX57'] = 0
+        p['GPLINMUX58'] = 0
+        p['GPLINMUX59'] = 0
+        p['GPLINMUX60'] = 0
+        p['GPLINMUX61'] = 0
+        p['GPLINMUX62'] = 0
+        p['GPLINMUX63'] = 0
+        p['GPLINMUX64'] = 0
+        p['GPLINMUX65'] = 0
+        p['GPLINMUX66'] = 0
+        p['GPLINMUX67'] = 0
+        p['GPLINMUX68'] = 0
+        p['GPLINMUX69'] = 0
+        p['GPLINMUX70'] = 0
+        p['GPLMUX0'] = 1
+        p['GPLMUX1'] = 1
+        p['GPLMUX2'] = 1
+        p['GPLMUX3'] = 1
+        p['GPLMUX4'] = 1
+        p['GPLMUX5'] = 1
+        p['GPLMUX6'] = 1
+        p['GPLMUX7'] = 1
+        p['GPLMUX8'] = 1
+        p['GPLMUX9'] = 1
+        p['GPLMUX10'] = 1
+        p['GPLMUX11'] = 1
+        p['GPLMUX12'] = 1
+        p['GPLMUX13'] = 1
+        p['GPLMUX14'] = 1
+        p['GPLMUX15'] = 1
+        p['GPLMUX16'] = 1
+        p['GPLMUX17'] = 1
+        p['GPLMUX18'] = 1
+        p['GPLMUX19'] = 1
+        p['GPLMUX20'] = 1
+        p['GPLMUX21'] = 1
+        p['GPLMUX22'] = 1
+        p['GPLMUX23'] = 1
+        p['GPLMUX24'] = 1
+        p['GPLMUX25'] = 1
+        p['GPLMUX26'] = 1
+        p['GPLMUX27'] = 1
+        p['GPLMUX28'] = 1
+        p['GPLMUX29'] = 1
+        p['GPLMUX30'] = 1
+        p['GPLMUX31'] = 1
+        p['GPLMUX32'] = 1
+        p['GPLMUX33'] = 1
+        p['GPLMUX34'] = 1
+        p['GPLMUX35'] = 1
+        p['GPLMUX36'] = 1
+        p['GPLMUX37'] = 1
+        p['GPLMUX38'] = 1
+        p['GPLMUX39'] = 1
+        p['GPLMUX40'] = 1
+        p['GPLMUX41'] = 1
+        p['GPLMUX42'] = 1
+        p['GPLMUX43'] = 1
+        p['GPLMUX44'] = 1
+        p['GPLMUX45'] = 1
+        p['GPLMUX46'] = 1
+        p['GPLMUX47'] = 1
+        p['GPLMUX48'] = 1
+        p['GPLMUX49'] = 1
+        p['GPLMUX50'] = 1
+        p['GPLMUX51'] = 1
+        p['GPLMUX52'] = 1
+        p['GPLMUX53'] = 1
+        p['GPLMUX54'] = 1
+        p['GPLMUX55'] = 1
+        p['GPLMUX56'] = 1
+        p['GPLMUX57'] = 1
+        p['GPLMUX58'] = 1
+        p['GPLMUX59'] = 1
+        p['GPLMUX60'] = 1
+        p['GPLMUX61'] = 1
+        p['GPLMUX62'] = 1
+        p['GPLMUX63'] = 1
+        p['GPLMUX64'] = 1
+        p['GPLMUX65'] = 1
+        p['GPLMUX66'] = 1
+        p['GPLMUX67'] = 1
+        p['GPLMUX68'] = 1
+        p['GPLMUX69'] = 1
+        p['GPLMUX70'] = 1
+        p['NANDUSEFPGA'] = 0
+        p['UART0USEFPGA'] = 0
+        p['RGMII1USEFPGA'] = 0
+        p['SPIS0USEFPGA'] = 0
+        p['CAN0USEFPGA'] = 0
+        p['I2C0USEFPGA'] = 0
+        p['SDMMCUSEFPGA'] = 0
+        p['QSPIUSEFPGA'] = 0
+        p['SPIS1USEFPGA'] = 0
+        p['RGMII0USEFPGA'] = 0
+        p['UART1USEFPGA'] = 0
+        p['CAN1USEFPGA'] = 0
+        p['USB1USEFPGA'] = 0
+        p['I2C3USEFPGA'] = 0
+        p['I2C2USEFPGA'] = 0
+        p['I2C1USEFPGA'] = 0
+        p['SPIM1USEFPGA'] = 0
+        p['USB0USEFPGA'] = 0
+        p['SPIM0USEFPGA'] = 0
+
+        return p
+
+
+    def get_default_pinmux_configs(self):
+        """ Get default pinmux values """
+        p = collections.OrderedDict()
+
+        p['rgmii0'] = { 'name': 'CFG_HPS_EMAC0', 'used': 0 }
+        p['rgmii1'] = { 'name': 'CFG_HPS_EMAC1', 'used': 0 }
+        p['usb0'] = { 'name': 'CFG_HPS_USB0', 'used': 0 }
+        p['usb1'] = { 'name': 'CFG_HPS_USB1', 'used': 0 }
+        p['nand'] = { 'name': 'CFG_HPS_NAND', 'used': 0 }
+        p['sdmmc'] = { 'name': 'CFG_HPS_SDMMC', 'used': 0 }
+        p['CFG_HPS_SDMMC_BUSWIDTH'] = { 'name': 'CFG_HPS_SDMMC_BUSWIDTH', 'used': 0 }
+        p['qspi'] = { 'name': 'CFG_HPS_QSPI', 'used': 0 }
+        p['CFG_HPS_QSPI_CS3'] = { 'name': 'CFG_HPS_QSPI_CS3', 'used': 0 }
+        p['CFG_HPS_QSPI_CS2'] = { 'name': 'CFG_HPS_QSPI_CS2', 'used': 0 }
+        p['CFG_HPS_QSPI_CS1'] = { 'name': 'CFG_HPS_QSPI_CS1', 'used': 0 }
+        p['CFG_HPS_QSPI_CS0'] = { 'name': 'CFG_HPS_QSPI_CS0', 'used': 0 }
+        p['uart0'] = { 'name': 'CFG_HPS_UART0', 'used': 0 }
+        p['CFG_HPS_UART0_TX'] = { 'name': 'CFG_HPS_UART0_TX', 'used': 0 }
+        p['CFG_HPS_UART0_CTS'] = { 'name': 'CFG_HPS_UART0_CTS', 'used': 0 }
+        p['CFG_HPS_UART0_RTS'] = { 'name': 'CFG_HPS_UART0_RTS', 'used': 0 }
+        p['CFG_HPS_UART0_RX'] = { 'name': 'CFG_HPS_UART0_RX', 'used': 0 }
+        p['uart1'] = { 'name': 'CFG_HPS_UART1', 'used': 0 }
+        p['CFG_HPS_UART1_TX'] = { 'name': 'CFG_HPS_UART1_TX', 'used': 0 }
+        p['CFG_HPS_UART1_CTS'] = { 'name': 'CFG_HPS_UART1_CTS', 'used': 0 }
+        p['CFG_HPS_UART1_RTS'] = { 'name': 'CFG_HPS_UART1_RTS', 'used': 0 }
+        p['CFG_HPS_UART1_RX'] = { 'name': 'CFG_HPS_UART1_RX', 'used': 0 }
+        p['trace'] = { 'name': 'CFG_HPS_TRACE', 'used': 0 }
+        p['i2c0'] = { 'name': 'CFG_HPS_I2C0', 'used': 0 }
+        p['i2c1'] = { 'name': 'CFG_HPS_I2C1', 'used': 0 }
+        p['i2c2'] = { 'name': 'CFG_HPS_I2C2', 'used': 0 }
+        p['i2c3'] = { 'name': 'CFG_HPS_I2C3', 'used': 0 }
+        p['spim0'] = { 'name': 'CFG_HPS_SPIM0', 'used': 0 }
+        p['spim1'] = { 'name': 'CFG_HPS_SPIM1', 'used': 0 }
+        p['spis0'] = { 'name': 'CFG_HPS_SPIS0', 'used': 0 }
+        p['spis1'] = { 'name': 'CFG_HPS_SPIS1', 'used': 0 }
+        p['can0'] = { 'name': 'CFG_HPS_CAN0', 'used': 0 }
+        p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
+
+        p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
+        p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
+        p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
+        p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
+
+        return p
+
+    def updateTemplate(self, name, value):
+        """ Update Makefile & reset_config.h """
+        pattern = "${" + name + "}"
+        self.makefileTemplate = self.makefileTemplate.replace(pattern, value)
+        self.resetConfigHTemplate = self.resetConfigHTemplate.replace(pattern, value)
+
+    def romanToInteger(self, roman):
+        """
+        Convert roman numerals to integer
+        Since we only support I,V,X, the
+        supported range is 1-39
+        """
+        table = { 'I':1 , 'V':5, 'X':10 }
+
+        literals = list(roman)
+
+        value = 0
+        i = 0
+
+        while(i < (len(literals) - 1)):
+            current = table[literals[i]]
+            next = table[literals[i + 1]]
+            if (current < next):
+                value += (next - current)
+                i += 2
+            else:
+                value += current
+                i += 1
+
+        if (i < (len(literals))):
+            value += table[literals[i]]
+
+        return value
+
+    def getDeviceFamily(self):
+        """ Get device family """
+        return self.derivedDeviceFamily
+
+    def getDeviceFamilyName(self, deviceFamily):
+        """ Get device family name """
+        p = re.compile('^(\w+)\s+(\w+)$')
+        m = p.match(deviceFamily)
+        return m.group(1).lower() + str(self.romanToInteger(m.group(2)))
+
+    def handleHPSSystemNode(self, systemNode):
+        """ handleHPSPeripheralsNode(peripheralsNode)
+        peripheralsNode is a peripherals element node in hps.xml
+        peripheralsNode is a list of peripheralNodes
+        """
+        configNode = xmlgrok.firstElementChild(systemNode)
+        while configNode != None:
+
+            name = configNode.getAttribute('name')
+            value = configNode.getAttribute('value')
+
+            self.updateTemplate(name, value)
+
+            if name == "DEVICE_FAMILY":
+                self.derivedDeviceFamily = self.getDeviceFamilyName(value)
+
+            if name == "DMA_Enable":
+                self.dmaEnable = value
+
+            configNode = xmlgrok.nextElementSibling(configNode)
+
+    def handleHPSPeripheralNode(self, peripheralNode):
+        """ This node of the hps.xml may contain a name, value pair
+        We need to:
+            emit a #define for the peripheral for is 'used' state
+            emit a #define for that pair, if it is marked 'used'
+        """
+        peripheralNode = xmlgrok.firstElementChild(peripheralNode)
+
+        while peripheralNode != None:
+            if peripheralNode.hasAttribute('name') and peripheralNode.hasAttribute('used'):
+                newLine = "\n"
+                name = peripheralNode.getAttribute('name')
+                used = peripheralNode.getAttribute('used')
+
+                if used == 'true' or used == True:
+                    used = 1
+                elif used == 'false' or used == False:
+                    used = 0
+
+                configs = collections.OrderedDict()
+
+                configNode = xmlgrok.firstElementChild(peripheralNode)
+                while configNode != None:
+                    config_define_name = configNode.getAttribute('name')
+                    config_define_value = configNode.getAttribute('value')
+                    configs[config_define_name] = config_define_value
+                    configNode = xmlgrok.nextElementSibling(configNode)
+                    if configNode == None:
+                        newLine += newLine
+                    self.pinmuxConfigBuffer.write("#define " + str(config_define_name) + ' ' + '(' + str(config_define_value) + ')' + newLine)
+
+                entry = self.pinmux_configs[name]
+                define_name = entry['name']
+
+                if (len(configs) > 0):
+                    self.pinmux_configs[name] = { 'name': define_name, 'used': used, 'configs': configs }
+                else:
+                    self.pinmux_configs[name] = { 'name': define_name, 'used': used }
+
+                # skip the parent peripheral node
+                # since only need to define child config node(s)
+                peripheralNode = xmlgrok.nextElementSibling(peripheralNode)
+
+    def handleHPSPinmuxNode(self, pinmuxNode):
+        """ For a pinmuxNode, we may emit a #define for the name, value pair
+        """
+        if pinmuxNode.hasAttribute('name') and pinmuxNode.hasAttribute('value'):
+            self.pinmuxArraySize += 1
+            name = pinmuxNode.getAttribute('name')
+            value = pinmuxNode.getAttribute('value')
+
+    def handleHPSPinmuxesNode(self, pinmuxesNode):
+        """ PinmuxesNode is a list of pinmuxNodes
+        """
+        self.pinmuxHeaderBuffer.write(str("const u8 sys_mgr_init_table[] = {\n"))
+
+        pinmuxNode = xmlgrok.firstElementChild(pinmuxesNode)
+        while pinmuxNode != None:
+            if pinmuxNode.hasAttribute('name') and pinmuxNode.hasAttribute('value'):
+                self.pinmuxArraySize += 1
+                name = pinmuxNode.getAttribute('name')
+                value = pinmuxNode.getAttribute('value')
+                self.pinmux_regs[name] = value
+            pinmuxNode = xmlgrok.nextElementSibling(pinmuxNode)
+
+        reg_count = 0
+        pinmux_regs_count = len(self.pinmux_regs)
+        for reg, value in self.pinmux_regs.items():
+            reg_count += 1
+            if reg_count < pinmux_regs_count:
+                self.pinmuxHeaderBuffer.write(str("\t" + str(value) + ', /* ' + reg + ' */\n' ))
+            else:
+                self.pinmuxHeaderBuffer.write(str("\t" + str(value) + ' /* ' + reg + ' */\n' ))
+
+        # Write the close of the pin MUX array in the header
+        self.pinmuxHeaderBuffer.write(str("};" ))
+
+    def handleHPSClockNode(self, clockNode):
+        """ A clockNode may emit a #define for the name, frequency pair
+        """
+        if clockNode.hasAttribute('name') and clockNode.hasAttribute('frequency'):
+            name = clockNode.getAttribute('name')
+            frequency = clockNode.getAttribute('frequency')
+            self.clockStream.write("#define " + name + ' ' + '(' + frequency + ')' + '\n')
+
+    def handleHPSClocksNode(self, clocksNode):
+        """ A list of clockNodes is call clocksNode
+        """
+        self.clockStream = streamer.Streamer(self.outputDir + os.sep + clocksNode.nodeName + '.h', 'w')
+        self.clockStream.open()
+        clockNode = xmlgrok.firstElementChild(clocksNode)
+        while clockNode != None:
+            self.handleHPSClockNode(clockNode)
+            clockNode = xmlgrok.nextElementSibling(clockNode)
+
+        self.clockStream.close()
+
+    def handleHpsFpgaInterfaces(self, node):
+        """ Update FPGA Interface registers """
+        node = xmlgrok.firstElementChild(node)
+
+        while node != None:
+            name = node.getAttribute('name')
+            used = node.getAttribute('used')
+
+            if used == 'true':
+                reset = 0
+            else:
+                reset = 1
+
+            if name == 'F2H_AXI_SLAVE':
+                self.updateTemplate("DERIVED_RESET_ASSERT_FPGA2HPS", str(reset))
+            elif name == 'H2F_AXI_MASTER':
+                self.updateTemplate("DERIVED_RESET_ASSERT_HPS2FPGA", str(reset))
+            elif name == 'LWH2F_AXI_MASTER':
+                self.updateTemplate("DERIVED_RESET_ASSERT_LWHPS2FPGA", str(reset))
+
+            node = xmlgrok.nextElementSibling(node)
+
+    def createFilesFromHPS(self):
+        """ Parse xml and create pinmux_config.h """
+        # Unfortunately we can't determine the file name before
+        # parsing the XML, so let's build up the source file
+        # content in string buffer
+        self.pinmuxHeaderBuffer = CompatStringIO()
+        self.pinmuxConfigBuffer = CompatStringIO()
+
+        # Get a list of all nodes with the hps element name
+        hpsNodeList = self.dom.getElementsByTagName('hps')
+        if len(hpsNodeList) > 1:
+            print ("*** WARNING:" + "Multiple hps Elements found in %s!" % self.hpsInFileName)
+        # For each of the hps element nodes, go through the child list
+        # Note that currently there is only one hps Element
+        # but this code will handle more than one hps node
+        # In the future, multiple hps nodes may need additional code
+        # to combine settings from the multiple hps Elements
+        for hpsNode in hpsNodeList:
+            # Currently, there are only 3 children of the hps Element:
+            #     peripherals, pin_muxes, and clocks
+            # but this is left open-ended for future additions to the
+            # specification for the hps.xml
+            childNode = xmlgrok.firstElementChild(hpsNode)
+            while childNode != None:
+                if childNode.nodeName == 'pin_muxes':
+                    self.handleHPSPinmuxesNode(childNode)
+                elif childNode.nodeName == 'system':
+                    self.handleHPSSystemNode(childNode)
+                elif childNode.nodeName == 'fpga_interfaces':
+                    self.handleHpsFpgaInterfaces(childNode)
+                elif childNode.nodeName == 'peripherals':
+                    self.handleHPSPeripheralNode(childNode)
+                else:
+                    print ("***Error:Found unexpected HPS child node:%s" % childNode.nodeName)
+                childNode = xmlgrok.nextElementSibling(childNode)
+
+        self.updateTemplate("DERIVED_DEVICE_FAMILY", self.derivedDeviceFamily)
+
+        # Now we write string buffers into files once we know the device family
+        self.pinmux_config_h = 'pinmux_config.h'
+        self.pinmux_config_src = 'pinmux_config_' + self.derivedDeviceFamily + '.c'
+
+        # Create pinmux_config .h
+        headerDefine = "__SOCFPGA_PINMUX_CONFIG_H__"
+        self.pinmuxHeaderFile = streamer.Streamer(self.outputDir + os.sep + self.pinmux_config_h, 'w')
+        self.pinmuxHeaderFile.open()
+        self.pinmuxHeaderFile.writeLicenseHeader()
+        self.pinmuxHeaderFile.write('/*\n * Altera SoCFPGA PinMux configuration\n */\n\n')
+
+        self.pinmuxHeaderFile.write("#ifndef " + headerDefine + "\n")
+        self.pinmuxHeaderFile.write("#define " + headerDefine + "\n\n")
+        self.pinmuxHeaderFile.write(self.pinmuxHeaderBuffer.getvalue())
+        self.pinmuxHeaderFile.write("\n#endif /* " + headerDefine + " */\n")
+        self.pinmuxHeaderFile.close()
+
+        # Free up string buffers
+        self.pinmuxHeaderBuffer.close()
+        self.pinmuxConfigBuffer.close()
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 00000000000..a6ff5dfd829
--- /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 at intel.com>
+"""
+import os
+import struct
+import streamer
+
+class IOCSRGrokker(object):
+    """ Decode the .hiof file and produce some C source code
+    """
+    IOCSR_ROOT_FILENAME = 'iocsr_config'
+    IOCSR_SENTINEL = '__SOCFPGA_IOCSR_CONFIG_H__'
+    IOCSR_FILE_EXTENSION_MAX_LEN = 6
+    PTAG_HPS_IOCSR_INFO = 39
+    PTAG_HPS_IOCSR = 40
+    PTAG_DEVICE_NAME = 2
+    PTAG_TERMINATION = 8
+
+    def __init__(self, deviceFamily, inputDir, outputDir, hiofSrcFileName):
+        """ IOCSRGrokker Initialization """
+        self.deviceFamily = deviceFamily
+        self.inputDir = inputDir
+        self.outputDir = outputDir
+        self.hiofInFileName = hiofSrcFileName
+        self.iocsrFileName =  self.IOCSR_ROOT_FILENAME
+        self.headerOut = None
+        self.sourceOut = None
+        self.createFilesFromHIOF()
+
+    @staticmethod
+    def byteArrayToStr(bytes):
+        """ Convert a list of bytes into a string
+        """
+        # We don't like nulls
+        bytes = bytes.replace('\x00', '')
+        s = ''
+        for b in bytes:
+            s += b
+        return s
+
+    @staticmethod
+    def getLengthData(bytes):
+        """
+        @param: bytes is a chunk of bytes that we need to decode
+        There will be a ptag that we may care about.
+        If we care about it, we will get the length of the chunk
+        that the ptag cares about.
+        @rtype: a pair, length of chunk and the chunk itself
+        @return: length of the ptag chunk we care about
+        @return: data chunk that ptag indicates we need to decode
+        """
+        blockSize = len(bytes)
+        i = 0
+        bitlength = 0
+        length = 0
+        data = []
+
+        while i < blockSize:
+            byte = struct.unpack('B', bytes[i:i+1])[0]
+            i += 1
+
+            if byte == 1:
+                bitlength = struct.unpack('I', bytes[i:i+4])[0]
+                i += 4
+            elif byte == 2:
+                length = struct.unpack('I', bytes[i:i+4])[0]
+                i += 4
+
+            elif byte == 5:
+                j = 0
+                while i < blockSize:
+                    data.append(struct.unpack('I', bytes[i:i+4])[0])
+                    i += 4
+                    j += 1
+
+            else:
+                i += 4
+
+        return (bitlength, data)
+
+
+    def verifyRead(self, tagWeRead, tagWeExpected):
+        """ verify the hiof value with tag expected """
+        if tagWeRead != tagWeExpected:
+            print ("***Error: Expected ptag of %02d, but got %02d" % (tagWeExpected, tagWeRead))
+
+    def createFilesFromHIOF(self):
+        """ read the hiof file to create iocsr_config.h """
+        self.hiofStream = streamer.Streamer(self.inputDir + os.sep + self.hiofInFileName, 'rb')
+        self.iocsrHeaderStream = streamer.Streamer(self.outputDir + os.sep + self.iocsrFileName + '.h', 'w')
+        self.hiofStream.open()
+        self.iocsrHeaderStream.open()
+        self.iocsrHeaderStream.writeLicenseHeader()
+        self.iocsrHeaderStream.write('/*\n * Altera SoCFPGA IOCSR configuration\n */\n\n')
+        ret = self.iocsrHeaderStream.writeSentinelStart(IOCSRGrokker.IOCSR_SENTINEL)
+        if ret == -1:
+            print("Empty header written. Exiting.")
+
+        # Read the file extension (typically .hiof)
+        # and the file version
+        self.fileExtension = self.hiofStream.readBytesAsString(IOCSRGrokker.IOCSR_FILE_EXTENSION_MAX_LEN)
+        self.fileVersion = self.hiofStream.readUnsignedInt()
+
+        # Now read the ptags
+        # Device name is first
+        self.programmerTag = self.hiofStream.readUnsignedShort()
+        self.verifyRead(self.programmerTag, self.PTAG_DEVICE_NAME)
+        self.deviceNameLength = self.hiofStream.readUnsignedInt()
+        self.deviceName = self.hiofStream.readBytesAsString(self.deviceNameLength)
+
+        # Basic information of the HIOF files
+        # This is not used by the preloader generator, but we read it and ignore the
+        # contents.
+        programmerTag = self.hiofStream.readUnsignedShort()
+        self.verifyRead(programmerTag, self.PTAG_HPS_IOCSR_INFO)
+        basicHPSIOCSRInfoLength = self.hiofStream.readUnsignedInt()
+        self.hiofStream.read(basicHPSIOCSRInfoLength)
+
+        # Actual content of IOCSR information
+        self.programmerTag1 = self.hiofStream.readUnsignedShort()
+        self.verifyRead(self.programmerTag1, self.PTAG_HPS_IOCSR)
+        self.HPSIOCSRLength1 = self.hiofStream.readUnsignedInt()
+        self.HPSIOCSRBytes1 = self.hiofStream.read(self.HPSIOCSRLength1)
+        self.HPSIOCSRDataLength1, self.HPSIOCSRData1 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes1)
+
+        # Actual content of IOCSR information
+        self.programmerTag2 = self.hiofStream.readUnsignedShort()
+        self.verifyRead(self.programmerTag2, self.PTAG_HPS_IOCSR)
+        self.HPSIOCSRLength2 = self.hiofStream.readUnsignedInt()
+        self.HPSIOCSRBytes2 = self.hiofStream.read(self.HPSIOCSRLength2)
+        self.HPSIOCSRDataLength2, self.HPSIOCSRData2 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes2)
+
+        # Actual content of IOCSR information
+        self.programmerTag3 = self.hiofStream.readUnsignedShort()
+        self.verifyRead(self.programmerTag3, self.PTAG_HPS_IOCSR)
+        self.HPSIOCSRLength3 = self.hiofStream.readUnsignedInt()
+        self.HPSIOCSRBytes3 = self.hiofStream.read(self.HPSIOCSRLength3)
+        self.HPSIOCSRDataLength3, self.HPSIOCSRData3 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes3)
+
+        # Actual content of IOCSR information
+        self.programmerTag4 = self.hiofStream.readUnsignedShort()
+        self.verifyRead(self.programmerTag4, self.PTAG_HPS_IOCSR)
+        self.HPSIOCSRLength4 = self.hiofStream.readUnsignedInt()
+        self.HPSIOCSRBytes4 = self.hiofStream.read(self.HPSIOCSRLength4)
+        self.HPSIOCSRDataLength4, self.HPSIOCSRData4 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes4)
+
+        # Now we should see the end of the hiof input
+        programmerTag = self.hiofStream.readUnsignedShort()
+        if 8 != programmerTag:
+            print ("I didn't find the end of the .hiof file when I expected to!")
+
+        self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN0_LENGTH\t' +\
+                       str(self.HPSIOCSRDataLength1) + '\n')
+        self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN1_LENGTH\t' +\
+                       str(self.HPSIOCSRDataLength2) + '\n')
+        self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN2_LENGTH\t' +\
+                       str(self.HPSIOCSRDataLength3) + '\n')
+        self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN3_LENGTH\t' +\
+                       str(self.HPSIOCSRDataLength4) + '\n')
+
+        self.iocsrHeaderStream.write("\n")
+
+        self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain0_table[] = {\n')
+        for value in self.HPSIOCSRData1:
+            hv = '0x%08X' % (value)
+            self.iocsrHeaderStream.write('\t' + hv + ',\n')
+        self.iocsrHeaderStream.write('};\n')
+        self.iocsrHeaderStream.write('\n')
+
+        self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain1_table[] = {\n')
+        for value in self.HPSIOCSRData2:
+            hv = '0x%08X' % (value)
+            self.iocsrHeaderStream.write('\t' + hv + ',\n')
+        self.iocsrHeaderStream.write('};\n')
+        self.iocsrHeaderStream.write('\n')
+
+        self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain2_table[] = {\n')
+        for value in self.HPSIOCSRData3:
+            hv = '0x%08X' % (value)
+            self.iocsrHeaderStream.write('\t' + hv + ',\n')
+        self.iocsrHeaderStream.write('};\n')
+        self.iocsrHeaderStream.write('\n')
+
+        self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain3_table[] = {\n')
+        for value in self.HPSIOCSRData4:
+            hv = '0x%08X' % (value)
+            self.iocsrHeaderStream.write('\t' + hv + ',\n')
+        self.iocsrHeaderStream.write('};\n')
+        self.iocsrHeaderStream.write('\n\n')
+
+        ret = self.iocsrHeaderStream.writeSentinelEnd(IOCSRGrokker.IOCSR_SENTINEL)
+        if ret == -1:
+            print("Empty header written. Exiting.")
+
+        self.iocsrHeaderStream.close()
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 00000000000..c30d6246cc4
--- /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 at 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 00000000000..0ab1e2f2df2
--- /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 at intel.com>
+"""
+import collections
+import doc
+
+class pll_config_h:
+    """
+    pll_config.h renderer.
+    """
+
+    def __init__(self, hpsModel, emifModel):
+        """ renderer initialization """
+        self.hpsModel = hpsModel
+        self.emifModel = emifModel
+        self.doc = doc.generated_c_source("__SOCFPGA_PLL_CONFIG_H__")
+
+    def createContent(self):
+        """ add the content based on settings parsed. eventually it will be
+        written to pll_config.h file
+        """
+        doc.c_source.line(self.doc)
+        id = "CFG_HPS_DBCTRL_STAYOSC1"
+        valueString = self.hpsModel.getSystemConfig("dbctrl_stayosc1")
+        # Unfortunately hps.xml never tells us the data type of values
+        # attributes. Here we workaround this type of problem, often
+        # this is case-by-case, i.e. having to know which parameter that
+        # we're dealing with, hence this ugly parameter-specific
+        # if-statement needs here to workaround the data type inconsistency
+        if valueString.lower() == "true":
+            value = "1"
+        else:
+            value = "0"
+        doc.c_source.define(self.doc, id, value )
+        doc.c_source.line(self.doc)
+        self.addMainPllSettings()
+        doc.c_source.line(self.doc)
+        self.addPeriphPllSettings()
+        doc.c_source.line(self.doc)
+        self.addSdramPllSettings()
+        doc.c_source.line(self.doc)
+        self.addClockFreq()
+        doc.c_source.line(self.doc)
+        self.addAlteraSettings()
+        doc.c_source.line(self.doc)
+
+    def addMainPllSettings(self):
+        """ add pll settings to the file """
+        paramMap = collections.OrderedDict()
+        paramMap["VCO_DENOM"] = "main_pll_n"
+        paramMap["VCO_NUMER"] = "main_pll_m"
+
+        for key in paramMap.keys():
+            id = "CFG_HPS_MAINPLLGRP_" + key
+            value = self.hpsModel.getSystemConfig(paramMap[key])
+            doc.c_source.define(self.doc, id,  value )
+
+        # main_pll_c0, main_pll_c1, main_pll_c2 are fixed counters,
+        doc.c_source.define(self.doc, "CFG_HPS_MAINPLLGRP_MPUCLK_CNT", "0")
+        doc.c_source.define(self.doc, "CFG_HPS_MAINPLLGRP_MAINCLK_CNT", "0")
+        doc.c_source.define(self.doc, "CFG_HPS_MAINPLLGRP_DBGATCLK_CNT", "0")
+
+        paramMap = collections.OrderedDict()
+
+        paramMap["MAINQSPICLK_CNT"] = "main_pll_c3"
+        paramMap["MAINNANDSDMMCCLK_CNT"] = "main_pll_c4"
+        paramMap["CFGS2FUSER0CLK_CNT"] = "main_pll_c5"
+        paramMap["MAINDIV_L3MPCLK"] = "l3_mp_clk_div"
+        paramMap["MAINDIV_L3SPCLK"] = "l3_sp_clk_div"
+        paramMap["MAINDIV_L4MPCLK"] = "l4_mp_clk_div"
+        paramMap["MAINDIV_L4SPCLK"] = "l4_sp_clk_div"
+        paramMap["DBGDIV_DBGATCLK"] = "dbg_at_clk_div"
+        paramMap["DBGDIV_DBGCLK"] = "dbg_clk_div"
+        paramMap["TRACEDIV_TRACECLK"] = "dbg_trace_clk_div"
+        paramMap["L4SRC_L4MP"] = "l4_mp_clk_source"
+        paramMap["L4SRC_L4SP"] = "l4_sp_clk_source"
+
+        for key in paramMap.keys():
+            id = "CFG_HPS_MAINPLLGRP_" + key
+            value = self.hpsModel.getSystemConfig(paramMap[key])
+            doc.c_source.define(self.doc, id, value )
+
+    def addPeriphPllSettings(self):
+        """ add peripheral pll settings to the file """
+        paramMap = collections.OrderedDict()
+        paramMap["VCO_DENOM"] = "periph_pll_n"
+        paramMap["VCO_NUMER"] = "periph_pll_m"
+        paramMap["VCO_PSRC"] = "periph_pll_source"
+        paramMap["EMAC0CLK_CNT"] = "periph_pll_c0"
+        paramMap["EMAC1CLK_CNT"] = "periph_pll_c1"
+        paramMap["PERQSPICLK_CNT"] = "periph_pll_c2"
+        paramMap["PERNANDSDMMCCLK_CNT"] = "periph_pll_c3"
+        paramMap["PERBASECLK_CNT"] = "periph_pll_c4"
+        paramMap["S2FUSER1CLK_CNT"] = "periph_pll_c5"
+        paramMap["DIV_USBCLK"] = "usb_mp_clk_div"
+        paramMap["DIV_SPIMCLK"] = "spi_m_clk_div"
+        paramMap["DIV_CAN0CLK"] = "can0_clk_div"
+        paramMap["DIV_CAN1CLK"] = "can1_clk_div"
+        paramMap["GPIODIV_GPIODBCLK"] = "gpio_db_clk_div"
+        paramMap["SRC_SDMMC"] = "sdmmc_clk_source"
+        paramMap["SRC_NAND"] = "nand_clk_source"
+        paramMap["SRC_QSPI"] = "qspi_clk_source"
+
+        for key in paramMap.keys():
+            id = "CFG_HPS_PERPLLGRP_" + key
+            value = self.hpsModel.getSystemConfig(paramMap[key])
+            doc.c_source.define(self.doc, id, value )
+
+    def addSdramPllSettings(self):
+        """ add sdram pll settings to the file """
+        value = self.emifModel.getPllDefine("PLL_MEM_CLK_DIV")
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_VCO_DENOM", value )
+        value = self.emifModel.getPllDefine("PLL_MEM_CLK_MULT")
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_VCO_NUMER", value )
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_VCO_SSRC", "0")
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQSCLK_CNT", "1")
+        value = self.emifModel.getPllDefine("PLL_MEM_CLK_PHASE_DEG")
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQSCLK_PHASE", value )
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDR2XDQSCLK_CNT", "0")
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDR2XDQSCLK_PHASE", "0")
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQCLK_CNT", "1")
+        value = self.emifModel.getPllDefine("PLL_WRITE_CLK_PHASE_DEG")
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQCLK_PHASE", value )
+
+        try:
+            value = self.hpsModel.getSystemConfig("sdram_pll_c5")
+        except ValueError:
+            value = "5"
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_S2FUSER2CLK_CNT", value )
+        doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_S2FUSER2CLK_PHASE", "0")
+
+    def addClockFreq(self):
+        """ add clock frequency settings to the file """
+        paramMap = collections.OrderedDict()
+        paramMap["OSC1"] = "eosc1_clk_hz"
+        paramMap["OSC2"] = "eosc2_clk_hz"
+        paramMap["F2S_SDR_REF"] = "F2SCLK_SDRAMCLK_FREQ"
+        paramMap["F2S_PER_REF"] = "F2SCLK_PERIPHCLK_FREQ"
+        paramMap["MAINVCO"] = "main_pll_vco_hz"
+        paramMap["PERVCO"] = "periph_pll_vco_hz"
+
+        for key in paramMap.keys():
+            id = "CFG_HPS_CLK_" + key + "_HZ"
+            value = self.hpsModel.getSystemConfig(paramMap[key])
+            doc.c_source.define(self.doc, id, value )
+
+        eosc1 = int(self.hpsModel.getSystemConfig("eosc1_clk_hz"))
+        eosc2 = int(self.hpsModel.getSystemConfig("eosc2_clk_hz"))
+        m = int(self.emifModel.getPllDefine("PLL_MEM_CLK_MULT"))
+        n = int(self.emifModel.getPllDefine("PLL_MEM_CLK_DIV"))
+        vco = int(round(eosc1 * (m + 1) / (n + 1)))
+        doc.c_source.define(self.doc, "CFG_HPS_CLK_SDRVCO_HZ", str(vco) )
+
+        paramMap = collections.OrderedDict()
+        paramMap["EMAC0"] = "emac0_clk_hz"
+        paramMap["EMAC1"] = "emac1_clk_hz"
+        paramMap["USBCLK"] = "usb_mp_clk_hz"
+        paramMap["NAND"] = "nand_clk_hz"
+        paramMap["SDMMC"] = "sdmmc_clk_hz"
+        paramMap["QSPI"] = "qspi_clk_hz"
+        paramMap["SPIM"] = "spi_m_clk_hz"
+        paramMap["CAN0"] = "can0_clk_hz"
+        paramMap["CAN1"] = "can1_clk_hz"
+        paramMap["GPIODB"] = "gpio_db_clk_hz"
+        paramMap["L4_MP"] = "l4_mp_clk_hz"
+        paramMap["L4_SP"] = "l4_sp_clk_hz"
+
+        for key in paramMap.keys():
+            id = "CFG_HPS_CLK_" + key + "_HZ"
+            value = self.hpsModel.getSystemConfig(paramMap[key])
+            doc.c_source.define(self.doc, id, value )
+
+    def addAlteraSettings(self):
+        """ add Altera-related settings to the file """
+        paramMap = collections.OrderedDict()
+        paramMap["MPUCLK"] = "main_pll_c0_internal"
+        paramMap["MAINCLK"] = "main_pll_c1_internal"
+        paramMap["DBGATCLK"] = "main_pll_c2_internal"
+
+        for key in paramMap.keys():
+            id = "CFG_HPS_ALTERAGRP_" + key
+            value = self.hpsModel.getSystemConfig(paramMap[key])
+            doc.c_source.define(self.doc, id, value )
+
+    def __str__(self):
+        """ convert to string """
+        self.createContent()
+        return str(self.doc)
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 00000000000..19c30aced6a
--- /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 at 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 00000000000..fae1d745bfd
--- /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 at 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
-- 
2.25.1
    
    
More information about the U-Boot
mailing list