from ska_low_sps_tpm_api.base.definitions import *
from ska_low_sps_tpm_api.base.utils import *
from ska_low_sps_tpm_api.plugins.firmwareblock import FirmwareBlock
__author__ = "Gabriele Sorrenti"
MAX_RETRY = 1000
[docs]
class TpmEEP(FirmwareBlock):
"""TpmEEP plugin"""
[docs]
@compatibleboards(BoardMake.TpmBoard)
@friendlyname("tpm_eep")
@maxinstances(1)
def __init__(self, board, logger=None, **kwargs):
"""
TpmEEP initialiser.
:param board: Pointer to board instance
"""
super(TpmEEP, self).__init__(board, logger=logger)
self.phy_addr = 0xA0
# self.ba = 0x40000000 #self.board["board.i2c"] # I2C IF Base Add
self.i2c_shadow = 0x90000270
self.i2c_req_reg = 0x50
self.i2c_ack_reg = 0x54
self.eep_sec = {
"ip_address": {
"offset": 0x00,
"size": 4,
"name": "ip_address",
"type": "ip",
"protected": False,
},
"netmask": {
"offset": 0x04,
"size": 4,
"name": "netmask",
"type": "ip",
"protected": False,
},
"gateway": {
"offset": 0x08,
"size": 4,
"name": "gateway",
"type": "ip",
"protected": False,
},
"password": {
"offset": 0x0C,
"size": 3,
"name": "password",
"type": "bytearray",
"protected": False,
},
"eep_rev": {
"offset": 0x0F,
"size": 1,
"name": "eep_rev",
"type": "uint",
"protected": True,
},
"EXT_LABEL_SN": {
"offset": 0x30,
"size": 16,
"name": "EXT_LABEL_SN",
"type": "string",
"protected": True,
},
"SN": {
"offset": 0x40,
"size": 16,
"name": "SN",
"type": "string",
"protected": True,
},
"PN": {
"offset": 0x50,
"size": 16,
"name": "PN",
"type": "string",
"protected": True,
},
"BOARD_MODE": {
"offset": 0x60,
"size": 1,
"name": "BOARD_MODE",
"type": "uint",
"protected": True,
}, # 0 ada,0xff no-ada
"HARDWARE_REV": {
"offset": 0x61,
"size": 3,
"name": "HARDWARE_REV",
"type": "bytearray",
"protected": True,
}, # v00.00.00
"PCB_REV": {
"offset": 0x64,
"size": 1,
"name": "PCB_REV",
"type": "string",
"protected": True,
},
"DDR_SIZE_GB": {
"offset": 0x65,
"size": 1,
"name": "DDR_SIZE_GB",
"type": "uint",
"protected": True,
},
"EXT_LABEL_2": {
"offset": 0x6A,
"size": 6,
"name": "EXT_LABEL_2",
"type": "string",
"protected": True,
},
"pre_adu_0_rev": {
"offset": 0x70,
"size": 1,
"name": "pre_adu_0_rev",
"type": "uint",
"protected": False,
},
"pre_adu_1_rev": {
"offset": 0x71,
"size": 1,
"name": "pre_adu_1_rev",
"type": "uint",
"protected": False,
},
"EXT_LABEL_PN": {
"offset": 0x72,
"size": 14,
"name": "EXT_LABEL_PN",
"type": "string",
"protected": True,
},
"MAC": {
"offset": 0xFA,
"size": 6,
"name": "MAC",
"type": "bytearray",
"protected": True,
}, # READ-ONLY
}
#######################################################################################
[docs]
def poll_reg(self, reg, exit_condition, exception_val):
retry = 0
while True:
if (self.board[reg]) == exit_condition:
break
else:
time.sleep(0.001)
retry = retry + 1
self.board._i2c_lock.refresh()
if retry >= MAX_RETRY:
self.logger.error("EEP Polling Reg timeout: ", exception_val)
raise LibraryError(exception_val)
[docs]
def rd8(
self, offset, use_password=False, release_lock=True, size=1, mux=0, add=None
):
"""Read 8-bit value from EEP ROM"""
if self.board.i2c_old_mode:
self.set_passwd()
if add is None:
add = self.phy_addr >> 1
else:
add = add >> 1
nof_rd_byte = size
if offset is not None:
nof_wr_byte = 1
else:
nof_wr_byte = 0
cmd = (mux << 16) + (nof_rd_byte << 12) + (nof_wr_byte << 8) + add
if offset is not None:
self.board["board.i2c.transmit"] = offset & 0xFF
self.board["board.i2c.command"] = cmd
while self.board["board.i2c.status"] != 0:
pass
self.remove_passwd()
read_data = self.board["board.i2c.receive"]
if size > 1:
read_data = sum(
((read_data >> (8 * i)) & 0xFF) << (8 * (size - 1 - i))
for i in range(size)
)
return read_data
else:
self.board._i2c_lock.lock()
if self.board[self.i2c_shadow + self.i2c_req_reg] == 1:
self.logger.warning("Detected Incomplete Previous I2C operation")
self.board[self.i2c_shadow + self.i2c_req_reg] = 0
self.poll_reg(self.i2c_shadow + self.i2c_ack_reg, 0, "I2C/EEP not ready!")
self.set_passwd()
if add is None:
add = self.phy_addr >> 1
else:
add = add >> 1
nof_rd_byte = size
if offset is not None:
nof_wr_byte = 1
else:
nof_wr_byte = 0
cmd = (mux << 16) + (nof_rd_byte << 12) + (nof_wr_byte << 8) + add
# print(f"rd8 {hex(offset)} {hex(cmd)}")
if offset is not None:
self.board[self.i2c_shadow + 0x4] = offset & 0xFF
self.board[self.i2c_shadow + 0x0] = cmd
# send request
self.board[self.i2c_shadow + self.i2c_req_reg] = 1
# wait req acknowledge
self.logger.debug("i2c read wait req acknowledge")
self.poll_reg(
self.i2c_shadow + self.i2c_ack_reg, 1, "I2C/EEP request not accepted!"
)
# check passwd
self.logger.debug("i2c read check passwd")
self.check_passwd()
# check i2c op status: 0 ok, 1 busy, 2 NACK
self.logger.debug("i2c read check status")
self.poll_reg(self.i2c_shadow + 0xC, 0, "I2C/EEP busy or not acknowledge!")
read_data = self.board[self.i2c_shadow + 0x8] & ((1 << (size * 8)) - 1)
# Endianness swap
if size > 1:
read_data = sum(
((read_data >> (8 * i)) & 0xFF) << (8 * (size - 1 - i))
for i in range(size)
)
# self.remove_passwd()
# self.board[self.i2c_shadow+self.i2c_ack_reg] = 0
self.board[self.i2c_shadow + self.i2c_req_reg] = 0
self.logger.debug("i2c read check end operation")
self.poll_reg(
self.i2c_shadow + self.i2c_ack_reg,
0,
"I2C/EEP operation complete detected!",
)
if release_lock:
self.board._i2c_lock.unlock()
return read_data
[docs]
def rd16(self, offset, use_password=False, release_lock=True, mux=0, add=None):
"""Read 16-bit value from EEP ROM"""
if add is None:
add = self.phy_addr
return self.rd8(
offset,
size=2,
use_password=use_password,
release_lock=release_lock,
mux=mux,
add=add,
)
[docs]
def rd32(self, offset, use_password=False, release_lock=True, mux=0, add=None):
"""Read 32-bit value from EEP ROM"""
if add is None:
add = self.phy_addr
return self.rd8(
offset,
size=4,
use_password=use_password,
release_lock=release_lock,
mux=mux,
add=add,
)
[docs]
def wr8(self, offset, data):
"""Write 8-bit value to EEP ROM"""
if self.board.i2c_old_mode:
self.set_passwd()
add = self.phy_addr >> 1
nof_rd_byte = 0
nof_wr_byte = 2
cmd = (nof_rd_byte << 12) + (nof_wr_byte << 8) + add
while True:
data = data & 0xFF
offset = offset & 0xFF
self.board["board.i2c.transmit"] = (data << 8) + offset
self.board["board.i2c.command"] = cmd
while True:
rd = self.board["board.i2c.status"]
if rd == 2:
time.sleep(0.1)
break
elif rd == 0:
time.sleep(0.005)
self.remove_passwd()
return
else:
time.sleep(0.1)
else:
self.board._i2c_lock.lock()
if self.board[self.i2c_shadow + self.i2c_req_reg] == 1:
self.logger.warning("Detected Incomplete Previous I2C operation")
self.board[self.i2c_shadow + self.i2c_req_reg] = 0
self.poll_reg(self.i2c_shadow + self.i2c_ack_reg, 0, "I2C/EEP not ready!")
self.set_passwd()
add = self.phy_addr >> 1
nof_rd_byte = 0
nof_wr_byte = 2
cmd = (nof_rd_byte << 12) + (nof_wr_byte << 8) + add
self.board[self.i2c_shadow + 0x4] = ((data & 0xFF) << 8) + (offset & 0xFF)
self.board[self.i2c_shadow + 0x0] = cmd
# send request
self.board[self.i2c_shadow + self.i2c_req_reg] = 1
# wait req acknowledge
self.logger.debug("wait req acknowledge")
self.poll_reg(
self.i2c_shadow + self.i2c_ack_reg, 1, "I2C/EEP request not accepted!"
)
# check passwd
self.logger.debug("check passwd")
self.check_passwd()
# check i2c op status: 0 ok, 1 busy, 2 NACK
self.logger.debug("check status")
self.poll_reg(self.i2c_shadow + 0xC, 0, "I2C/EEP busy or not acknowledge!")
# read_data = self.board[self.i2c_shadow + 0x8]
# self.remove_passwd()
self.board[self.i2c_shadow + self.i2c_req_reg] = 0
self.logger.debug("check end operation")
self.poll_reg(
self.i2c_shadow + self.i2c_ack_reg,
0,
"I2C/EEP operation complete!",
)
self.board._i2c_lock.unlock()
time.sleep(0.020)
[docs]
def wr32(self, offset, data):
for n in range(4):
self.wr8(offset + n, (data >> 8 * (3 - n)) & 0xFF)
return
[docs]
def wr_string(self, partition, string):
return self._wr_string(partition["offset"], string, partition["size"])
def _wr_string(self, offset, string, max_len=16):
addr = offset
for i in range(len(string)):
self.wr8(addr, ord(string[i]))
addr += 1
if addr >= offset + max_len:
break
if addr < offset + max_len:
self.wr8(addr, ord("\n"))
[docs]
def rd_string(self, partition):
return self._rd_string(partition["offset"], partition["size"])
def _rd_string(self, offset, max_len=16, mux=0, add=None):
if add is None:
add = self.phy_addr
string = ""
for i in range(0, max_len, 4):
length = min(4, max_len - i)
data = self.rd8(offset + i, size=length, mux=mux, add=add)
for j in range(length):
byte = (data >> (8 * (length - 1 - j))) & 0xFF
if byte == ord("\n") or byte == 0xFF:
return string
string += chr(byte)
return string
def _rd_bytearray(self, offset, max_len=16, mux=0, add=None):
if add is None:
add = self.phy_addr
arr = bytearray()
for i in range(0, max_len, 4):
length = min(4, max_len - i)
data = self.rd8(offset + i, size=length, mux=mux, add=add)
for j in range(length):
byte = (data >> (8 * (length - 1 - j))) & 0xFF
arr.append(byte)
return arr
[docs]
def set_passwd(self):
if self.board.i2c_old_mode:
rd = self.board["board.i2c.mac_hi"]
self.board["board.i2c.password"] = rd
rd = self.board["board.i2c.mac_lo"]
self.board["board.i2c.password_lo"] = rd
rd = self.board["board.i2c.password"]
if rd & 0x10000 == 0:
raise LibraryError("I2C/EEP password not accepted!")
else:
rd = self.board["board.i2c.mac_hi"]
self.board[self.i2c_shadow + 0x3C] = rd
rd = self.board["board.i2c.mac_lo"]
self.board[self.i2c_shadow + 0x38] = rd
[docs]
def check_passwd(self):
rd = self.board[self.i2c_shadow + 0x3C]
if (rd & 0x10000) != 0x10000:
self.logger.error("I2C/EEP password not accepted!")
raise LibraryError("I2C/EEP password not accepted!")
[docs]
def remove_passwd(self):
if self.board.i2c_old_mode:
self.board["board.i2c.password"] = 0
self.board["board.i2c.password_lo"] = 0
else:
self.board[self.i2c_shadow + 0x3C] = 0
self.board[self.i2c_shadow + 0x38] = 0
[docs]
def get_field(self, key):
if self.eep_sec[key]["type"] == "ip":
return long2ip(self.rd32(self.eep_sec[key]["offset"]))
elif self.eep_sec[key]["type"] == "bytearray":
arr = bytearray()
for offset in range(self.eep_sec[key]["size"]):
arr.append(self.rd8(self.eep_sec[key]["offset"] + offset))
return arr
elif self.eep_sec[key]["type"] == "string":
return self.rd_string(self.eep_sec[key])
elif self.eep_sec[key]["type"] == "uint":
val = 0
for offset in range(self.eep_sec[key]["size"]):
val = val * 256 + self.rd8(self.eep_sec[key]["offset"] + offset)
return val
[docs]
def set_field(self, key, value, override_protected=False):
if self.eep_sec[key]["protected"] is False or override_protected:
if self.eep_sec[key]["type"] == "ip":
self.wr32(self.eep_sec[key]["offset"], ip2long(value))
elif self.eep_sec[key]["type"] == "bytearray":
for offset in range(self.eep_sec[key]["size"]):
self.wr8(self.eep_sec[key]["offset"] + offset,
((value & (0xff << (8*(self.eep_sec[key]["size"]-1-offset))))
>> (8*(self.eep_sec[key]["size"]-1-offset))) & 0xff) # fmt: skip
elif self.eep_sec[key]["type"] == "string":
self.wr_string(self.eep_sec[key], value)
elif self.eep_sec[key]["type"] == "uint":
val = value
for offset in range(self.eep_sec[key]["size"]):
self.wr8(self.eep_sec[key]["offset"] + offset, val & 0xFF)
val = val >> 8
else:
raise LibraryError("Writing attempt on protected sector %s" % key)