zephyr/boards/xtensa/intel_s1000_crb/support/messenger.py

233 lines
7.9 KiB
Python

#!/usr/bin/env python3
#
# Copyright (c) 2019 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
# Author: Sathish Kuttan <sathish.k.kuttan@intel.com>
# This file defines a message class that contains functions to create
# commands to the target and to parse responses from the target.
import bitstruct
class Message:
"""
Message class containing the methods to create command messages and
parse response messages.
"""
message_id = {1: 'Control'}
cmd_rsp = {2: 'Load Firmware',
4: 'Mode Select',
0x10: 'Memory Read',
0x11: 'Memory Write',
0x12: 'Memory Block Write',
0x13: 'Execute',
0x14: 'Wait',
0x20: 'Ready'}
tx_data = None
tx_bulk_data = None
tx_index = 0
cmd_word_fmt = 'u1 u1 u1 u5 u16 u8'
cmd_keys = ['cmd', 'rsvd1', 'rsp', 'msg_id', 'rsvd2', 'cmd_rsp']
def __init__(self):
"""
Intialize a byte array of 64 bytes for command messages
Intialize another byte array of 4096 bytes for bulk messages
"""
self.tx_data = bytearray(64)
self.tx_bulk_data = bytearray(4096)
def init_tx_data(self):
"""
Intialize transmit message buffers to zeros
"""
for index in range(len(self.tx_data)):
self.tx_data[index] = 0
self.tx_index = 0
@staticmethod
def endian_swap(dst, dst_offset, src):
"""
Performs a byte swap of a 32-bit word to change it's endianness
"""
for index in range(0, len(src), 4):
dst[dst_offset + index + 0] = src[index + 3]
dst[dst_offset + index + 1] = src[index + 2]
dst[dst_offset + index + 2] = src[index + 1]
dst[dst_offset + index + 3] = src[index + 0]
def print_cmd_message(self):
"""
Prints the contents of the command message buffer
"""
for index in range(0, self.tx_index, 4):
offset = index * 8
word = bitstruct.unpack_from('u32', self.tx_data, offset)
print('Index: %2d Content: 0x%08x' %(index, word[0]))
def print_response(self, msg, verbose=False):
"""
Parses and prints the contents of the response message
"""
unpacked = bitstruct.unpack_from_dict(self.cmd_word_fmt,
self.cmd_keys, msg)
msg_id = unpacked['msg_id']
rsp = unpacked['cmd_rsp']
if msg_id == 0 and rsp == 0:
print('RSP <<< NULL.')
else:
print('RSP <<< %s.' % self.cmd_rsp[rsp])
if verbose:
count = bitstruct.unpack_from('u32', msg, 4 * 8)[0]
count &= 0x1ff
for index in range(0, 8 + (count * 4), 4):
offset = index * 8
word = bitstruct.unpack_from('u32', msg, offset)
print('Index: %2d Content: 0x%08x' %(index, word[0]))
def get_cmd_code(self, cmd):
"""
Looks up the command and returns the numeric code
"""
index = list(self.cmd_rsp.values()).index(cmd)
return list(self.cmd_rsp.keys())[index]
def print_cmd_code(self, cmd):
"""
Prints the numeric code for the given command
"""
key = self.get_cmd_code(cmd)
print('CMD >>> %s. Command Code: 0x%02x' % (cmd, key))
def create_null_cmd(self):
"""
Creates a NULL command
"""
print('CMD >>> NULL.')
for index in range(len(self.tx_data)):
self.tx_data[index] = 0
self.tx_index = len(self.tx_data)
return self.tx_data
def create_memwrite_cmd(self, tuple):
"""
Creates a memory write command with memory address and value pairs
"""
cmd = 'Memory Write'
print('CMD >>> %s.' % cmd)
code = self.get_cmd_code(cmd)
self.init_tx_data()
index = list(self.message_id.values()).index('Control')
msg_id = list(self.message_id.keys())[index]
bitstruct.pack_into_dict(self.cmd_word_fmt, self.cmd_keys,
self.tx_data, 0, {'cmd': 1, 'rsvd1': 0, 'rsp': 0,
'msg_id': msg_id, 'rsvd2': 0, 'cmd_rsp': code})
self.tx_index += 4
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8,
len(tuple))
self.tx_index += 4
for elm in tuple:
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8, elm)
self.tx_index += 4
return self.tx_data
def create_memread_cmd(self, tuple):
"""
Creates a memory read command with memory addresses
"""
cmd = 'Memory Read'
print('CMD >>> %s.' % cmd)
code = self.get_cmd_code(cmd)
self.init_tx_data()
index = list(self.message_id.values()).index('Control')
msg_id = list(self.message_id.keys())[index]
bitstruct.pack_into_dict(self.cmd_word_fmt, self.cmd_keys,
self.tx_data, 0, {'cmd': 1, 'rsvd1': 0, 'rsp': 0,
'msg_id': msg_id, 'rsvd2': 0, 'cmd_rsp': code})
self.tx_index += 4
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8,
len(tuple))
self.tx_index += 4
for elm in tuple:
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8, elm)
self.tx_index += 4
return self.tx_data
def create_loadfw_cmd(self, size, sha):
"""
Creates a command to load firmware with associated parameters
"""
cmd = 'Load Firmware'
print('CMD >>> %s.' % cmd)
code = self.get_cmd_code(cmd)
FW_NO_EXEC_FLAG = (1 << 26)
SEL_HP_CLK = (1 << 21)
LD_FW_HEADER_LEN = 3
count_flags = FW_NO_EXEC_FLAG | SEL_HP_CLK
count_flags |= (LD_FW_HEADER_LEN + int(len(sha) / 4))
self.init_tx_data()
index = list(self.message_id.values()).index('Control')
msg_id = list(self.message_id.keys())[index]
bitstruct.pack_into_dict(self.cmd_word_fmt, self.cmd_keys,
self.tx_data, 0, {'cmd': 1, 'rsvd1': 0, 'rsp': 0,
'msg_id': msg_id, 'rsvd2': 0, 'cmd_rsp': code})
self.tx_index += 4
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8, count_flags)
self.tx_index += 4
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8, 0xbe000000)
self.tx_index += 4
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8, 0)
self.tx_index += 4
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8, size)
self.tx_index += 4
self.endian_swap(self.tx_data, self.tx_index, sha)
self.tx_index += len(sha)
return self.tx_data
def create_execfw_cmd(self):
"""
Creates a command to excute firmware
"""
cmd = 'Execute'
print('CMD >>> %s.' % cmd)
code = self.get_cmd_code(cmd)
EXE_FW_HEADER_LEN = 1
count = EXE_FW_HEADER_LEN
self.init_tx_data()
index = list(self.message_id.values()).index('Control')
msg_id = list(self.message_id.keys())[index]
bitstruct.pack_into_dict(self.cmd_word_fmt, self.cmd_keys,
self.tx_data, 0, {'cmd': 1, 'rsvd1': 0, 'rsp': 0,
'msg_id': msg_id, 'rsvd2': 0, 'cmd_rsp': code})
self.tx_index += 4
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8, count)
self.tx_index += 4
bitstruct.pack_into('u32', self.tx_data, self.tx_index * 8, 0xbe000000)
self.tx_index += 4
return self.tx_data
def create_bulk_message(self, data):
"""
Copies the input byte stream to the bulk message buffer
"""
self.endian_swap(self.tx_bulk_data, 0, data)
return self.tx_bulk_data[:len(data)]
def get_bulk_message_size(self):
"""
Returns the size of the bulk message buffer
"""
return len(self.tx_bulk_data)