1#!/usr/bin/env python3 2 3# SPDX-License-Identifier: Apache-2.0 4import subprocess 5import tempfile 6import argparse 7import os 8import string 9import sys 10 11quartus_cpf_template = """<?xml version="1.0" encoding="US-ASCII" standalone="yes"?> 12<cof> 13 <output_filename>${OUTPUT_FILENAME}</output_filename> 14 <n_pages>1</n_pages> 15 <width>1</width> 16 <mode>14</mode> 17 <sof_data> 18 <user_name>Page_0</user_name> 19 <page_flags>1</page_flags> 20 <bit0> 21 <sof_filename>${SOF_FILENAME}<compress_bitstream>1</compress_bitstream></sof_filename> 22 </bit0> 23 </sof_data> 24 <version>10</version> 25 <create_cvp_file>0</create_cvp_file> 26 <create_hps_iocsr>0</create_hps_iocsr> 27 <auto_create_rpd>0</auto_create_rpd> 28 <rpd_little_endian>1</rpd_little_endian> 29 <options> 30 <map_file>1</map_file> 31 </options> 32 <MAX10_device_options> 33 <por>0</por> 34 <io_pullup>1</io_pullup> 35 <config_from_cfm0_only>0</config_from_cfm0_only> 36 <isp_source>0</isp_source> 37 <verify_protect>0</verify_protect> 38 <epof>0</epof> 39 <ufm_source>2</ufm_source> 40 <ufm_filepath>${KERNEL_FILENAME}</ufm_filepath> 41 </MAX10_device_options> 42 <advanced_options> 43 <ignore_epcs_id_check>2</ignore_epcs_id_check> 44 <ignore_condone_check>2</ignore_condone_check> 45 <plc_adjustment>0</plc_adjustment> 46 <post_chain_bitstream_pad_bytes>-1</post_chain_bitstream_pad_bytes> 47 <post_device_bitstream_pad_bytes>-1</post_device_bitstream_pad_bytes> 48 <bitslice_pre_padding>1</bitslice_pre_padding> 49 </advanced_options> 50</cof> 51""" 52 53# XXX Do we care about FileRevision, DefaultMfr, PartName? Do they need 54# to be parameters? So far seems to work across 2 different boards, leave 55# this alone for now. 56quartus_pgm_template = """/* Quartus Prime Version 16.0.0 Build 211 04/27/2016 SJ Lite Edition */ 57JedecChain; 58 FileRevision(JESD32A); 59 DefaultMfr(6E); 60 61 P ActionCode(Cfg) 62 Device PartName(10M50DAF484ES) Path("${POF_DIR}/") File("${POF_FILE}") MfrSpec(OpMask(1)); 63 64ChainEnd; 65 66AlteraBegin; 67 ChainType(JTAG); 68AlteraEnd;""" 69 70 71def create_pof(input_sof, kernel_hex): 72 """given an input CPU .sof file and a kernel binary, return a file-like 73 object containing .pof data suitable for flashing onto the device""" 74 75 t = string.Template(quartus_cpf_template) 76 output_pof = tempfile.NamedTemporaryFile(suffix=".pof") 77 78 input_sof = os.path.abspath(input_sof) 79 kernel_hex = os.path.abspath(kernel_hex) 80 81 # These tools are very stupid and freak out if the desired filename 82 # extensions are used. The kernel image must have extension .hex 83 84 with tempfile.NamedTemporaryFile(suffix=".cof") as temp_xml: 85 86 xml = t.substitute(SOF_FILENAME=input_sof, 87 OUTPUT_FILENAME=output_pof.name, 88 KERNEL_FILENAME=kernel_hex) 89 90 temp_xml.write(bytes(xml, 'UTF-8')) 91 temp_xml.flush() 92 93 cmd = ["quartus_cpf", "-c", temp_xml.name] 94 try: 95 subprocess.check_output(cmd) 96 except subprocess.CalledProcessError as cpe: 97 sys.exit(cpe.output.decode("utf-8") + 98 "\nFailed to create POF file") 99 100 return output_pof 101 102 103def flash_kernel(device_id, input_sof, kernel_hex): 104 pof_file = create_pof(input_sof, kernel_hex) 105 106 with tempfile.NamedTemporaryFile(suffix=".cdf") as temp_cdf: 107 dname, fname = os.path.split(pof_file.name) 108 t = string.Template(quartus_pgm_template) 109 cdf = t.substitute(POF_DIR=dname, POF_FILE=fname) 110 temp_cdf.write(bytes(cdf, 'UTF-8')) 111 temp_cdf.flush() 112 cmd = ["quartus_pgm", "-c", device_id, temp_cdf.name] 113 try: 114 subprocess.check_output(cmd) 115 except subprocess.CalledProcessError as cpe: 116 sys.exit(cpe.output.decode("utf-8") + 117 "\nFailed to flash image") 118 pof_file.close() 119 120def main(): 121 parser = argparse.ArgumentParser(description="Flash zephyr onto Altera boards", allow_abbrev=False) 122 parser.add_argument("-s", "--sof", 123 help=".sof file with Nios II CPU configuration") 124 parser.add_argument("-k", "--kernel", 125 help="Zephyr kernel image to place into UFM in Intel HEX format") 126 parser.add_argument("-d", "--device", 127 help="Remote device identifier / cable name. Default is " 128 "USB-BlasterII. Run jtagconfig -n if unsure.", 129 default="USB-BlasterII") 130 131 args = parser.parse_args() 132 133 flash_kernel(args.device, args.sof, args.kernel) 134 135 136if __name__ == "__main__": 137 main() 138