blob: d9b73dc68d59b837309b8d149fc42ce5c794d3ba [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright (c) 2019 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
# This script will add specific headers and FW load message to tell
# intel_s1000 ROM bootloader to load the firmware
# Usage python3 ${ZEPHYR_BASE}/scripts/create_board_img.py
# -i in_file.bin -o out_file.bin -l zephyr_prebuilt.elf
# [-m|--no_sram] [-c|--no_l1cache] [-t|--no_tlb]
# [-x|--no_exec] [-s|--no_sha] [-k|--clk_sel]
import argparse
import os
import sys
import struct
from elftools.elf.elffile import ELFFile
help_text="""
The flash memory needs to have specific headers and fw load message to tell
the ROM bootloader to load firmware.
To run script use command:
create_board_img.py -i in_file.bin -o out_file.bin -l zephyr_prebuilt.elf
[-m|--no_sram] [-c|--no_l1cache] [-t|--no_tlb]
[-x|--no_exec] [-s|--no_sha] [-k|--clk_sel]
"""
FLASH_PART_TABLE_OFFSET = (0x1000)
FLASH_SECTOR_SIZE = (4 * 1024)
FLASH_MAGIC_WORD = (0x30504353)
SRAM_SIZE = (1024*1024*4)
MAX_FLASH_FILE_SIZE = (1024*1024*2)
SIZEOF_IPC64 = (64)
ROM_CONTROL_MEMWRITE = (0x11)
ROM_CONTROL_LOADFW = (0x2)
ROM_CONTROL_EXEC = (0x13)
FW_LOAD_NO_L1_CACHE = (1 << 29)
FW_LOAD_NO_SRAM_FLAG = (1 << 28)
FW_LOAD_NO_TLB_FLAG = (1 << 27)
FW_LOAD_NO_EXEC_FLAG = (1 << 26)
FW_LOAD_NO_SHA_FLAG = (1 << 25)
FW_LOAD_CLK_SEL = (1 << 21)
# File write buffer
flash_content = []
write_buf = []
def debug(text):
sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n")
def error(text):
sys.exit(os.path.basename(sys.argv[0]) + ": " + text)
def set_magic_number(value):
flash_content.append(value)
def set_partition_table_pointer(value):
flash_content.append(value)
def ipc_load_fw(fw_size, fw_offset):
dword_count = 3
load_flags = 0
clock_sel = 0
dword_count = 0x3ff & dword_count
debug("Creating flash image with following options:")
if args.no_sram:
load_flags |= FW_LOAD_NO_SRAM_FLAG
debug("-m no_sram")
if args.no_l1cache:
load_flags |= FW_LOAD_NO_L1_CACHE
debug("-c no_l1cache")
if args.no_tlb:
load_flags |= FW_LOAD_NO_TLB_FLAG
debug("-t no_tlb")
if args.no_exec:
load_flags |= FW_LOAD_NO_EXEC_FLAG
debug("-x no_exec")
if args.no_sha:
load_flags |= FW_LOAD_NO_SHA_FLAG
debug("-s no_sha")
if args.clk_sel:
clock_sel = FW_LOAD_CLK_SEL
debug("-k clk_sel")
with open(args.kernel, "rb") as fp_kernel:
kernel = ELFFile(fp_kernel)
load_address = kernel.header['e_entry']
debug("load address = 0x%X" % load_address)
msg_header = 0x81000000 | ROM_CONTROL_LOADFW
ext_header = 0x80000000 | dword_count | load_flags | clock_sel
flash_content.append(msg_header)
flash_content.append(ext_header)
flash_content.append(load_address)
flash_content.append(fw_offset)
flash_content.append(fw_size)
def ipc_dbg_exec(address):
dword_count = 1
dword_count = 0x3ff & dword_count
msg_header = 0x81000000 | ROM_CONTROL_EXEC
ext_header = 0x0 | dword_count
flash_content.append(msg_header)
flash_content.append(ext_header)
flash_content.append(address)
def ipc_dbg_memwrite(address, value):
dword_count = 2
dword_count = 0x3ff & dword_count
msg_header = 0x81000000 | ROM_CONTROL_MEMWRITE
ext_header = 0x0 | dword_count
flash_content.append(msg_header)
flash_content.append(ext_header)
flash_content.append(address)
flash_content.append(value)
def parse_args():
global args
parser = argparse.ArgumentParser(
description=help_text,
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("-i", "--in_file", required=True,
help="Input FW Bin File")
parser.add_argument("-o", "--out_file", required=True,
help="Output Flash Bin File")
parser.add_argument("-l", "--kernel", required=True,
help="Zephyr kernel image")
parser.add_argument("-m", "--no_sram", action="store_true",
help="No SRAM")
parser.add_argument("-c", "--no_l1cache", action="store_true",
help="No L1 Cache")
parser.add_argument("-t", "--no_tlb", action="store_true",
help="No TLB")
parser.add_argument("-x", "--no_exec", action="store_true",
help="No Exec")
parser.add_argument("-s", "--no_sha", action="store_true",
help="No SHA")
parser.add_argument("-k", "--clk_sel", action="store_true",
help="Clock Select")
args = parser.parse_args()
def main():
global flash_content, write_buf
parse_args()
in_file_size = os.path.getsize(args.in_file)
if in_file_size == 0:
error("%s file has no content\n" % args.in_file)
out_file_size = FLASH_PART_TABLE_OFFSET + in_file_size
# round up the flash size to sector boundary
zeropad_size = FLASH_SECTOR_SIZE - (out_file_size % FLASH_SECTOR_SIZE)
out_file_size += zeropad_size
if out_file_size > MAX_FLASH_FILE_SIZE:
error("%s exceeds %d bytes\n" % (args.out_file, MAX_FLASH_FILE_SIZE))
# pre-boot initialization commands
set_magic_number(FLASH_MAGIC_WORD)
set_partition_table_pointer(FLASH_PART_TABLE_OFFSET)
ipc_dbg_memwrite(0x71d14, 0x0)
ipc_dbg_memwrite(0x71d24, 0x0)
ipc_dbg_memwrite(0x304628, 0xd)
ipc_dbg_memwrite(0x71fd0, 0x3)
# load the image at address FLASH_PART_TABLE_OFFSET in flash to SRAM
# at load_address (determined by the entrypoint in the supplied elf)
ipc_load_fw(SRAM_SIZE, FLASH_PART_TABLE_OFFSET)
# pad zeros until FLASH_PART_TABLE_OFFSET
num_zero_pad = FLASH_PART_TABLE_OFFSET // 4 - len(flash_content)
flash_content += num_zero_pad * [0]
# read contents of firmware input file and change the endianness
with open(args.in_file, "rb") as in_fp:
read_buf = in_fp.read()
in_fp.close()
for itr in range(int(in_file_size/4)):
write_buf.append(read_buf[itr*4 + 3])
write_buf.append(read_buf[itr*4 + 2])
write_buf.append(read_buf[itr*4 + 1])
write_buf.append(read_buf[itr*4 + 0])
# pad zeros until the sector boundary
write_buf += zeropad_size*[0]
# Generate the file which should be downloaded to Flash
with open(args.out_file, "wb") as out_fp:
# write as a uint (4 bytes) with byte order swapped (big-endian)
out_fp.write(struct.pack(">{}I".format(len(flash_content)),
*flash_content))
# write as a byte
out_fp.write(struct.pack("{}B".format(len(write_buf)),
*write_buf))
out_fp.close()
debug("Input %s = %ld bytes" % (os.path.basename(args.in_file), in_file_size))
debug("Output %s = %ld bytes" % (os.path.basename(args.out_file), out_file_size))
if __name__ == "__main__":
main()