mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-02 09:46:37 +03:00
Cyclone V Board handsoff script
Since turning from old build flow. New Altera SoCFPGA requires converting handsoff conversion via the python script. This is from official provided, and now sync to U-Boot with better location at tools/cv_xxxx. Meantime, requirement.txt is also provided to further explain the libraries require for these scripts. Signed-off-by: Brian Sune <briansune@gmail.com> Reviewed-by: Tien Fong Chee <tien.fong.chee@altera.com>
This commit is contained in:
committed by
Tien Fong Chee
parent
5eb14e1ea2
commit
3ba9b1f7bd
100
tools/cv_bsp_generator/cv_bsp_generator.py
Executable file
100
tools/cv_bsp_generator/cv_bsp_generator.py
Executable file
@@ -0,0 +1,100 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
"""
|
||||||
|
Bsp preloader header file generator
|
||||||
|
|
||||||
|
Process the handoff files from Quartus and convert them to headers
|
||||||
|
usable by U-Boot. Includes the qts filter.sh capability to generate
|
||||||
|
correct format for headers to be used for mainline Uboot on FPGA,
|
||||||
|
namely Cyclone V & Arria V.
|
||||||
|
|
||||||
|
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||||
|
|
||||||
|
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||||
|
"""
|
||||||
|
import glob
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import emif
|
||||||
|
import hps
|
||||||
|
import iocsr
|
||||||
|
import renderer
|
||||||
|
import model
|
||||||
|
import collections
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def printUsage():
|
||||||
|
""" usage string """
|
||||||
|
print ("Usage:\n\t%s\n" % ("sys.argv[0], --input_dir=<path to iswinfo directory> --output_dir=<path store output files>"))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
def verifyInputDir(dir):
|
||||||
|
""" check if the input directory exists """
|
||||||
|
if not os.path.isdir(dir):
|
||||||
|
print ("There is no such directory '%s'!\n" % (dir))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
def verifyOutputDir(dir):
|
||||||
|
""" check if the output directory exists """
|
||||||
|
if not os.path.isdir(dir):
|
||||||
|
os.makedirs(dir)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Do some rudimentary command line processing until it is proven we need something
|
||||||
|
# heavier, such as argparse (preferred, but 2.7+ only) or optparse
|
||||||
|
|
||||||
|
inputDir = '.'
|
||||||
|
outputDir = '.'
|
||||||
|
|
||||||
|
progVersion = '%prog 1.0'
|
||||||
|
progDesc = 'Generate board-specific files for the preloader'
|
||||||
|
optParser = optparse.OptionParser(version=progVersion, description=progDesc)
|
||||||
|
optParser.add_option('-i', '--input-dir', action='store', type='string', dest='inputDir', default='.',
|
||||||
|
help='input-dir is usually the iswinfo directory')
|
||||||
|
optParser.add_option('-o', '--output-dir', action='store', type='string', dest='outputDir', default='.',
|
||||||
|
help='output-dir is usually the directory containing the preloader source')
|
||||||
|
|
||||||
|
(options, args) = optParser.parse_args()
|
||||||
|
|
||||||
|
for arg in args:
|
||||||
|
print ("***WARNING: I don't understand '%s', so I am ignoring it\n" % (arg))
|
||||||
|
|
||||||
|
inputDir = options.inputDir
|
||||||
|
verifyInputDir(inputDir)
|
||||||
|
outputDir = options.outputDir
|
||||||
|
|
||||||
|
verifyOutputDir(outputDir)
|
||||||
|
|
||||||
|
emif = emif.EMIFGrokker(inputDir, outputDir, 'emif.xml')
|
||||||
|
hps = hps.HPSGrokker(inputDir, outputDir)
|
||||||
|
|
||||||
|
pllConfigH = outputDir + "/" + "pll_config.h"
|
||||||
|
print ("Generating file: " + pllConfigH)
|
||||||
|
hpsModel = model.hps.create(inputDir + "/" + "hps.xml")
|
||||||
|
emifModel = model.emif.create(inputDir +"/" + "emif.xml")
|
||||||
|
|
||||||
|
content=str(renderer.pll_config_h(hpsModel, emifModel))
|
||||||
|
f = open(pllConfigH, "w")
|
||||||
|
f.write(content)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
# For all the .hiof files, make a iocsr_config.[h|c]
|
||||||
|
# Only support single hiof file currently
|
||||||
|
hiof_list = glob.glob(inputDir + os.sep + "*.hiof")
|
||||||
|
if len(hiof_list) < 1:
|
||||||
|
print ("***Error: No .hiof files found in input!")
|
||||||
|
|
||||||
|
elif len(hiof_list) > 1:
|
||||||
|
print ("***Error: We don't handle more than one .hiof file yet")
|
||||||
|
print (" Only the last .hiof file in the list will be converted")
|
||||||
|
print (" hiof files found:")
|
||||||
|
for f in hiof_list:
|
||||||
|
print (" " + f)
|
||||||
|
|
||||||
|
for hiof_file_path in hiof_list:
|
||||||
|
hiof_file = os.path.basename(hiof_file_path)
|
||||||
|
# Avoid IOCSRGrokker having to parse hps.xml to determine
|
||||||
|
# device family for output file name, instead we'll just
|
||||||
|
# get it from HPSGrokker
|
||||||
|
iocsr = iocsr.IOCSRGrokker(hps.getDeviceFamily(), inputDir, outputDir, hiof_file)
|
||||||
243
tools/cv_bsp_generator/doc.py
Executable file
243
tools/cv_bsp_generator/doc.py
Executable file
@@ -0,0 +1,243 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
"""
|
||||||
|
Generic document construction classes.
|
||||||
|
|
||||||
|
These classes are templates for creating documents that are not bound
|
||||||
|
to a specific usage or data model.
|
||||||
|
|
||||||
|
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||||
|
|
||||||
|
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
class document(object):
|
||||||
|
"""
|
||||||
|
An abstract document class which does not dictate
|
||||||
|
how a document should be constructed or manipulated.
|
||||||
|
|
||||||
|
It's sole purpose is to describe the entire document
|
||||||
|
in smaller units
|
||||||
|
"""
|
||||||
|
|
||||||
|
class entry(object):
|
||||||
|
"""
|
||||||
|
An entry is the smallest unit
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
""" entry initialization """
|
||||||
|
if parent != None:
|
||||||
|
parent.add(self)
|
||||||
|
|
||||||
|
class block(entry):
|
||||||
|
"""
|
||||||
|
A block is the smallest collection unit
|
||||||
|
consists of entries and blocks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
""" block initialization """
|
||||||
|
super(document.block, self).__init__(parent)
|
||||||
|
self.entries = []
|
||||||
|
|
||||||
|
def add(self, entry):
|
||||||
|
""" add entry to block """
|
||||||
|
self.entries.append(entry)
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" document initialization """
|
||||||
|
self.entries = []
|
||||||
|
|
||||||
|
def add(self, entry):
|
||||||
|
""" add entry to entry list """
|
||||||
|
self.entries.append(entry)
|
||||||
|
|
||||||
|
|
||||||
|
class text(document):
|
||||||
|
"""
|
||||||
|
A simple text document implementation
|
||||||
|
"""
|
||||||
|
|
||||||
|
class string(document.entry):
|
||||||
|
"""
|
||||||
|
The smallest unit of a text file is a string
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent, stringString=None):
|
||||||
|
""" string initialization """
|
||||||
|
super(text.string, self).__init__(parent)
|
||||||
|
self.stringString = stringString
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" convert None to empty string """
|
||||||
|
if (self.stringString != None):
|
||||||
|
return self.stringString
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
class line(string):
|
||||||
|
"""
|
||||||
|
A line is a string with EOL character
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" convert string with newline """
|
||||||
|
return super(text.line, self).__str__() + "\n"
|
||||||
|
|
||||||
|
class block(document.block):
|
||||||
|
"""
|
||||||
|
A block of text which can be made up of
|
||||||
|
strings or lines
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" concatenate strings or lines """
|
||||||
|
blockString = ""
|
||||||
|
|
||||||
|
for entry in self.entries:
|
||||||
|
blockString += str(entry)
|
||||||
|
|
||||||
|
return blockString
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" concatenate strings or lines """
|
||||||
|
textString = ""
|
||||||
|
|
||||||
|
for entry in self.entries:
|
||||||
|
textString += str(entry)
|
||||||
|
|
||||||
|
return textString
|
||||||
|
|
||||||
|
|
||||||
|
class c_source(text):
|
||||||
|
"""
|
||||||
|
A simple C header document implementation
|
||||||
|
"""
|
||||||
|
|
||||||
|
class define(text.string):
|
||||||
|
"""
|
||||||
|
C header define
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent, id, token=None):
|
||||||
|
""" c header constructor initialization """
|
||||||
|
super(c_source.define, self).__init__(parent, id)
|
||||||
|
self.token = token
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" c header to strings """
|
||||||
|
defineString = "#define" + " " + super(c_source.define, self).__str__()
|
||||||
|
|
||||||
|
if self.token != None:
|
||||||
|
defineString += " " + self.token
|
||||||
|
|
||||||
|
defineString += "\n"
|
||||||
|
|
||||||
|
return defineString
|
||||||
|
|
||||||
|
class comment_string(text.string):
|
||||||
|
"""
|
||||||
|
C header comment
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" c comment """
|
||||||
|
return "/*" + " " + super(c_source.comment_string, self).__str__() + " " + "*/"
|
||||||
|
|
||||||
|
class comment_line(comment_string):
|
||||||
|
"""
|
||||||
|
C header comment with newline
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" c comment with newline """
|
||||||
|
return super(c_source.comment_line, self).__str__() + "\n"
|
||||||
|
|
||||||
|
class block(text.block):
|
||||||
|
"""
|
||||||
|
A simple C block string implementation
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent, prologue=None, epilogue=None):
|
||||||
|
""" ifdef block string implementation """
|
||||||
|
super(c_source.block, self).__init__(parent)
|
||||||
|
|
||||||
|
self.prologue = None
|
||||||
|
self.epilogue = None
|
||||||
|
|
||||||
|
if prologue != None:
|
||||||
|
self.prologue = prologue
|
||||||
|
|
||||||
|
if epilogue != None:
|
||||||
|
self.epilogue = epilogue
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" convert ifdef to string """
|
||||||
|
blockString = ""
|
||||||
|
|
||||||
|
if self.prologue != None:
|
||||||
|
blockString += str(self.prologue)
|
||||||
|
|
||||||
|
blockString += super(c_source.block, self).__str__()
|
||||||
|
|
||||||
|
if self.epilogue != None:
|
||||||
|
blockString += str(self.epilogue)
|
||||||
|
|
||||||
|
return blockString
|
||||||
|
|
||||||
|
class comment_block(block):
|
||||||
|
"""
|
||||||
|
A simple C header block comment implementation
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent, comments):
|
||||||
|
""" block comment initialization """
|
||||||
|
super(c_source.comment_block, self).__init__(parent, "/*\n", " */\n")
|
||||||
|
for comment in comments.split("\n"):
|
||||||
|
self.add(comment)
|
||||||
|
|
||||||
|
def add(self, entry):
|
||||||
|
""" add line to block comment """
|
||||||
|
super(c_source.block, self).add(" * " + entry + "\n")
|
||||||
|
|
||||||
|
class ifndef_block(block):
|
||||||
|
"""
|
||||||
|
A simple C header ifndef implementation
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent, id):
|
||||||
|
""" ifndef block initialization """
|
||||||
|
prologue = text.line(None, "#ifndef" + " " + id)
|
||||||
|
epilogue = text.block(None)
|
||||||
|
text.string(epilogue, "#endif")
|
||||||
|
text.string(epilogue, " ")
|
||||||
|
c_source.comment_line(epilogue, id)
|
||||||
|
super(c_source.ifndef_block, self).__init__(parent, prologue, epilogue)
|
||||||
|
|
||||||
|
|
||||||
|
class generated_c_source(c_source):
|
||||||
|
"""
|
||||||
|
Caller to generate c format files using the helper classes
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, filename):
|
||||||
|
""" Generate c header file with license, copyright, comment,
|
||||||
|
ifdef block
|
||||||
|
"""
|
||||||
|
super(generated_c_source, self).__init__()
|
||||||
|
|
||||||
|
self.entries.append(c_source.comment_line(None, "SPDX-License-Identifier: BSD-3-Clause"))
|
||||||
|
self.entries.append(c_source.comment_block(None, "Copyright (C) 2022 Intel Corporation <www.intel.com>"))
|
||||||
|
self.entries.append(c_source.comment_block(None, "Altera SoCFPGA Clock and PLL configuration"))
|
||||||
|
self.entries.append(text.line(None))
|
||||||
|
|
||||||
|
self.body = c_source.ifndef_block(None, filename)
|
||||||
|
self.body.add(c_source.define(None, filename))
|
||||||
|
self.entries.append(self.body)
|
||||||
|
|
||||||
|
def add(self, entry):
|
||||||
|
""" add content to be written into c header file """
|
||||||
|
self.body.add(entry)
|
||||||
424
tools/cv_bsp_generator/emif.py
Executable file
424
tools/cv_bsp_generator/emif.py
Executable file
File diff suppressed because one or more lines are too long
571
tools/cv_bsp_generator/hps.py
Executable file
571
tools/cv_bsp_generator/hps.py
Executable file
@@ -0,0 +1,571 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
"""
|
||||||
|
Pinmux header file generator
|
||||||
|
|
||||||
|
Process the hps.xml from Quartus and convert them to headers
|
||||||
|
usable by U-Boot.
|
||||||
|
|
||||||
|
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||||
|
|
||||||
|
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import streamer
|
||||||
|
import xmlgrok
|
||||||
|
import xml.dom.minidom
|
||||||
|
import collections
|
||||||
|
import io
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
class CompatStringIO(io.StringIO):
|
||||||
|
def write(self, s):
|
||||||
|
if hasattr(s, 'decode'):
|
||||||
|
# Use unicode for python2 to keep compatible
|
||||||
|
return int(super(CompatStringIO, self).write(s.decode('utf-8')))
|
||||||
|
else:
|
||||||
|
return super(CompatStringIO, self).write(s)
|
||||||
|
def getvalue(self):
|
||||||
|
return str(super(CompatStringIO, self).getvalue())
|
||||||
|
|
||||||
|
class HPSGrokker(object):
|
||||||
|
|
||||||
|
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
TEMPLATE_DIR = os.path.dirname(SCRIPT_DIR) + '/src'
|
||||||
|
|
||||||
|
MAKEFILE_FILENAME = "Makefile"
|
||||||
|
makefileTemplate = ""
|
||||||
|
RESET_CONFIG_H_FILENAME = "reset_config.h"
|
||||||
|
resetConfigHTemplate = ""
|
||||||
|
|
||||||
|
# If no device family is specified, assume Cyclone V.
|
||||||
|
derivedDeviceFamily = "cyclone5"
|
||||||
|
|
||||||
|
# Assume FPGA DMA 0-7 are not in use by default
|
||||||
|
# Note: there appears to be a weird mismatch between sopcinfo
|
||||||
|
# value vs hps.xml value of DMA_Enable of string_list hw.tcl
|
||||||
|
# type, where sopcinfo uses comma as separator e.g.
|
||||||
|
# "No,No,No,..." while hps.xml uses space as separator.
|
||||||
|
dmaEnable = "No No No No No No No No"
|
||||||
|
|
||||||
|
def __init__(self, inputDir, outputDir, hpsFileName='hps.xml'):
|
||||||
|
""" HPSGrokker initialization """
|
||||||
|
self.inputDir = inputDir
|
||||||
|
self.outputDir = outputDir
|
||||||
|
self.hpsInFileName = inputDir + os.sep + hpsFileName
|
||||||
|
self.dom = xml.dom.minidom.parse(self.hpsInFileName)
|
||||||
|
self.peripheralStream = None
|
||||||
|
self.pinmuxConfigBuffer = None
|
||||||
|
self.pinmuxHeaderBuffer = None
|
||||||
|
self.pinmuxHeaderFile = None
|
||||||
|
self.pinmuxArraySize = 0
|
||||||
|
self.config_hps_ = "CFG_HPS_"
|
||||||
|
self.clockStream = None
|
||||||
|
self.pinmux_regs = self.get_default_pinmux_regs()
|
||||||
|
self.pinmux_configs = self.get_default_pinmux_configs()
|
||||||
|
self.pinmux_config_h = None
|
||||||
|
|
||||||
|
self.createFilesFromHPS()
|
||||||
|
|
||||||
|
def get_default_pinmux_regs(self):
|
||||||
|
""" Set default pinmux values """
|
||||||
|
p = collections.OrderedDict()
|
||||||
|
|
||||||
|
p['EMACIO0'] = 0
|
||||||
|
p['EMACIO1'] = 0
|
||||||
|
p['EMACIO2'] = 0
|
||||||
|
p['EMACIO3'] = 0
|
||||||
|
p['EMACIO4'] = 0
|
||||||
|
p['EMACIO5'] = 0
|
||||||
|
p['EMACIO6'] = 0
|
||||||
|
p['EMACIO7'] = 0
|
||||||
|
p['EMACIO8'] = 0
|
||||||
|
p['EMACIO9'] = 0
|
||||||
|
p['EMACIO10'] = 0
|
||||||
|
p['EMACIO11'] = 0
|
||||||
|
p['EMACIO12'] = 0
|
||||||
|
p['EMACIO13'] = 0
|
||||||
|
p['EMACIO14'] = 0
|
||||||
|
p['EMACIO15'] = 0
|
||||||
|
p['EMACIO16'] = 0
|
||||||
|
p['EMACIO17'] = 0
|
||||||
|
p['EMACIO18'] = 0
|
||||||
|
p['EMACIO19'] = 0
|
||||||
|
p['FLASHIO0'] = 0
|
||||||
|
p['FLASHIO1'] = 0
|
||||||
|
p['FLASHIO2'] = 0
|
||||||
|
p['FLASHIO3'] = 0
|
||||||
|
p['FLASHIO4'] = 0
|
||||||
|
p['FLASHIO5'] = 0
|
||||||
|
p['FLASHIO6'] = 0
|
||||||
|
p['FLASHIO7'] = 0
|
||||||
|
p['FLASHIO8'] = 0
|
||||||
|
p['FLASHIO9'] = 0
|
||||||
|
p['FLASHIO10'] = 0
|
||||||
|
p['FLASHIO11'] = 0
|
||||||
|
p['GENERALIO0'] = 0
|
||||||
|
p['GENERALIO1'] = 0
|
||||||
|
p['GENERALIO2'] = 0
|
||||||
|
p['GENERALIO3'] = 0
|
||||||
|
p['GENERALIO4'] = 0
|
||||||
|
p['GENERALIO5'] = 0
|
||||||
|
p['GENERALIO6'] = 0
|
||||||
|
p['GENERALIO7'] = 0
|
||||||
|
p['GENERALIO8'] = 0
|
||||||
|
p['GENERALIO9'] = 0
|
||||||
|
p['GENERALIO10'] = 0
|
||||||
|
p['GENERALIO11'] = 0
|
||||||
|
p['GENERALIO12'] = 0
|
||||||
|
p['GENERALIO13'] = 0
|
||||||
|
p['GENERALIO14'] = 0
|
||||||
|
p['GENERALIO15'] = 0
|
||||||
|
p['GENERALIO16'] = 0
|
||||||
|
p['GENERALIO17'] = 0
|
||||||
|
p['GENERALIO18'] = 0
|
||||||
|
p['GENERALIO19'] = 0
|
||||||
|
p['GENERALIO20'] = 0
|
||||||
|
p['GENERALIO21'] = 0
|
||||||
|
p['GENERALIO22'] = 0
|
||||||
|
p['GENERALIO23'] = 0
|
||||||
|
p['GENERALIO24'] = 0
|
||||||
|
p['GENERALIO25'] = 0
|
||||||
|
p['GENERALIO26'] = 0
|
||||||
|
p['GENERALIO27'] = 0
|
||||||
|
p['GENERALIO28'] = 0
|
||||||
|
p['GENERALIO29'] = 0
|
||||||
|
p['GENERALIO30'] = 0
|
||||||
|
p['GENERALIO31'] = 0
|
||||||
|
p['MIXED1IO0'] = 0
|
||||||
|
p['MIXED1IO1'] = 0
|
||||||
|
p['MIXED1IO2'] = 0
|
||||||
|
p['MIXED1IO3'] = 0
|
||||||
|
p['MIXED1IO4'] = 0
|
||||||
|
p['MIXED1IO5'] = 0
|
||||||
|
p['MIXED1IO6'] = 0
|
||||||
|
p['MIXED1IO7'] = 0
|
||||||
|
p['MIXED1IO8'] = 0
|
||||||
|
p['MIXED1IO9'] = 0
|
||||||
|
p['MIXED1IO10'] = 0
|
||||||
|
p['MIXED1IO11'] = 0
|
||||||
|
p['MIXED1IO12'] = 0
|
||||||
|
p['MIXED1IO13'] = 0
|
||||||
|
p['MIXED1IO14'] = 0
|
||||||
|
p['MIXED1IO15'] = 0
|
||||||
|
p['MIXED1IO16'] = 0
|
||||||
|
p['MIXED1IO17'] = 0
|
||||||
|
p['MIXED1IO18'] = 0
|
||||||
|
p['MIXED1IO19'] = 0
|
||||||
|
p['MIXED1IO20'] = 0
|
||||||
|
p['MIXED1IO21'] = 0
|
||||||
|
p['MIXED2IO0'] = 0
|
||||||
|
p['MIXED2IO1'] = 0
|
||||||
|
p['MIXED2IO2'] = 0
|
||||||
|
p['MIXED2IO3'] = 0
|
||||||
|
p['MIXED2IO4'] = 0
|
||||||
|
p['MIXED2IO5'] = 0
|
||||||
|
p['MIXED2IO6'] = 0
|
||||||
|
p['MIXED2IO7'] = 0
|
||||||
|
p['GPLINMUX48'] = 0
|
||||||
|
p['GPLINMUX49'] = 0
|
||||||
|
p['GPLINMUX50'] = 0
|
||||||
|
p['GPLINMUX51'] = 0
|
||||||
|
p['GPLINMUX52'] = 0
|
||||||
|
p['GPLINMUX53'] = 0
|
||||||
|
p['GPLINMUX54'] = 0
|
||||||
|
p['GPLINMUX55'] = 0
|
||||||
|
p['GPLINMUX56'] = 0
|
||||||
|
p['GPLINMUX57'] = 0
|
||||||
|
p['GPLINMUX58'] = 0
|
||||||
|
p['GPLINMUX59'] = 0
|
||||||
|
p['GPLINMUX60'] = 0
|
||||||
|
p['GPLINMUX61'] = 0
|
||||||
|
p['GPLINMUX62'] = 0
|
||||||
|
p['GPLINMUX63'] = 0
|
||||||
|
p['GPLINMUX64'] = 0
|
||||||
|
p['GPLINMUX65'] = 0
|
||||||
|
p['GPLINMUX66'] = 0
|
||||||
|
p['GPLINMUX67'] = 0
|
||||||
|
p['GPLINMUX68'] = 0
|
||||||
|
p['GPLINMUX69'] = 0
|
||||||
|
p['GPLINMUX70'] = 0
|
||||||
|
p['GPLMUX0'] = 1
|
||||||
|
p['GPLMUX1'] = 1
|
||||||
|
p['GPLMUX2'] = 1
|
||||||
|
p['GPLMUX3'] = 1
|
||||||
|
p['GPLMUX4'] = 1
|
||||||
|
p['GPLMUX5'] = 1
|
||||||
|
p['GPLMUX6'] = 1
|
||||||
|
p['GPLMUX7'] = 1
|
||||||
|
p['GPLMUX8'] = 1
|
||||||
|
p['GPLMUX9'] = 1
|
||||||
|
p['GPLMUX10'] = 1
|
||||||
|
p['GPLMUX11'] = 1
|
||||||
|
p['GPLMUX12'] = 1
|
||||||
|
p['GPLMUX13'] = 1
|
||||||
|
p['GPLMUX14'] = 1
|
||||||
|
p['GPLMUX15'] = 1
|
||||||
|
p['GPLMUX16'] = 1
|
||||||
|
p['GPLMUX17'] = 1
|
||||||
|
p['GPLMUX18'] = 1
|
||||||
|
p['GPLMUX19'] = 1
|
||||||
|
p['GPLMUX20'] = 1
|
||||||
|
p['GPLMUX21'] = 1
|
||||||
|
p['GPLMUX22'] = 1
|
||||||
|
p['GPLMUX23'] = 1
|
||||||
|
p['GPLMUX24'] = 1
|
||||||
|
p['GPLMUX25'] = 1
|
||||||
|
p['GPLMUX26'] = 1
|
||||||
|
p['GPLMUX27'] = 1
|
||||||
|
p['GPLMUX28'] = 1
|
||||||
|
p['GPLMUX29'] = 1
|
||||||
|
p['GPLMUX30'] = 1
|
||||||
|
p['GPLMUX31'] = 1
|
||||||
|
p['GPLMUX32'] = 1
|
||||||
|
p['GPLMUX33'] = 1
|
||||||
|
p['GPLMUX34'] = 1
|
||||||
|
p['GPLMUX35'] = 1
|
||||||
|
p['GPLMUX36'] = 1
|
||||||
|
p['GPLMUX37'] = 1
|
||||||
|
p['GPLMUX38'] = 1
|
||||||
|
p['GPLMUX39'] = 1
|
||||||
|
p['GPLMUX40'] = 1
|
||||||
|
p['GPLMUX41'] = 1
|
||||||
|
p['GPLMUX42'] = 1
|
||||||
|
p['GPLMUX43'] = 1
|
||||||
|
p['GPLMUX44'] = 1
|
||||||
|
p['GPLMUX45'] = 1
|
||||||
|
p['GPLMUX46'] = 1
|
||||||
|
p['GPLMUX47'] = 1
|
||||||
|
p['GPLMUX48'] = 1
|
||||||
|
p['GPLMUX49'] = 1
|
||||||
|
p['GPLMUX50'] = 1
|
||||||
|
p['GPLMUX51'] = 1
|
||||||
|
p['GPLMUX52'] = 1
|
||||||
|
p['GPLMUX53'] = 1
|
||||||
|
p['GPLMUX54'] = 1
|
||||||
|
p['GPLMUX55'] = 1
|
||||||
|
p['GPLMUX56'] = 1
|
||||||
|
p['GPLMUX57'] = 1
|
||||||
|
p['GPLMUX58'] = 1
|
||||||
|
p['GPLMUX59'] = 1
|
||||||
|
p['GPLMUX60'] = 1
|
||||||
|
p['GPLMUX61'] = 1
|
||||||
|
p['GPLMUX62'] = 1
|
||||||
|
p['GPLMUX63'] = 1
|
||||||
|
p['GPLMUX64'] = 1
|
||||||
|
p['GPLMUX65'] = 1
|
||||||
|
p['GPLMUX66'] = 1
|
||||||
|
p['GPLMUX67'] = 1
|
||||||
|
p['GPLMUX68'] = 1
|
||||||
|
p['GPLMUX69'] = 1
|
||||||
|
p['GPLMUX70'] = 1
|
||||||
|
p['NANDUSEFPGA'] = 0
|
||||||
|
p['UART0USEFPGA'] = 0
|
||||||
|
p['RGMII1USEFPGA'] = 0
|
||||||
|
p['SPIS0USEFPGA'] = 0
|
||||||
|
p['CAN0USEFPGA'] = 0
|
||||||
|
p['I2C0USEFPGA'] = 0
|
||||||
|
p['SDMMCUSEFPGA'] = 0
|
||||||
|
p['QSPIUSEFPGA'] = 0
|
||||||
|
p['SPIS1USEFPGA'] = 0
|
||||||
|
p['RGMII0USEFPGA'] = 0
|
||||||
|
p['UART1USEFPGA'] = 0
|
||||||
|
p['CAN1USEFPGA'] = 0
|
||||||
|
p['USB1USEFPGA'] = 0
|
||||||
|
p['I2C3USEFPGA'] = 0
|
||||||
|
p['I2C2USEFPGA'] = 0
|
||||||
|
p['I2C1USEFPGA'] = 0
|
||||||
|
p['SPIM1USEFPGA'] = 0
|
||||||
|
p['USB0USEFPGA'] = 0
|
||||||
|
p['SPIM0USEFPGA'] = 0
|
||||||
|
|
||||||
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_pinmux_configs(self):
|
||||||
|
""" Get default pinmux values """
|
||||||
|
p = collections.OrderedDict()
|
||||||
|
|
||||||
|
p['rgmii0'] = { 'name': 'CFG_HPS_EMAC0', 'used': 0 }
|
||||||
|
p['rgmii1'] = { 'name': 'CFG_HPS_EMAC1', 'used': 0 }
|
||||||
|
p['usb0'] = { 'name': 'CFG_HPS_USB0', 'used': 0 }
|
||||||
|
p['usb1'] = { 'name': 'CFG_HPS_USB1', 'used': 0 }
|
||||||
|
p['nand'] = { 'name': 'CFG_HPS_NAND', 'used': 0 }
|
||||||
|
p['sdmmc'] = { 'name': 'CFG_HPS_SDMMC', 'used': 0 }
|
||||||
|
p['CFG_HPS_SDMMC_BUSWIDTH'] = { 'name': 'CFG_HPS_SDMMC_BUSWIDTH', 'used': 0 }
|
||||||
|
p['qspi'] = { 'name': 'CFG_HPS_QSPI', 'used': 0 }
|
||||||
|
p['CFG_HPS_QSPI_CS3'] = { 'name': 'CFG_HPS_QSPI_CS3', 'used': 0 }
|
||||||
|
p['CFG_HPS_QSPI_CS2'] = { 'name': 'CFG_HPS_QSPI_CS2', 'used': 0 }
|
||||||
|
p['CFG_HPS_QSPI_CS1'] = { 'name': 'CFG_HPS_QSPI_CS1', 'used': 0 }
|
||||||
|
p['CFG_HPS_QSPI_CS0'] = { 'name': 'CFG_HPS_QSPI_CS0', 'used': 0 }
|
||||||
|
p['uart0'] = { 'name': 'CFG_HPS_UART0', 'used': 0 }
|
||||||
|
p['CFG_HPS_UART0_TX'] = { 'name': 'CFG_HPS_UART0_TX', 'used': 0 }
|
||||||
|
p['CFG_HPS_UART0_CTS'] = { 'name': 'CFG_HPS_UART0_CTS', 'used': 0 }
|
||||||
|
p['CFG_HPS_UART0_RTS'] = { 'name': 'CFG_HPS_UART0_RTS', 'used': 0 }
|
||||||
|
p['CFG_HPS_UART0_RX'] = { 'name': 'CFG_HPS_UART0_RX', 'used': 0 }
|
||||||
|
p['uart1'] = { 'name': 'CFG_HPS_UART1', 'used': 0 }
|
||||||
|
p['CFG_HPS_UART1_TX'] = { 'name': 'CFG_HPS_UART1_TX', 'used': 0 }
|
||||||
|
p['CFG_HPS_UART1_CTS'] = { 'name': 'CFG_HPS_UART1_CTS', 'used': 0 }
|
||||||
|
p['CFG_HPS_UART1_RTS'] = { 'name': 'CFG_HPS_UART1_RTS', 'used': 0 }
|
||||||
|
p['CFG_HPS_UART1_RX'] = { 'name': 'CFG_HPS_UART1_RX', 'used': 0 }
|
||||||
|
p['trace'] = { 'name': 'CFG_HPS_TRACE', 'used': 0 }
|
||||||
|
p['i2c0'] = { 'name': 'CFG_HPS_I2C0', 'used': 0 }
|
||||||
|
p['i2c1'] = { 'name': 'CFG_HPS_I2C1', 'used': 0 }
|
||||||
|
p['i2c2'] = { 'name': 'CFG_HPS_I2C2', 'used': 0 }
|
||||||
|
p['i2c3'] = { 'name': 'CFG_HPS_I2C3', 'used': 0 }
|
||||||
|
p['spim0'] = { 'name': 'CFG_HPS_SPIM0', 'used': 0 }
|
||||||
|
p['spim1'] = { 'name': 'CFG_HPS_SPIM1', 'used': 0 }
|
||||||
|
p['spis0'] = { 'name': 'CFG_HPS_SPIS0', 'used': 0 }
|
||||||
|
p['spis1'] = { 'name': 'CFG_HPS_SPIS1', 'used': 0 }
|
||||||
|
p['can0'] = { 'name': 'CFG_HPS_CAN0', 'used': 0 }
|
||||||
|
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||||
|
|
||||||
|
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||||
|
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||||
|
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||||
|
p['can1'] = { 'name': 'CFG_HPS_CAN1', 'used': 0 }
|
||||||
|
|
||||||
|
return p
|
||||||
|
|
||||||
|
def updateTemplate(self, name, value):
|
||||||
|
""" Update Makefile & reset_config.h """
|
||||||
|
pattern = "${" + name + "}"
|
||||||
|
self.makefileTemplate = self.makefileTemplate.replace(pattern, value)
|
||||||
|
self.resetConfigHTemplate = self.resetConfigHTemplate.replace(pattern, value)
|
||||||
|
|
||||||
|
def romanToInteger(self, roman):
|
||||||
|
"""
|
||||||
|
Convert roman numerals to integer
|
||||||
|
Since we only support I,V,X, the
|
||||||
|
supported range is 1-39
|
||||||
|
"""
|
||||||
|
table = { 'I':1 , 'V':5, 'X':10 }
|
||||||
|
|
||||||
|
literals = list(roman)
|
||||||
|
|
||||||
|
value = 0
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
while(i < (len(literals) - 1)):
|
||||||
|
current = table[literals[i]]
|
||||||
|
next = table[literals[i + 1]]
|
||||||
|
if (current < next):
|
||||||
|
value += (next - current)
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
value += current
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if (i < (len(literals))):
|
||||||
|
value += table[literals[i]]
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
def getDeviceFamily(self):
|
||||||
|
""" Get device family """
|
||||||
|
return self.derivedDeviceFamily
|
||||||
|
|
||||||
|
def getDeviceFamilyName(self, deviceFamily):
|
||||||
|
""" Get device family name """
|
||||||
|
p = re.compile('^(\w+)\s+(\w+)$')
|
||||||
|
m = p.match(deviceFamily)
|
||||||
|
return m.group(1).lower() + str(self.romanToInteger(m.group(2)))
|
||||||
|
|
||||||
|
def handleHPSSystemNode(self, systemNode):
|
||||||
|
""" handleHPSPeripheralsNode(peripheralsNode)
|
||||||
|
peripheralsNode is a peripherals element node in hps.xml
|
||||||
|
peripheralsNode is a list of peripheralNodes
|
||||||
|
"""
|
||||||
|
configNode = xmlgrok.firstElementChild(systemNode)
|
||||||
|
while configNode != None:
|
||||||
|
|
||||||
|
name = configNode.getAttribute('name')
|
||||||
|
value = configNode.getAttribute('value')
|
||||||
|
|
||||||
|
self.updateTemplate(name, value)
|
||||||
|
|
||||||
|
if name == "DEVICE_FAMILY":
|
||||||
|
self.derivedDeviceFamily = self.getDeviceFamilyName(value)
|
||||||
|
|
||||||
|
if name == "DMA_Enable":
|
||||||
|
self.dmaEnable = value
|
||||||
|
|
||||||
|
configNode = xmlgrok.nextElementSibling(configNode)
|
||||||
|
|
||||||
|
def handleHPSPeripheralNode(self, peripheralNode):
|
||||||
|
""" This node of the hps.xml may contain a name, value pair
|
||||||
|
We need to:
|
||||||
|
emit a #define for the peripheral for is 'used' state
|
||||||
|
emit a #define for that pair, if it is marked 'used'
|
||||||
|
"""
|
||||||
|
peripheralNode = xmlgrok.firstElementChild(peripheralNode)
|
||||||
|
|
||||||
|
while peripheralNode != None:
|
||||||
|
if peripheralNode.hasAttribute('name') and peripheralNode.hasAttribute('used'):
|
||||||
|
newLine = "\n"
|
||||||
|
name = peripheralNode.getAttribute('name')
|
||||||
|
used = peripheralNode.getAttribute('used')
|
||||||
|
|
||||||
|
if used == 'true' or used == True:
|
||||||
|
used = 1
|
||||||
|
elif used == 'false' or used == False:
|
||||||
|
used = 0
|
||||||
|
|
||||||
|
configs = collections.OrderedDict()
|
||||||
|
|
||||||
|
configNode = xmlgrok.firstElementChild(peripheralNode)
|
||||||
|
while configNode != None:
|
||||||
|
config_define_name = configNode.getAttribute('name')
|
||||||
|
config_define_value = configNode.getAttribute('value')
|
||||||
|
configs[config_define_name] = config_define_value
|
||||||
|
configNode = xmlgrok.nextElementSibling(configNode)
|
||||||
|
if configNode == None:
|
||||||
|
newLine += newLine
|
||||||
|
self.pinmuxConfigBuffer.write("#define " + str(config_define_name) + ' ' + '(' + str(config_define_value) + ')' + newLine)
|
||||||
|
|
||||||
|
entry = self.pinmux_configs[name]
|
||||||
|
define_name = entry['name']
|
||||||
|
|
||||||
|
if (len(configs) > 0):
|
||||||
|
self.pinmux_configs[name] = { 'name': define_name, 'used': used, 'configs': configs }
|
||||||
|
else:
|
||||||
|
self.pinmux_configs[name] = { 'name': define_name, 'used': used }
|
||||||
|
|
||||||
|
# skip the parent peripheral node
|
||||||
|
# since only need to define child config node(s)
|
||||||
|
peripheralNode = xmlgrok.nextElementSibling(peripheralNode)
|
||||||
|
|
||||||
|
def handleHPSPinmuxNode(self, pinmuxNode):
|
||||||
|
""" For a pinmuxNode, we may emit a #define for the name, value pair
|
||||||
|
"""
|
||||||
|
if pinmuxNode.hasAttribute('name') and pinmuxNode.hasAttribute('value'):
|
||||||
|
self.pinmuxArraySize += 1
|
||||||
|
name = pinmuxNode.getAttribute('name')
|
||||||
|
value = pinmuxNode.getAttribute('value')
|
||||||
|
|
||||||
|
def handleHPSPinmuxesNode(self, pinmuxesNode):
|
||||||
|
""" PinmuxesNode is a list of pinmuxNodes
|
||||||
|
"""
|
||||||
|
self.pinmuxHeaderBuffer.write(str("const u8 sys_mgr_init_table[] = {\n"))
|
||||||
|
|
||||||
|
pinmuxNode = xmlgrok.firstElementChild(pinmuxesNode)
|
||||||
|
while pinmuxNode != None:
|
||||||
|
if pinmuxNode.hasAttribute('name') and pinmuxNode.hasAttribute('value'):
|
||||||
|
self.pinmuxArraySize += 1
|
||||||
|
name = pinmuxNode.getAttribute('name')
|
||||||
|
value = pinmuxNode.getAttribute('value')
|
||||||
|
self.pinmux_regs[name] = value
|
||||||
|
pinmuxNode = xmlgrok.nextElementSibling(pinmuxNode)
|
||||||
|
|
||||||
|
reg_count = 0
|
||||||
|
pinmux_regs_count = len(self.pinmux_regs)
|
||||||
|
for reg, value in self.pinmux_regs.items():
|
||||||
|
reg_count += 1
|
||||||
|
if reg_count < pinmux_regs_count:
|
||||||
|
self.pinmuxHeaderBuffer.write(str("\t" + str(value) + ', /* ' + reg + ' */\n' ))
|
||||||
|
else:
|
||||||
|
self.pinmuxHeaderBuffer.write(str("\t" + str(value) + ' /* ' + reg + ' */\n' ))
|
||||||
|
|
||||||
|
# Write the close of the pin MUX array in the header
|
||||||
|
self.pinmuxHeaderBuffer.write(str("};" ))
|
||||||
|
|
||||||
|
def handleHPSClockNode(self, clockNode):
|
||||||
|
""" A clockNode may emit a #define for the name, frequency pair
|
||||||
|
"""
|
||||||
|
if clockNode.hasAttribute('name') and clockNode.hasAttribute('frequency'):
|
||||||
|
name = clockNode.getAttribute('name')
|
||||||
|
frequency = clockNode.getAttribute('frequency')
|
||||||
|
self.clockStream.write("#define " + name + ' ' + '(' + frequency + ')' + '\n')
|
||||||
|
|
||||||
|
def handleHPSClocksNode(self, clocksNode):
|
||||||
|
""" A list of clockNodes is call clocksNode
|
||||||
|
"""
|
||||||
|
self.clockStream = streamer.Streamer(self.outputDir + os.sep + clocksNode.nodeName + '.h', 'w')
|
||||||
|
self.clockStream.open()
|
||||||
|
clockNode = xmlgrok.firstElementChild(clocksNode)
|
||||||
|
while clockNode != None:
|
||||||
|
self.handleHPSClockNode(clockNode)
|
||||||
|
clockNode = xmlgrok.nextElementSibling(clockNode)
|
||||||
|
|
||||||
|
self.clockStream.close()
|
||||||
|
|
||||||
|
def handleHpsFpgaInterfaces(self, node):
|
||||||
|
""" Update FPGA Interface registers """
|
||||||
|
node = xmlgrok.firstElementChild(node)
|
||||||
|
|
||||||
|
while node != None:
|
||||||
|
name = node.getAttribute('name')
|
||||||
|
used = node.getAttribute('used')
|
||||||
|
|
||||||
|
if used == 'true':
|
||||||
|
reset = 0
|
||||||
|
else:
|
||||||
|
reset = 1
|
||||||
|
|
||||||
|
if name == 'F2H_AXI_SLAVE':
|
||||||
|
self.updateTemplate("DERIVED_RESET_ASSERT_FPGA2HPS", str(reset))
|
||||||
|
elif name == 'H2F_AXI_MASTER':
|
||||||
|
self.updateTemplate("DERIVED_RESET_ASSERT_HPS2FPGA", str(reset))
|
||||||
|
elif name == 'LWH2F_AXI_MASTER':
|
||||||
|
self.updateTemplate("DERIVED_RESET_ASSERT_LWHPS2FPGA", str(reset))
|
||||||
|
|
||||||
|
node = xmlgrok.nextElementSibling(node)
|
||||||
|
|
||||||
|
def createFilesFromHPS(self):
|
||||||
|
""" Parse xml and create pinmux_config.h """
|
||||||
|
# Unfortunately we can't determine the file name before
|
||||||
|
# parsing the XML, so let's build up the source file
|
||||||
|
# content in string buffer
|
||||||
|
self.pinmuxHeaderBuffer = CompatStringIO()
|
||||||
|
self.pinmuxConfigBuffer = CompatStringIO()
|
||||||
|
|
||||||
|
# Get a list of all nodes with the hps element name
|
||||||
|
hpsNodeList = self.dom.getElementsByTagName('hps')
|
||||||
|
if len(hpsNodeList) > 1:
|
||||||
|
print ("*** WARNING:" + "Multiple hps Elements found in %s!" % self.hpsInFileName)
|
||||||
|
# For each of the hps element nodes, go through the child list
|
||||||
|
# Note that currently there is only one hps Element
|
||||||
|
# but this code will handle more than one hps node
|
||||||
|
# In the future, multiple hps nodes may need additional code
|
||||||
|
# to combine settings from the multiple hps Elements
|
||||||
|
for hpsNode in hpsNodeList:
|
||||||
|
# Currently, there are only 3 children of the hps Element:
|
||||||
|
# peripherals, pin_muxes, and clocks
|
||||||
|
# but this is left open-ended for future additions to the
|
||||||
|
# specification for the hps.xml
|
||||||
|
childNode = xmlgrok.firstElementChild(hpsNode)
|
||||||
|
while childNode != None:
|
||||||
|
if childNode.nodeName == 'pin_muxes':
|
||||||
|
self.handleHPSPinmuxesNode(childNode)
|
||||||
|
elif childNode.nodeName == 'system':
|
||||||
|
self.handleHPSSystemNode(childNode)
|
||||||
|
elif childNode.nodeName == 'fpga_interfaces':
|
||||||
|
self.handleHpsFpgaInterfaces(childNode)
|
||||||
|
elif childNode.nodeName == 'peripherals':
|
||||||
|
self.handleHPSPeripheralNode(childNode)
|
||||||
|
else:
|
||||||
|
print ("***Error:Found unexpected HPS child node:%s" % childNode.nodeName)
|
||||||
|
childNode = xmlgrok.nextElementSibling(childNode)
|
||||||
|
|
||||||
|
self.updateTemplate("DERIVED_DEVICE_FAMILY", self.derivedDeviceFamily)
|
||||||
|
|
||||||
|
# Now we write string buffers into files once we know the device family
|
||||||
|
self.pinmux_config_h = 'pinmux_config.h'
|
||||||
|
self.pinmux_config_src = 'pinmux_config_' + self.derivedDeviceFamily + '.c'
|
||||||
|
|
||||||
|
# Create pinmux_config .h
|
||||||
|
headerDefine = "__SOCFPGA_PINMUX_CONFIG_H__"
|
||||||
|
self.pinmuxHeaderFile = streamer.Streamer(self.outputDir + os.sep + self.pinmux_config_h, 'w')
|
||||||
|
self.pinmuxHeaderFile.open()
|
||||||
|
self.pinmuxHeaderFile.writeLicenseHeader()
|
||||||
|
self.pinmuxHeaderFile.write('/*\n * Altera SoCFPGA PinMux configuration\n */\n\n')
|
||||||
|
|
||||||
|
self.pinmuxHeaderFile.write("#ifndef " + headerDefine + "\n")
|
||||||
|
self.pinmuxHeaderFile.write("#define " + headerDefine + "\n\n")
|
||||||
|
self.pinmuxHeaderFile.write(self.pinmuxHeaderBuffer.getvalue())
|
||||||
|
self.pinmuxHeaderFile.write("\n#endif /* " + headerDefine + " */\n")
|
||||||
|
self.pinmuxHeaderFile.close()
|
||||||
|
|
||||||
|
# Free up string buffers
|
||||||
|
self.pinmuxHeaderBuffer.close()
|
||||||
|
self.pinmuxConfigBuffer.close()
|
||||||
203
tools/cv_bsp_generator/iocsr.py
Executable file
203
tools/cv_bsp_generator/iocsr.py
Executable file
@@ -0,0 +1,203 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
"""
|
||||||
|
IOCSR header file generator
|
||||||
|
|
||||||
|
Process the hiof file from Quartus and generate iocsr header
|
||||||
|
usable by U-Boot.
|
||||||
|
|
||||||
|
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||||
|
|
||||||
|
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
import streamer
|
||||||
|
|
||||||
|
class IOCSRGrokker(object):
|
||||||
|
""" Decode the .hiof file and produce some C source code
|
||||||
|
"""
|
||||||
|
IOCSR_ROOT_FILENAME = 'iocsr_config'
|
||||||
|
IOCSR_SENTINEL = '__SOCFPGA_IOCSR_CONFIG_H__'
|
||||||
|
IOCSR_FILE_EXTENSION_MAX_LEN = 6
|
||||||
|
PTAG_HPS_IOCSR_INFO = 39
|
||||||
|
PTAG_HPS_IOCSR = 40
|
||||||
|
PTAG_DEVICE_NAME = 2
|
||||||
|
PTAG_TERMINATION = 8
|
||||||
|
|
||||||
|
def __init__(self, deviceFamily, inputDir, outputDir, hiofSrcFileName):
|
||||||
|
""" IOCSRGrokker Initialization """
|
||||||
|
self.deviceFamily = deviceFamily
|
||||||
|
self.inputDir = inputDir
|
||||||
|
self.outputDir = outputDir
|
||||||
|
self.hiofInFileName = hiofSrcFileName
|
||||||
|
self.iocsrFileName = self.IOCSR_ROOT_FILENAME
|
||||||
|
self.headerOut = None
|
||||||
|
self.sourceOut = None
|
||||||
|
self.createFilesFromHIOF()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def byteArrayToStr(bytes):
|
||||||
|
""" Convert a list of bytes into a string
|
||||||
|
"""
|
||||||
|
# We don't like nulls
|
||||||
|
bytes = bytes.replace('\x00', '')
|
||||||
|
s = ''
|
||||||
|
for b in bytes:
|
||||||
|
s += b
|
||||||
|
return s
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getLengthData(bytes):
|
||||||
|
"""
|
||||||
|
@param: bytes is a chunk of bytes that we need to decode
|
||||||
|
There will be a ptag that we may care about.
|
||||||
|
If we care about it, we will get the length of the chunk
|
||||||
|
that the ptag cares about.
|
||||||
|
@rtype: a pair, length of chunk and the chunk itself
|
||||||
|
@return: length of the ptag chunk we care about
|
||||||
|
@return: data chunk that ptag indicates we need to decode
|
||||||
|
"""
|
||||||
|
blockSize = len(bytes)
|
||||||
|
i = 0
|
||||||
|
bitlength = 0
|
||||||
|
length = 0
|
||||||
|
data = []
|
||||||
|
|
||||||
|
while i < blockSize:
|
||||||
|
byte = struct.unpack('B', bytes[i:i+1])[0]
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if byte == 1:
|
||||||
|
bitlength = struct.unpack('I', bytes[i:i+4])[0]
|
||||||
|
i += 4
|
||||||
|
elif byte == 2:
|
||||||
|
length = struct.unpack('I', bytes[i:i+4])[0]
|
||||||
|
i += 4
|
||||||
|
|
||||||
|
elif byte == 5:
|
||||||
|
j = 0
|
||||||
|
while i < blockSize:
|
||||||
|
data.append(struct.unpack('I', bytes[i:i+4])[0])
|
||||||
|
i += 4
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
else:
|
||||||
|
i += 4
|
||||||
|
|
||||||
|
return (bitlength, data)
|
||||||
|
|
||||||
|
|
||||||
|
def verifyRead(self, tagWeRead, tagWeExpected):
|
||||||
|
""" verify the hiof value with tag expected """
|
||||||
|
if tagWeRead != tagWeExpected:
|
||||||
|
print ("***Error: Expected ptag of %02d, but got %02d" % (tagWeExpected, tagWeRead))
|
||||||
|
|
||||||
|
def createFilesFromHIOF(self):
|
||||||
|
""" read the hiof file to create iocsr_config.h """
|
||||||
|
self.hiofStream = streamer.Streamer(self.inputDir + os.sep + self.hiofInFileName, 'rb')
|
||||||
|
self.iocsrHeaderStream = streamer.Streamer(self.outputDir + os.sep + self.iocsrFileName + '.h', 'w')
|
||||||
|
self.hiofStream.open()
|
||||||
|
self.iocsrHeaderStream.open()
|
||||||
|
self.iocsrHeaderStream.writeLicenseHeader()
|
||||||
|
self.iocsrHeaderStream.write('/*\n * Altera SoCFPGA IOCSR configuration\n */\n\n')
|
||||||
|
ret = self.iocsrHeaderStream.writeSentinelStart(IOCSRGrokker.IOCSR_SENTINEL)
|
||||||
|
if ret == -1:
|
||||||
|
print("Empty header written. Exiting.")
|
||||||
|
|
||||||
|
# Read the file extension (typically .hiof)
|
||||||
|
# and the file version
|
||||||
|
self.fileExtension = self.hiofStream.readBytesAsString(IOCSRGrokker.IOCSR_FILE_EXTENSION_MAX_LEN)
|
||||||
|
self.fileVersion = self.hiofStream.readUnsignedInt()
|
||||||
|
|
||||||
|
# Now read the ptags
|
||||||
|
# Device name is first
|
||||||
|
self.programmerTag = self.hiofStream.readUnsignedShort()
|
||||||
|
self.verifyRead(self.programmerTag, self.PTAG_DEVICE_NAME)
|
||||||
|
self.deviceNameLength = self.hiofStream.readUnsignedInt()
|
||||||
|
self.deviceName = self.hiofStream.readBytesAsString(self.deviceNameLength)
|
||||||
|
|
||||||
|
# Basic information of the HIOF files
|
||||||
|
# This is not used by the preloader generator, but we read it and ignore the
|
||||||
|
# contents.
|
||||||
|
programmerTag = self.hiofStream.readUnsignedShort()
|
||||||
|
self.verifyRead(programmerTag, self.PTAG_HPS_IOCSR_INFO)
|
||||||
|
basicHPSIOCSRInfoLength = self.hiofStream.readUnsignedInt()
|
||||||
|
self.hiofStream.read(basicHPSIOCSRInfoLength)
|
||||||
|
|
||||||
|
# Actual content of IOCSR information
|
||||||
|
self.programmerTag1 = self.hiofStream.readUnsignedShort()
|
||||||
|
self.verifyRead(self.programmerTag1, self.PTAG_HPS_IOCSR)
|
||||||
|
self.HPSIOCSRLength1 = self.hiofStream.readUnsignedInt()
|
||||||
|
self.HPSIOCSRBytes1 = self.hiofStream.read(self.HPSIOCSRLength1)
|
||||||
|
self.HPSIOCSRDataLength1, self.HPSIOCSRData1 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes1)
|
||||||
|
|
||||||
|
# Actual content of IOCSR information
|
||||||
|
self.programmerTag2 = self.hiofStream.readUnsignedShort()
|
||||||
|
self.verifyRead(self.programmerTag2, self.PTAG_HPS_IOCSR)
|
||||||
|
self.HPSIOCSRLength2 = self.hiofStream.readUnsignedInt()
|
||||||
|
self.HPSIOCSRBytes2 = self.hiofStream.read(self.HPSIOCSRLength2)
|
||||||
|
self.HPSIOCSRDataLength2, self.HPSIOCSRData2 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes2)
|
||||||
|
|
||||||
|
# Actual content of IOCSR information
|
||||||
|
self.programmerTag3 = self.hiofStream.readUnsignedShort()
|
||||||
|
self.verifyRead(self.programmerTag3, self.PTAG_HPS_IOCSR)
|
||||||
|
self.HPSIOCSRLength3 = self.hiofStream.readUnsignedInt()
|
||||||
|
self.HPSIOCSRBytes3 = self.hiofStream.read(self.HPSIOCSRLength3)
|
||||||
|
self.HPSIOCSRDataLength3, self.HPSIOCSRData3 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes3)
|
||||||
|
|
||||||
|
# Actual content of IOCSR information
|
||||||
|
self.programmerTag4 = self.hiofStream.readUnsignedShort()
|
||||||
|
self.verifyRead(self.programmerTag4, self.PTAG_HPS_IOCSR)
|
||||||
|
self.HPSIOCSRLength4 = self.hiofStream.readUnsignedInt()
|
||||||
|
self.HPSIOCSRBytes4 = self.hiofStream.read(self.HPSIOCSRLength4)
|
||||||
|
self.HPSIOCSRDataLength4, self.HPSIOCSRData4 = IOCSRGrokker.getLengthData(self.HPSIOCSRBytes4)
|
||||||
|
|
||||||
|
# Now we should see the end of the hiof input
|
||||||
|
programmerTag = self.hiofStream.readUnsignedShort()
|
||||||
|
if 8 != programmerTag:
|
||||||
|
print ("I didn't find the end of the .hiof file when I expected to!")
|
||||||
|
|
||||||
|
self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN0_LENGTH\t' +\
|
||||||
|
str(self.HPSIOCSRDataLength1) + '\n')
|
||||||
|
self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN1_LENGTH\t' +\
|
||||||
|
str(self.HPSIOCSRDataLength2) + '\n')
|
||||||
|
self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN2_LENGTH\t' +\
|
||||||
|
str(self.HPSIOCSRDataLength3) + '\n')
|
||||||
|
self.iocsrHeaderStream.write('#define CFG_HPS_IOCSR_SCANCHAIN3_LENGTH\t' +\
|
||||||
|
str(self.HPSIOCSRDataLength4) + '\n')
|
||||||
|
|
||||||
|
self.iocsrHeaderStream.write("\n")
|
||||||
|
|
||||||
|
self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain0_table[] = {\n')
|
||||||
|
for value in self.HPSIOCSRData1:
|
||||||
|
hv = '0x%08X' % (value)
|
||||||
|
self.iocsrHeaderStream.write('\t' + hv + ',\n')
|
||||||
|
self.iocsrHeaderStream.write('};\n')
|
||||||
|
self.iocsrHeaderStream.write('\n')
|
||||||
|
|
||||||
|
self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain1_table[] = {\n')
|
||||||
|
for value in self.HPSIOCSRData2:
|
||||||
|
hv = '0x%08X' % (value)
|
||||||
|
self.iocsrHeaderStream.write('\t' + hv + ',\n')
|
||||||
|
self.iocsrHeaderStream.write('};\n')
|
||||||
|
self.iocsrHeaderStream.write('\n')
|
||||||
|
|
||||||
|
self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain2_table[] = {\n')
|
||||||
|
for value in self.HPSIOCSRData3:
|
||||||
|
hv = '0x%08X' % (value)
|
||||||
|
self.iocsrHeaderStream.write('\t' + hv + ',\n')
|
||||||
|
self.iocsrHeaderStream.write('};\n')
|
||||||
|
self.iocsrHeaderStream.write('\n')
|
||||||
|
|
||||||
|
self.iocsrHeaderStream.write('const unsigned long iocsr_scan_chain3_table[] = {\n')
|
||||||
|
for value in self.HPSIOCSRData4:
|
||||||
|
hv = '0x%08X' % (value)
|
||||||
|
self.iocsrHeaderStream.write('\t' + hv + ',\n')
|
||||||
|
self.iocsrHeaderStream.write('};\n')
|
||||||
|
self.iocsrHeaderStream.write('\n\n')
|
||||||
|
|
||||||
|
ret = self.iocsrHeaderStream.writeSentinelEnd(IOCSRGrokker.IOCSR_SENTINEL)
|
||||||
|
if ret == -1:
|
||||||
|
print("Empty header written. Exiting.")
|
||||||
|
|
||||||
|
self.iocsrHeaderStream.close()
|
||||||
114
tools/cv_bsp_generator/model.py
Executable file
114
tools/cv_bsp_generator/model.py
Executable file
@@ -0,0 +1,114 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
"""
|
||||||
|
Data models for XML files required for generating a preloader.
|
||||||
|
|
||||||
|
These classes encapsulate the complexities of XML DOM in order to
|
||||||
|
make retrieving data from XML files easier and more reliable.
|
||||||
|
By shielding data model deserialization from data consumers,
|
||||||
|
it'd be easier to switch to other formats such as JSON if required.
|
||||||
|
|
||||||
|
There are some assumptions about how these XML files are structured
|
||||||
|
such as the hierarchy of elements and ordering of attributes, these
|
||||||
|
are relatively safe assumptions for as long as the XML files are
|
||||||
|
always generated by HPS megawizard (isw.tcl) and are not hand-edited.
|
||||||
|
|
||||||
|
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||||
|
|
||||||
|
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||||
|
"""
|
||||||
|
import xml.dom.minidom
|
||||||
|
|
||||||
|
def getSingletonElementByTagName(parent, tagName):
|
||||||
|
"""
|
||||||
|
Find tag by name and ensure that there is exactly one match
|
||||||
|
"""
|
||||||
|
nodes = parent.getElementsByTagName(tagName)
|
||||||
|
|
||||||
|
if len(nodes) == 0:
|
||||||
|
raise Exception("Can't find element: " + tagName)
|
||||||
|
elif len(nodes) > 1:
|
||||||
|
raise Exception("Unexpected multiple matches for singleton element: " + tagName)
|
||||||
|
else:
|
||||||
|
return nodes[0]
|
||||||
|
|
||||||
|
class hps(object):
|
||||||
|
"""
|
||||||
|
Data model for hps.xml
|
||||||
|
"""
|
||||||
|
@staticmethod
|
||||||
|
def create(file):
|
||||||
|
""" hps model """
|
||||||
|
return hps(file)
|
||||||
|
|
||||||
|
def __init__(self, file):
|
||||||
|
""" hps model initialization """
|
||||||
|
self.dom = xml.dom.minidom.parse(file)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Look for <hps> node
|
||||||
|
self.hpsNode = getSingletonElementByTagName(self.dom, "hps")
|
||||||
|
# Look for <hps><system> node
|
||||||
|
self.hpsSystemNode = getSingletonElementByTagName(self.hpsNode, "system")
|
||||||
|
except Exception:
|
||||||
|
raise Exception("Can't initialize from file: " + file)
|
||||||
|
|
||||||
|
def getSystemConfig(self, param):
|
||||||
|
""" parse system configuration tag """
|
||||||
|
hpsSystemConfigNode = None
|
||||||
|
|
||||||
|
# Look for <hps><system><config ...> nodes
|
||||||
|
for node in self.hpsSystemNode.getElementsByTagName("config"):
|
||||||
|
# assume name is the first attribute as in <config name="..." ...>
|
||||||
|
nameAttrNode = node.attributes.item(0)
|
||||||
|
if nameAttrNode.nodeName == "name" and nameAttrNode.nodeValue == param:
|
||||||
|
# assume value is the second attribute as in <config name="..." value="...">
|
||||||
|
valueAttrNode = node.attributes.item(1)
|
||||||
|
if valueAttrNode.nodeName == "value":
|
||||||
|
hpsSystemConfigNode = valueAttrNode
|
||||||
|
break
|
||||||
|
|
||||||
|
if hpsSystemConfigNode == None:
|
||||||
|
raise ValueError("Can't find <hps><system><config> node: " + param)
|
||||||
|
|
||||||
|
return hpsSystemConfigNode.nodeValue
|
||||||
|
|
||||||
|
class emif(object):
|
||||||
|
"""
|
||||||
|
Data model for emif.xml.
|
||||||
|
"""
|
||||||
|
@staticmethod
|
||||||
|
def create(file):
|
||||||
|
""" emif model """
|
||||||
|
return emif(file)
|
||||||
|
|
||||||
|
def __init__(self, file):
|
||||||
|
""" emif model initialization """
|
||||||
|
self.dom = xml.dom.minidom.parse(file)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Look for <emif> node
|
||||||
|
self.emifNode = getSingletonElementByTagName(self.dom, "emif")
|
||||||
|
# Look for <emif><pll> node
|
||||||
|
self.emifPllNode = getSingletonElementByTagName(self.emifNode, "pll")
|
||||||
|
except Exception:
|
||||||
|
raise Exception("Can't initialize from file: " + file)
|
||||||
|
|
||||||
|
def getPllDefine(self, param):
|
||||||
|
""" parse pll define tag """
|
||||||
|
emifPllDefineNode = None
|
||||||
|
|
||||||
|
# Look for <emif><pll><define ...> nodes
|
||||||
|
for node in self.emifPllNode.getElementsByTagName("define"):
|
||||||
|
nameAttrNode = node.attributes.item(0)
|
||||||
|
# assume name is the first attribute as in <define name="..." ...>
|
||||||
|
if nameAttrNode.nodeName == "name" and nameAttrNode.nodeValue == param:
|
||||||
|
# assume value is the second attribute as in <config name="..." value="...">
|
||||||
|
valueAttrNode = node.attributes.item(1)
|
||||||
|
if valueAttrNode.nodeName == "value":
|
||||||
|
emifPllDefineNode = valueAttrNode
|
||||||
|
break
|
||||||
|
|
||||||
|
if emifPllDefineNode == None:
|
||||||
|
raise Exception("Can't find EMIF PLL define node: " + param)
|
||||||
|
|
||||||
|
return emifPllDefineNode.nodeValue
|
||||||
196
tools/cv_bsp_generator/renderer.py
Executable file
196
tools/cv_bsp_generator/renderer.py
Executable file
@@ -0,0 +1,196 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
"""
|
||||||
|
Document renderer class for preloader source files
|
||||||
|
|
||||||
|
Each document renderer takes care of a full construction of
|
||||||
|
a specific file format using the required data model.
|
||||||
|
|
||||||
|
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||||
|
|
||||||
|
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||||
|
"""
|
||||||
|
import collections
|
||||||
|
import doc
|
||||||
|
|
||||||
|
class pll_config_h:
|
||||||
|
"""
|
||||||
|
pll_config.h renderer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, hpsModel, emifModel):
|
||||||
|
""" renderer initialization """
|
||||||
|
self.hpsModel = hpsModel
|
||||||
|
self.emifModel = emifModel
|
||||||
|
self.doc = doc.generated_c_source("__SOCFPGA_PLL_CONFIG_H__")
|
||||||
|
|
||||||
|
def createContent(self):
|
||||||
|
""" add the content based on settings parsed. eventually it will be
|
||||||
|
written to pll_config.h file
|
||||||
|
"""
|
||||||
|
doc.c_source.line(self.doc)
|
||||||
|
id = "CFG_HPS_DBCTRL_STAYOSC1"
|
||||||
|
valueString = self.hpsModel.getSystemConfig("dbctrl_stayosc1")
|
||||||
|
# Unfortunately hps.xml never tells us the data type of values
|
||||||
|
# attributes. Here we workaround this type of problem, often
|
||||||
|
# this is case-by-case, i.e. having to know which parameter that
|
||||||
|
# we're dealing with, hence this ugly parameter-specific
|
||||||
|
# if-statement needs here to workaround the data type inconsistency
|
||||||
|
if valueString.lower() == "true":
|
||||||
|
value = "1"
|
||||||
|
else:
|
||||||
|
value = "0"
|
||||||
|
doc.c_source.define(self.doc, id, value )
|
||||||
|
doc.c_source.line(self.doc)
|
||||||
|
self.addMainPllSettings()
|
||||||
|
doc.c_source.line(self.doc)
|
||||||
|
self.addPeriphPllSettings()
|
||||||
|
doc.c_source.line(self.doc)
|
||||||
|
self.addSdramPllSettings()
|
||||||
|
doc.c_source.line(self.doc)
|
||||||
|
self.addClockFreq()
|
||||||
|
doc.c_source.line(self.doc)
|
||||||
|
self.addAlteraSettings()
|
||||||
|
doc.c_source.line(self.doc)
|
||||||
|
|
||||||
|
def addMainPllSettings(self):
|
||||||
|
""" add pll settings to the file """
|
||||||
|
paramMap = collections.OrderedDict()
|
||||||
|
paramMap["VCO_DENOM"] = "main_pll_n"
|
||||||
|
paramMap["VCO_NUMER"] = "main_pll_m"
|
||||||
|
|
||||||
|
for key in paramMap.keys():
|
||||||
|
id = "CFG_HPS_MAINPLLGRP_" + key
|
||||||
|
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||||
|
doc.c_source.define(self.doc, id, value )
|
||||||
|
|
||||||
|
# main_pll_c0, main_pll_c1, main_pll_c2 are fixed counters,
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_MAINPLLGRP_MPUCLK_CNT", "0")
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_MAINPLLGRP_MAINCLK_CNT", "0")
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_MAINPLLGRP_DBGATCLK_CNT", "0")
|
||||||
|
|
||||||
|
paramMap = collections.OrderedDict()
|
||||||
|
|
||||||
|
paramMap["MAINQSPICLK_CNT"] = "main_pll_c3"
|
||||||
|
paramMap["MAINNANDSDMMCCLK_CNT"] = "main_pll_c4"
|
||||||
|
paramMap["CFGS2FUSER0CLK_CNT"] = "main_pll_c5"
|
||||||
|
paramMap["MAINDIV_L3MPCLK"] = "l3_mp_clk_div"
|
||||||
|
paramMap["MAINDIV_L3SPCLK"] = "l3_sp_clk_div"
|
||||||
|
paramMap["MAINDIV_L4MPCLK"] = "l4_mp_clk_div"
|
||||||
|
paramMap["MAINDIV_L4SPCLK"] = "l4_sp_clk_div"
|
||||||
|
paramMap["DBGDIV_DBGATCLK"] = "dbg_at_clk_div"
|
||||||
|
paramMap["DBGDIV_DBGCLK"] = "dbg_clk_div"
|
||||||
|
paramMap["TRACEDIV_TRACECLK"] = "dbg_trace_clk_div"
|
||||||
|
paramMap["L4SRC_L4MP"] = "l4_mp_clk_source"
|
||||||
|
paramMap["L4SRC_L4SP"] = "l4_sp_clk_source"
|
||||||
|
|
||||||
|
for key in paramMap.keys():
|
||||||
|
id = "CFG_HPS_MAINPLLGRP_" + key
|
||||||
|
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||||
|
doc.c_source.define(self.doc, id, value )
|
||||||
|
|
||||||
|
def addPeriphPllSettings(self):
|
||||||
|
""" add peripheral pll settings to the file """
|
||||||
|
paramMap = collections.OrderedDict()
|
||||||
|
paramMap["VCO_DENOM"] = "periph_pll_n"
|
||||||
|
paramMap["VCO_NUMER"] = "periph_pll_m"
|
||||||
|
paramMap["VCO_PSRC"] = "periph_pll_source"
|
||||||
|
paramMap["EMAC0CLK_CNT"] = "periph_pll_c0"
|
||||||
|
paramMap["EMAC1CLK_CNT"] = "periph_pll_c1"
|
||||||
|
paramMap["PERQSPICLK_CNT"] = "periph_pll_c2"
|
||||||
|
paramMap["PERNANDSDMMCCLK_CNT"] = "periph_pll_c3"
|
||||||
|
paramMap["PERBASECLK_CNT"] = "periph_pll_c4"
|
||||||
|
paramMap["S2FUSER1CLK_CNT"] = "periph_pll_c5"
|
||||||
|
paramMap["DIV_USBCLK"] = "usb_mp_clk_div"
|
||||||
|
paramMap["DIV_SPIMCLK"] = "spi_m_clk_div"
|
||||||
|
paramMap["DIV_CAN0CLK"] = "can0_clk_div"
|
||||||
|
paramMap["DIV_CAN1CLK"] = "can1_clk_div"
|
||||||
|
paramMap["GPIODIV_GPIODBCLK"] = "gpio_db_clk_div"
|
||||||
|
paramMap["SRC_SDMMC"] = "sdmmc_clk_source"
|
||||||
|
paramMap["SRC_NAND"] = "nand_clk_source"
|
||||||
|
paramMap["SRC_QSPI"] = "qspi_clk_source"
|
||||||
|
|
||||||
|
for key in paramMap.keys():
|
||||||
|
id = "CFG_HPS_PERPLLGRP_" + key
|
||||||
|
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||||
|
doc.c_source.define(self.doc, id, value )
|
||||||
|
|
||||||
|
def addSdramPllSettings(self):
|
||||||
|
""" add sdram pll settings to the file """
|
||||||
|
value = self.emifModel.getPllDefine("PLL_MEM_CLK_DIV")
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_VCO_DENOM", value )
|
||||||
|
value = self.emifModel.getPllDefine("PLL_MEM_CLK_MULT")
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_VCO_NUMER", value )
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_VCO_SSRC", "0")
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQSCLK_CNT", "1")
|
||||||
|
value = self.emifModel.getPllDefine("PLL_MEM_CLK_PHASE_DEG")
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQSCLK_PHASE", value )
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDR2XDQSCLK_CNT", "0")
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDR2XDQSCLK_PHASE", "0")
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQCLK_CNT", "1")
|
||||||
|
value = self.emifModel.getPllDefine("PLL_WRITE_CLK_PHASE_DEG")
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_DDRDQCLK_PHASE", value )
|
||||||
|
|
||||||
|
try:
|
||||||
|
value = self.hpsModel.getSystemConfig("sdram_pll_c5")
|
||||||
|
except ValueError:
|
||||||
|
value = "5"
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_S2FUSER2CLK_CNT", value )
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_SDRPLLGRP_S2FUSER2CLK_PHASE", "0")
|
||||||
|
|
||||||
|
def addClockFreq(self):
|
||||||
|
""" add clock frequency settings to the file """
|
||||||
|
paramMap = collections.OrderedDict()
|
||||||
|
paramMap["OSC1"] = "eosc1_clk_hz"
|
||||||
|
paramMap["OSC2"] = "eosc2_clk_hz"
|
||||||
|
paramMap["F2S_SDR_REF"] = "F2SCLK_SDRAMCLK_FREQ"
|
||||||
|
paramMap["F2S_PER_REF"] = "F2SCLK_PERIPHCLK_FREQ"
|
||||||
|
paramMap["MAINVCO"] = "main_pll_vco_hz"
|
||||||
|
paramMap["PERVCO"] = "periph_pll_vco_hz"
|
||||||
|
|
||||||
|
for key in paramMap.keys():
|
||||||
|
id = "CFG_HPS_CLK_" + key + "_HZ"
|
||||||
|
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||||
|
doc.c_source.define(self.doc, id, value )
|
||||||
|
|
||||||
|
eosc1 = int(self.hpsModel.getSystemConfig("eosc1_clk_hz"))
|
||||||
|
eosc2 = int(self.hpsModel.getSystemConfig("eosc2_clk_hz"))
|
||||||
|
m = int(self.emifModel.getPllDefine("PLL_MEM_CLK_MULT"))
|
||||||
|
n = int(self.emifModel.getPllDefine("PLL_MEM_CLK_DIV"))
|
||||||
|
vco = int(round(eosc1 * (m + 1) / (n + 1)))
|
||||||
|
doc.c_source.define(self.doc, "CFG_HPS_CLK_SDRVCO_HZ", str(vco) )
|
||||||
|
|
||||||
|
paramMap = collections.OrderedDict()
|
||||||
|
paramMap["EMAC0"] = "emac0_clk_hz"
|
||||||
|
paramMap["EMAC1"] = "emac1_clk_hz"
|
||||||
|
paramMap["USBCLK"] = "usb_mp_clk_hz"
|
||||||
|
paramMap["NAND"] = "nand_clk_hz"
|
||||||
|
paramMap["SDMMC"] = "sdmmc_clk_hz"
|
||||||
|
paramMap["QSPI"] = "qspi_clk_hz"
|
||||||
|
paramMap["SPIM"] = "spi_m_clk_hz"
|
||||||
|
paramMap["CAN0"] = "can0_clk_hz"
|
||||||
|
paramMap["CAN1"] = "can1_clk_hz"
|
||||||
|
paramMap["GPIODB"] = "gpio_db_clk_hz"
|
||||||
|
paramMap["L4_MP"] = "l4_mp_clk_hz"
|
||||||
|
paramMap["L4_SP"] = "l4_sp_clk_hz"
|
||||||
|
|
||||||
|
for key in paramMap.keys():
|
||||||
|
id = "CFG_HPS_CLK_" + key + "_HZ"
|
||||||
|
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||||
|
doc.c_source.define(self.doc, id, value )
|
||||||
|
|
||||||
|
def addAlteraSettings(self):
|
||||||
|
""" add Altera-related settings to the file """
|
||||||
|
paramMap = collections.OrderedDict()
|
||||||
|
paramMap["MPUCLK"] = "main_pll_c0_internal"
|
||||||
|
paramMap["MAINCLK"] = "main_pll_c1_internal"
|
||||||
|
paramMap["DBGATCLK"] = "main_pll_c2_internal"
|
||||||
|
|
||||||
|
for key in paramMap.keys():
|
||||||
|
id = "CFG_HPS_ALTERAGRP_" + key
|
||||||
|
value = self.hpsModel.getSystemConfig(paramMap[key])
|
||||||
|
doc.c_source.define(self.doc, id, value )
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" convert to string """
|
||||||
|
self.createContent()
|
||||||
|
return str(self.doc)
|
||||||
5
tools/cv_bsp_generator/requirements.txt
Normal file
5
tools/cv_bsp_generator/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# requirements.txt for cv_bsp_generator.py
|
||||||
|
# All dependencies are either standard library modules
|
||||||
|
# or local Python files included in this BSP tool.
|
||||||
|
# No external pip packages are required.
|
||||||
|
|
||||||
102
tools/cv_bsp_generator/streamer.py
Executable file
102
tools/cv_bsp_generator/streamer.py
Executable file
@@ -0,0 +1,102 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
"""
|
||||||
|
Generate license, file header and close tag.
|
||||||
|
|
||||||
|
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||||
|
|
||||||
|
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
import doc
|
||||||
|
|
||||||
|
class Streamer(object):
|
||||||
|
""" Streamer class to generate license, header, and close tag.
|
||||||
|
"""
|
||||||
|
def __init__(self, fileName, mode='r'):
|
||||||
|
""" Streamer initialization """
|
||||||
|
self.fileName = fileName
|
||||||
|
self.mode = mode
|
||||||
|
self.file = None
|
||||||
|
self.sentinel = None
|
||||||
|
if '+' in mode or 'w' in mode or 'a' in mode:
|
||||||
|
self.fileMode = 'write'
|
||||||
|
else:
|
||||||
|
self.fileMode = 'read'
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
""" file close """
|
||||||
|
if self.file != None:
|
||||||
|
self.file.close()
|
||||||
|
self.file = None
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
""" file open """
|
||||||
|
if self.fileName != None:
|
||||||
|
if self.file == None:
|
||||||
|
if self.fileMode == 'write':
|
||||||
|
print ("Generating file: %s..." % self.fileName)
|
||||||
|
else:
|
||||||
|
print ("Reading file: %s..." % self.fileName)
|
||||||
|
self.file = open(self.fileName, self.mode)
|
||||||
|
|
||||||
|
def read(self, numBytes):
|
||||||
|
""" file read number of bytes """
|
||||||
|
if self.file == None:
|
||||||
|
print ("***Error: Attempted to read from unopened file %s" \
|
||||||
|
% (self.fileName))
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return self.file.read(numBytes)
|
||||||
|
|
||||||
|
def readUnsignedInt(self):
|
||||||
|
""" read unsigned integer """
|
||||||
|
return struct.unpack('I', self.read(4))[0]
|
||||||
|
|
||||||
|
def readUnsignedShort(self):
|
||||||
|
""" read unsigned short """
|
||||||
|
return struct.unpack('H', self.read(2))[0]
|
||||||
|
|
||||||
|
def readBytesAsString(self, numBytes):
|
||||||
|
""" Read some bytes from a binary file
|
||||||
|
and interpret the data values as a String
|
||||||
|
"""
|
||||||
|
bytes = self.read(numBytes)
|
||||||
|
s = bytes.decode('utf-8')
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
def write(self, str):
|
||||||
|
""" file write """
|
||||||
|
if self.file == None:
|
||||||
|
print ("***Error: Attempted to write to unopened file %s" \
|
||||||
|
% (self.fileName))
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.file.write("%s" % str)
|
||||||
|
|
||||||
|
def writeLicenseHeader(self):
|
||||||
|
""" write license & copyright """
|
||||||
|
# format the license header
|
||||||
|
licenseHeader = "/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */\n"
|
||||||
|
self.file.write("%s" % licenseHeader)
|
||||||
|
copyrightHeader = "/*\n * Copyright (C) 2022 Intel Corporation <www.intel.com>\n *\n */\n"
|
||||||
|
self.file.write("%s" % copyrightHeader)
|
||||||
|
|
||||||
|
def writeSentinelStart(self, sentinel):
|
||||||
|
""" start header """
|
||||||
|
if sentinel == None:
|
||||||
|
return -1
|
||||||
|
self.sentinel = sentinel
|
||||||
|
self.file.write("%s\n%s\n\n" % (\
|
||||||
|
"#ifndef " + self.sentinel,
|
||||||
|
"#define " + self.sentinel))
|
||||||
|
|
||||||
|
def writeSentinelEnd(self, sentinel):
|
||||||
|
""" end header """
|
||||||
|
if sentinel == None:
|
||||||
|
return -1
|
||||||
|
self.sentinel = sentinel
|
||||||
|
self.file.write("\n%s\n" % ("#endif /* " + self.sentinel + " */"))
|
||||||
32
tools/cv_bsp_generator/xmlgrok.py
Executable file
32
tools/cv_bsp_generator/xmlgrok.py
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
"""
|
||||||
|
XML node parser
|
||||||
|
|
||||||
|
Copyright (C) 2022 Intel Corporation <www.intel.com>
|
||||||
|
|
||||||
|
Author: Lee, Kah Jing <kah.jing.lee@intel.com>
|
||||||
|
"""
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
|
def isElementNode(XMLNode):
|
||||||
|
""" check if the node is element node """
|
||||||
|
return XMLNode.nodeType == xml.dom.Node.ELEMENT_NODE
|
||||||
|
|
||||||
|
def firstElementChild(XMLNode):
|
||||||
|
""" Calling firstChild on an Node of type Element often (always?)
|
||||||
|
returns a Node of Text type. How annoying! Return the first Element
|
||||||
|
child
|
||||||
|
"""
|
||||||
|
child = XMLNode.firstChild
|
||||||
|
while child != None and not isElementNode(child):
|
||||||
|
child = nextElementSibling(child)
|
||||||
|
return child
|
||||||
|
|
||||||
|
def nextElementSibling(XMLNode):
|
||||||
|
""" nextElementSibling will return the next sibling of XMLNode that is
|
||||||
|
an Element Node Type
|
||||||
|
"""
|
||||||
|
sib = XMLNode.nextSibling
|
||||||
|
while sib != None and not isElementNode(sib):
|
||||||
|
sib = sib.nextSibling
|
||||||
|
return sib
|
||||||
Reference in New Issue
Block a user