soc/mediatek/adsp: Enable winstream console
Enable a winstream console via the new "STATIC" platform API, and add code to the loader script to read it (largely cribbed with modifications from the same feature in cavstool.py, we have nowhere to share code like this, alas). The older logging feature is still present as an "oldlog" mode to the script. We can leave it for a bit as a failsafe (e.g. for debugging issues with winstream) and remove it later. Signed-off-by: Andy Ross <andyross@google.com>
This commit is contained in:
parent
14418a7f39
commit
2860ab9179
3 changed files with 108 additions and 4 deletions
|
@ -48,6 +48,15 @@ config MTK_ADSP_TIMER
|
|||
config XTENSA_TIMER
|
||||
default n
|
||||
|
||||
config CONSOLE
|
||||
default y
|
||||
config WINSTREAM_CONSOLE
|
||||
default y
|
||||
config WINSTREAM
|
||||
default y
|
||||
config LOG_BACKEND_ADSP
|
||||
default y if LOG
|
||||
|
||||
config XTENSA_CCOUNT_HZ
|
||||
default 720000000 if SOC_MT8195
|
||||
default 400000000 if SOC_MT8186
|
||||
|
|
|
@ -171,7 +171,7 @@ class MT8196:
|
|||
# stream at 0x60700000 -- the top of the linkable region of
|
||||
# existing SOF firmware, before the heap. Nothing uses this
|
||||
# currently. Will be replaced by winstream very soon.
|
||||
def log(dev):
|
||||
def old_log(dev):
|
||||
msg = b''
|
||||
dram = maps["dram1"]
|
||||
for i in dev.logrange():
|
||||
|
@ -218,6 +218,93 @@ def le4(bstr):
|
|||
return struct.unpack("<I", bstr)[0]
|
||||
|
||||
|
||||
# Wrapper class for winstream logging. Instantiate with a single
|
||||
# integer argument representing a local/in-process address for the
|
||||
# shared winstream memory. The memory mapped access is encapsulated
|
||||
# with a Regs object for the fields and a ctypes array for the data
|
||||
# area. The lockless algorithm in read() matches the C version in
|
||||
# upstream Zephyr, don't modify in isolation. Note that on some
|
||||
# platforms word access to the data array (by e.g. copying a slice
|
||||
# into a bytes object or by calling memmove) produces bus errors
|
||||
# (plausibly an alignment requirement on the fabric with the DSP
|
||||
# memory, where arm64 python is happy doing unaligned loads?). Access
|
||||
# to the data bytes is done bytewise for safety.
|
||||
class Winstream:
|
||||
def __init__(self, addr):
|
||||
r = Regs(addr)
|
||||
r.WLEN = 0x00
|
||||
r.START = 0x04
|
||||
r.END = 0x08
|
||||
r.SEQ = 0x0C
|
||||
r.freeze()
|
||||
# Sanity-check, the 32M size limit isn't a rule, but seems reasonable
|
||||
if r.WLEN > 0x2000000 or (r.START >= r.WLEN) or (r.END >= r.WLEN):
|
||||
raise RuntimeError("Invalid winstream")
|
||||
self.regs = r
|
||||
self.data = (ctypes.c_char * r.WLEN).from_address(addr + 16)
|
||||
self.msg = bytearray(r.WLEN)
|
||||
self.seq = 0
|
||||
|
||||
def read(self):
|
||||
ws, msg, data = self.regs, self.msg, self.data
|
||||
last_seq = self.seq
|
||||
wlen = ws.WLEN
|
||||
while True:
|
||||
start, end, seq = ws.START, ws.END, ws.SEQ
|
||||
self.seq = seq
|
||||
if seq == last_seq or start == end:
|
||||
return ""
|
||||
behind = seq - last_seq
|
||||
if behind > ((end - start) % wlen):
|
||||
return ""
|
||||
copy = (end - behind) % wlen
|
||||
suffix = min(behind, wlen - copy)
|
||||
for i in range(suffix):
|
||||
msg[i] = data[copy + i][0]
|
||||
msglen = suffix
|
||||
l2 = behind - suffix
|
||||
if l2 > 0:
|
||||
for i in range(l2):
|
||||
msg[msglen + i] = data[i][0]
|
||||
msglen += l2
|
||||
if start == ws.START and seq == ws.SEQ:
|
||||
return msg[0:msglen].decode("utf-8", "replace")
|
||||
|
||||
|
||||
# Locates a winstream descriptor in the firmware via its 96-bit magic
|
||||
# number and returns the address and size fields it finds there.
|
||||
def find_winstream(maps):
|
||||
magic = b'\x74\x5f\x6a\xd0\x79\xe2\x4f\x00\xcd\xb8\xbd\xf9'
|
||||
for m in maps:
|
||||
if "ram" in m:
|
||||
magoff = maps[m].find(magic)
|
||||
if magoff >= 0:
|
||||
addr = le4(maps[m][magoff + 12 : magoff + 16])
|
||||
return addr
|
||||
raise RuntimeError("Cannot find winstream descriptor in firmware runtime")
|
||||
|
||||
|
||||
def winstream_localaddr(globaddr, mmio, maps):
|
||||
for m in mmio:
|
||||
off = globaddr - mmio[m][0]
|
||||
if 0 <= off < mmio[m][1]:
|
||||
return ctypes.addressof(ctypes.c_int.from_buffer(maps[m])) + off
|
||||
raise RuntimeError("Winstream address not inside DSP memory")
|
||||
|
||||
|
||||
def winstream_log(mmio, maps):
|
||||
physaddr = find_winstream(maps)
|
||||
regsbase = winstream_localaddr(physaddr, mmio, maps)
|
||||
ws = Winstream(regsbase)
|
||||
while True:
|
||||
msg = ws.read()
|
||||
if msg:
|
||||
sys.stdout.write(msg)
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
def main():
|
||||
dsp = detect()
|
||||
assert dsp
|
||||
|
@ -272,14 +359,17 @@ def main():
|
|||
for i in range(len(dram), mmio["dram1"][1]):
|
||||
maps["dram1"][i] = 0
|
||||
dev.start(boot_vector)
|
||||
log(dev)
|
||||
winstream_log(mmio, maps)
|
||||
|
||||
elif sys.argv[1] == "log":
|
||||
log(dev)
|
||||
winstream_log(mmio, maps)
|
||||
|
||||
elif sys.argv[1] == "oldlog":
|
||||
old_log(dev)
|
||||
|
||||
elif sys.argv[1] == "mem":
|
||||
print("Memory Regions:")
|
||||
for m in mmio.keys():
|
||||
for m in mmio:
|
||||
print(f" {m}: {mmio[m][1]} @ 0x{mmio[m][0]:08x}")
|
||||
|
||||
elif sys.argv[1] == "dump":
|
||||
|
|
|
@ -251,6 +251,7 @@ static void enable_mpu(void)
|
|||
* dram clear and also set buf[0] to 0 manually (as it isn't affected
|
||||
* by device reset).
|
||||
*/
|
||||
#ifndef CONFIG_WINSTREAM_CONSOLE
|
||||
int arch_printk_char_out(int c)
|
||||
{
|
||||
char volatile * const buf = (void *)LOG_BASE;
|
||||
|
@ -263,6 +264,10 @@ int arch_printk_char_out(int c)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Define this here as a simple uncached array, no special linkage requirements */
|
||||
__nocache char _winstream_console_buf[CONFIG_WINSTREAM_CONSOLE_STATIC_SIZE];
|
||||
|
||||
void c_boot(void)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue