boards/intel_adsp_cavs15: Remove ancient tooling
There were several generations of loader/logger tooling in this directory, several of which no longer work. They have all been replaced by just one pythong script in the soc directory. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
parent
e71b1a1148
commit
cd5302fa00
21 changed files with 0 additions and 2565 deletions
|
@ -1,22 +0,0 @@
|
|||
For various legacy reasons this directory has two similar log tools:
|
||||
logtool.py and adsplog.py
|
||||
|
||||
Both may be used in automation so merging them would require some
|
||||
coordination.
|
||||
|
||||
They both read from the same data from the exact same shared memory
|
||||
yet they have significant differences:
|
||||
|
||||
- logtool.py reads /sys/kernel/debug/sof/etrace which requires the
|
||||
kernel driver to be loaded.
|
||||
- adsplog.py finds the memory address by scanning
|
||||
/sys/bus/pci/devices/; this does not require a driver.
|
||||
|
||||
- logtool.py supports reading from a special QEMU location.
|
||||
|
||||
- logtool.py performs a raw dump of the memory and exits immediately.
|
||||
- adsplog.py parses the data, understands the ring buffer and reads
|
||||
continuously. Its output is much more human-readable.
|
||||
|
||||
- adsplog.py has technical details explained in a comment at the top.
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
# Copyright (c) 2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import mmap
|
||||
import struct
|
||||
|
||||
# Log reader for the trace output buffer on a ADSP device.
|
||||
#
|
||||
# When run with no arguments, it will detect the device, dump the
|
||||
# contents of the trace buffer and continue to poll for more output.
|
||||
# The "--no-history" argument can be passed to suppress emission of the
|
||||
# history, and emit only new output. This can be useful for test
|
||||
# integration where the user does not want to see any previous runs in
|
||||
# the log output.
|
||||
#
|
||||
# The trace buffer is inside a shared memory region exposed by the
|
||||
# audio PCI device as a BAR at index 4. The hardware provides 4 128k
|
||||
# "windows" starting at 512kb in the BAR which the DSP firmware can
|
||||
# map to 4k-aligned locations within its own address space. By
|
||||
# protocol convention log output is an 8k region at window index 3.
|
||||
|
||||
MAP_SIZE = 8192
|
||||
WIN_OFFSET = 0x80000
|
||||
WIN_IDX = 3
|
||||
WIN_SIZE = 0x20000
|
||||
LOG_OFFSET = WIN_OFFSET + WIN_IDX * WIN_SIZE
|
||||
|
||||
mem = None
|
||||
sys_devices = "/sys/bus/pci/devices"
|
||||
|
||||
for dev_addr in os.listdir(sys_devices):
|
||||
class_file = sys_devices + "/" + dev_addr + "/class"
|
||||
pciclass = open(class_file).read()
|
||||
|
||||
vendor_file = sys_devices + "/" + dev_addr + "/vendor"
|
||||
pcivendor = open(vendor_file).read()
|
||||
|
||||
if not "0x8086" in pcivendor:
|
||||
continue
|
||||
|
||||
# Intel Multimedia audio controller
|
||||
# 0x040100 -> DSP is present
|
||||
# 0x040380 -> DSP is present but optional
|
||||
if "0x040100" in pciclass or "0x040380" in pciclass:
|
||||
barfile = sys_devices + "/" + dev_addr + "/resource4"
|
||||
|
||||
fd = open(barfile)
|
||||
try:
|
||||
mem = mmap.mmap(fd.fileno(), MAP_SIZE, offset=LOG_OFFSET,
|
||||
prot=mmap.PROT_READ)
|
||||
except OSError as ose:
|
||||
sys.stderr.write("""\
|
||||
mmap failed! If CONFIG IO_STRICT_DEVMEM is set then you must unload the kernel driver.
|
||||
""")
|
||||
raise ose
|
||||
break
|
||||
|
||||
if mem is None:
|
||||
sys.stderr.write("ERROR: No ADSP device found.\n")
|
||||
sys.exit(1)
|
||||
|
||||
# This SHOULD be just "mem[start:start+length]", but slicing an mmap
|
||||
# array seems to be unreliable on one of my machines (python 3.6.9 on
|
||||
# Ubuntu 18.04). Read out bytes individually.
|
||||
def read_mem(start, length):
|
||||
return b''.join(mem[x].to_bytes(1, 'little') for x in range(start, start + length))
|
||||
|
||||
def read_hdr():
|
||||
return struct.unpack("<IIII", read_mem(0, 16))
|
||||
|
||||
# Python implementation of the same algorithm in sys_winstream_read(),
|
||||
# see there for details.
|
||||
def winstream_read(last_seq):
|
||||
while True:
|
||||
(wlen, start, end, seq) = read_hdr()
|
||||
if seq == last_seq or start == end:
|
||||
return (seq, "")
|
||||
behind = seq - last_seq
|
||||
if behind > ((end - start) % wlen):
|
||||
return (seq, "")
|
||||
copy = (end - behind) % wlen
|
||||
suffix = min(behind, wlen - copy)
|
||||
result = read_mem(16 + copy, suffix)
|
||||
if suffix < behind:
|
||||
result += read_mem(16, behind - suffix)
|
||||
(wlen, start1, end, seq1) = read_hdr()
|
||||
if start1 == start and seq1 == seq:
|
||||
return (seq, result.decode("utf-8"))
|
||||
|
||||
# Choose our last_seq based on whether to dump the pre-existing buffer
|
||||
(wlen, start, end, seq) = read_hdr()
|
||||
last_seq = seq
|
||||
if len(sys.argv) < 2 or sys.argv[1] != "--no-history":
|
||||
last_seq -= (end - start) % wlen
|
||||
|
||||
while True:
|
||||
time.sleep(0.1)
|
||||
(last_seq, output) = winstream_read(last_seq)
|
||||
if output:
|
||||
sys.stdout.write(output)
|
|
@ -1,123 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright(c) 2021 Intel Corporation. All rights reserved.
|
||||
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
from cavs_fw_common import *
|
||||
|
||||
# Intel Audio DSP firmware loader. No dependencies on anything
|
||||
# outside this file beyond Python3 builtins. Assumes the host system
|
||||
# has a hugetlbs mounted at /dev/hugepages. Confirmed to run out of
|
||||
# the box on Ubuntu 18.04 and 20.04. Run as root with the firmware
|
||||
# file as the single argument.
|
||||
|
||||
logging.basicConfig()
|
||||
log = logging.getLogger("cavs-fw")
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
FW_FILE = sys.argv[2] if sys.argv[1] == "-f" else sys.argv[1]
|
||||
|
||||
HDA_PPCTL__GPROCEN = 1 << 30
|
||||
HDA_SD_CTL__TRAFFIC_PRIO = 1 << 18
|
||||
HDA_SD_CTL__START = 1 << 1
|
||||
|
||||
def main():
|
||||
with open(FW_FILE, "rb") as f:
|
||||
fw_bytes = f.read()
|
||||
|
||||
(magic, sz) = struct.unpack("4sI", fw_bytes[0:8])
|
||||
if magic == b'XMan':
|
||||
fw_bytes = fw_bytes[sz:len(fw_bytes)]
|
||||
|
||||
(hda, sd, dsp, hda_ostream_id, cavs15) = map_regs() # Device register mappings
|
||||
log.info(f"Detected cAVS {'1.5' if cavs15 else '1.8+'} hardware")
|
||||
|
||||
# Turn on HDA "global processing enable" first, which actually
|
||||
# means "enable access to the ADSP registers in PCI BAR 4" (!)
|
||||
hda.PPCTL |= HDA_PPCTL__GPROCEN
|
||||
|
||||
# Turn off the DSP CPUs (each byte of ADSPCS is a bitmask for each
|
||||
# of 1-8 DSP cores: lowest byte controls "stall", the second byte
|
||||
# engages "reset", the third controls power, and the highest byte
|
||||
# is the output state for "powered" to be read after a state
|
||||
# change. Set stall and reset, and turn off power for everything:
|
||||
dsp.ADSPCS = 0xffff
|
||||
while dsp.ADSPCS & 0xff000000: pass
|
||||
|
||||
# Reset the HDA device
|
||||
hda.GCTL = 0
|
||||
while hda.GCTL & 1: pass
|
||||
hda.GCTL = 1
|
||||
while not hda.GCTL & 1: pass
|
||||
|
||||
# Power up (and clear stall and reset on) all the cores on the DSP
|
||||
# and wait for CPU0 to show that it has power
|
||||
dsp.ADSPCS = 0xff0000
|
||||
while (dsp.ADSPCS & 0x1000000) == 0: pass
|
||||
|
||||
# Wait for the ROM to boot and signal it's ready. This short
|
||||
# sleep seems to be needed; if we're banging on the memory window
|
||||
# during initial boot (before/while the window control registers
|
||||
# are configured?) the DSP hardware will hang fairly reliably.
|
||||
time.sleep(0.1)
|
||||
while (dsp.SRAM_FW_STATUS >> 24) != 5: pass
|
||||
|
||||
# Send the DSP an IPC message to tell the device how to boot
|
||||
# ("PURGE_FW" means "load new code") and which DMA channel to use.
|
||||
# The high bit is the "BUSY" signal bit that latches a device
|
||||
# interrupt.
|
||||
dsp.HIPCI = ( (1 << 31) # BUSY bit
|
||||
| (0x01 << 24) # type = PURGE_FW
|
||||
| (1 << 14) # purge_fw = 1
|
||||
| (hda_ostream_id << 9)) # dma_id
|
||||
|
||||
# Configure our DMA stream to transfer the firmware image
|
||||
(buf_list_addr, num_bufs) = setup_dma_mem(fw_bytes)
|
||||
sd.BDPU = (buf_list_addr >> 32) & 0xffffffff
|
||||
sd.BDPL = buf_list_addr & 0xffffffff
|
||||
sd.CBL = len(fw_bytes)
|
||||
sd.LVI = num_bufs - 1
|
||||
|
||||
# Enable "processing" on the output stream (send DMA to the DSP
|
||||
# and not the audio output hardware)
|
||||
hda.PPCTL |= (HDA_PPCTL__GPROCEN | (1 << hda_ostream_id))
|
||||
|
||||
# SPIB ("Software Position In Buffer") a Intel HDA extension that
|
||||
# puts a transfer boundary into the stream beyond which the other
|
||||
# side will not read. The ROM wants to poll on a "buffer full"
|
||||
# bit on the other side that only works with this enabled.
|
||||
hda.SD_SPIB = len(fw_bytes)
|
||||
hda.SPBFCTL |= (1 << hda_ostream_id)
|
||||
|
||||
# Uncork the stream
|
||||
sd.CTL |= HDA_SD_CTL__START
|
||||
|
||||
# FIXME: The ROM sets a FW_ENTERED value of 5 into the bottom 28
|
||||
# bit "state" field of FW_STATUS on entry to the app. But this is
|
||||
# actually ephemeral and racy, because Zephyr is free to write its
|
||||
# own data once the app launches and we might miss it. There's no
|
||||
# standard "alive" signaling from the OS, which is really what we
|
||||
# want to wait for. So give it one second and move on.
|
||||
for _ in range(100):
|
||||
alive = dsp.SRAM_FW_STATUS & ((1 << 28) - 1) == 5
|
||||
if alive: break
|
||||
time.sleep(0.01)
|
||||
if not alive:
|
||||
log.warning(f"Load failed? FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}")
|
||||
|
||||
# Turn DMA off and reset the stream. If this doesn't happen the
|
||||
# hardware continues streaming out of our now-stale page and can
|
||||
# has been observed to glitch the next boot.
|
||||
sd.CTL &= ~HDA_SD_CTL__START
|
||||
sd.CTL |= 1
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
log.info(f"ADSPCS = 0x{dsp.ADSPCS:x}")
|
||||
log.info(f"cAVS v15 firmware load complete, {ncores(dsp)} cores active")
|
||||
|
||||
if __name__ == "__main__":
|
||||
log.info("cAVS firmware loader v15")
|
||||
main()
|
|
@ -1,189 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright(c) 2021 Intel Corporation. All rights reserved.
|
||||
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
from cavs_fw_common import *
|
||||
|
||||
# Intel Audio DSP firmware loader. No dependencies on anything
|
||||
# outside this file beyond Python3 builtins. Pass a signed rimage
|
||||
# file as the single argument.
|
||||
|
||||
logging.basicConfig()
|
||||
log = logging.getLogger("cavs-fw")
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
FW_FILE = sys.argv[1]
|
||||
|
||||
HDA_PPCTL__GPROCEN = 1 << 30
|
||||
HDA_SD_CTL__TRAFFIC_PRIO = 1 << 18
|
||||
HDA_SD_CTL__START = 1 << 1
|
||||
|
||||
def main():
|
||||
if os.system("lsmod | grep -q snd_sof_pci") == 0:
|
||||
log.warning("The Linux snd-sof-pci kernel module is loaded. While this")
|
||||
log.warning(" loader will normally work in such circumstances, things")
|
||||
log.warning(" will get confused if the system tries to touch the hardware")
|
||||
log.warning(" simultaneously. Operation is most reliable if it is")
|
||||
log.warning(" unloaded first.")
|
||||
|
||||
# Make sure hugetlbfs is mounted (not there on chromeos)
|
||||
os.system("mount | grep -q hugetlbfs ||"
|
||||
+ " (mkdir -p /dev/hugepages; "
|
||||
+ " mount -t hugetlbfs hugetlbfs /dev/hugepages)")
|
||||
|
||||
with open(FW_FILE, "rb") as f:
|
||||
fw_bytes = f.read()
|
||||
|
||||
(magic, sz) = struct.unpack("4sI", fw_bytes[0:8])
|
||||
if magic == b'XMan':
|
||||
log.info(f"Trimming {sz} bytes of extended manifest")
|
||||
fw_bytes = fw_bytes[sz:len(fw_bytes)]
|
||||
|
||||
(hda, sd, dsp, hda_ostream_id, cavs15) = map_regs() # Device register mappings
|
||||
log.info(f"Detected cAVS {'1.5' if cavs15 else '1.8+'} hardware")
|
||||
|
||||
# Reset the HDA device
|
||||
log.info("Reset HDA device")
|
||||
hda.GCTL = 0
|
||||
while hda.GCTL & 1: pass
|
||||
hda.GCTL = 1
|
||||
while not hda.GCTL & 1: pass
|
||||
|
||||
# Turn on HDA "global processing enable" first. As documented,
|
||||
# this enables the audio DSP (vs. hardware HDA emulation). But it
|
||||
# actually means "enable access to the ADSP registers in PCI BAR 4" (!)
|
||||
log.info("Enable HDA global processing")
|
||||
hda.PPCTL |= HDA_PPCTL__GPROCEN
|
||||
|
||||
# Turn off the DSP CPUs (each byte of ADSPCS is a bitmask for each
|
||||
# of 1-8 DSP cores: lowest byte controls "stall", the second byte
|
||||
# engages "reset", the third controls power, and the highest byte
|
||||
# is the output state for "powered" to be read after a state
|
||||
# change. Set stall and reset, and turn off power for everything:
|
||||
log.info(f"Powering down, ADSPCS = 0x{dsp.ADSPCS:x}")
|
||||
dsp.ADSPCS = 0xffff
|
||||
while dsp.ADSPCS & 0xff000000: pass
|
||||
log.info(f"Powered down, ADSPCS = 0x{dsp.ADSPCS:x}")
|
||||
|
||||
# Configure our DMA stream to transfer the firmware image
|
||||
log.info(f"Configuring DMA output stream {hda_ostream_id}...")
|
||||
(buf_list_addr, num_bufs) = setup_dma_mem(fw_bytes)
|
||||
|
||||
# Reset stream
|
||||
sd.CTL = 1
|
||||
while (sd.CTL & 1) == 0: pass
|
||||
sd.CTL = 0
|
||||
while (sd.CTL & 1) == 1: pass
|
||||
|
||||
sd.CTL = (1 << 20) # Set stream ID to anything non-zero
|
||||
sd.BDPU = (buf_list_addr >> 32) & 0xffffffff
|
||||
sd.BDPL = buf_list_addr & 0xffffffff
|
||||
sd.CBL = len(fw_bytes)
|
||||
sd.LVI = num_bufs - 1
|
||||
|
||||
# Enable "processing" on the output stream (send DMA to the DSP
|
||||
# and not the audio output hardware)
|
||||
hda.PPCTL |= (HDA_PPCTL__GPROCEN | (1 << hda_ostream_id))
|
||||
|
||||
# SPIB ("Software Position In Buffer") is an Intel HDA extension
|
||||
# that puts a transfer boundary into the stream beyond which the
|
||||
# other side will not read. The ROM wants to poll on a "buffer
|
||||
# full" bit on the other side that only works with this enabled.
|
||||
hda.SPBFCTL |= (1 << hda_ostream_id)
|
||||
hda.SD_SPIB = len(fw_bytes)
|
||||
|
||||
# Power up all the cores on the DSP and wait for CPU0 to show that
|
||||
# it has power. Leave stall and reset high for now
|
||||
log.info(f"Powering up DSP core #0, ADSPCS = 0x{dsp.ADSPCS:x}")
|
||||
dsp.ADSPCS = 0x01ffff
|
||||
while (dsp.ADSPCS & 0x01000000) == 0: pass
|
||||
log.info(f"Powered up {ncores(dsp)} cores, ADSPCS = 0x{dsp.ADSPCS:x}")
|
||||
|
||||
# Send the DSP an IPC message to tell the device how to boot
|
||||
# ("PURGE_FW" means "load new code") and which DMA channel to use.
|
||||
# The high bit is the "BUSY" signal bit that latches a device
|
||||
# interrupt.
|
||||
#
|
||||
# Note: with cAVS 1.8+ the ROM receives the stream argument as an index
|
||||
# within the array of output streams (and we always use the first
|
||||
# one by construction). But with 1.5 it's the HDA index, and
|
||||
# depends on the number of input streams on the device.
|
||||
stream_idx = hda_ostream_id if cavs15 else 0
|
||||
ipcval = ( (1 << 31) # BUSY bit
|
||||
| (0x01 << 24) # type = PURGE_FW
|
||||
| (1 << 14) # purge_fw = 1
|
||||
| (stream_idx << 9)) # dma_id
|
||||
log.info(f"Sending PURGW_FW IPC, HIPCR = 0x{ipcval:x}")
|
||||
dsp.HIPCI = ipcval
|
||||
|
||||
# Now start CPU #0 by dropping stall and reset
|
||||
log.info(f"Starting {ncores(dsp)} cores, ADSPCS = 0x{dsp.ADSPCS:x}")
|
||||
dsp.ADSPCS = 0x01fffe # Out of reset
|
||||
time.sleep(0.1)
|
||||
dsp.ADSPCS = 0x01fefe # Un-stall
|
||||
log.info(f"Started {ncores(dsp)} cores, ADSPCS = 0x{dsp.ADSPCS:x}")
|
||||
|
||||
# Experimentation shows that these steps aren't actually required,
|
||||
# the ROM just charges ahead and initializes itself correctly even
|
||||
# if we don't wait for it. Do them anyway for better visibility,
|
||||
# when requested. Potentially remove later once this code is
|
||||
# mature.
|
||||
if log.level <= logging.INFO:
|
||||
# Wait for the ROM to boot and signal it's ready. NOTE: This
|
||||
# short sleep seems to be needed; if we're banging on the
|
||||
# memory window during initial boot (before/while the window
|
||||
# control registers are configured?) the DSP hardware will
|
||||
# hang fairly reliably.
|
||||
time.sleep(0.1)
|
||||
log.info(f"Waiting for ROM init, FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}")
|
||||
while (dsp.SRAM_FW_STATUS >> 24) != 5: pass
|
||||
log.info(f"ROM ready, FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}")
|
||||
|
||||
# Newer devices have an ACK bit we can check
|
||||
if not cavs15:
|
||||
log.info(f"Awaiting IPC acknowledgment, HIPCA 0x{dsp.HIPCA:x}")
|
||||
while not dsp.HIPCA & (1 << 31): pass
|
||||
dsp.HIPCA |= ~(1 << 31)
|
||||
|
||||
# Wait for it to signal ROM_INIT_DONE
|
||||
log.info(f"Awaiting ROM init... FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}")
|
||||
while (dsp.SRAM_FW_STATUS & 0x00ffffff) != 1: pass
|
||||
|
||||
# It's ready, uncork the stream
|
||||
log.info(f"Starting DMA, FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}")
|
||||
sd.CTL |= HDA_SD_CTL__START
|
||||
|
||||
# The ROM sets a FW_ENTERED value of 5 into the bottom 28 bit
|
||||
# "state" field of FW_STATUS on entry to the app. (Pedantry: this
|
||||
# is actually ephemeral and racy, because Zephyr is free to write
|
||||
# its own data once the app launches and we might miss it.
|
||||
# There's no standard "alive" signaling from the OS, which is
|
||||
# really what we want to wait for. So give it one second and move
|
||||
# on).
|
||||
log.info(f"Waiting for load, FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}")
|
||||
for _ in range(100):
|
||||
alive = dsp.SRAM_FW_STATUS & ((1 << 28) - 1) == 5
|
||||
if alive: break
|
||||
time.sleep(0.01)
|
||||
if alive:
|
||||
log.info("ROM reports firmware was entered")
|
||||
else:
|
||||
log.warning(f"Load failed? FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}")
|
||||
|
||||
# Turn DMA off and reset the stream. If this doesn't happen the
|
||||
# hardware continues streaming out of our now-stale page and has
|
||||
# been observed to glitch the next boot.
|
||||
sd.CTL = 1
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
log.info(f"ADSPCS = 0x{dsp.ADSPCS:x}")
|
||||
log.info(f"cAVS v25 firmware load complete, {ncores(dsp)} cores active")
|
||||
|
||||
if __name__ == "__main__":
|
||||
log.info("cAVS firmware loader v25")
|
||||
main()
|
|
@ -1,174 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright(c) 2021 Intel Corporation. All rights reserved.
|
||||
|
||||
import ctypes
|
||||
import mmap
|
||||
import os
|
||||
import struct
|
||||
import subprocess
|
||||
import time
|
||||
import logging
|
||||
|
||||
logging.basicConfig()
|
||||
log = logging.getLogger("cavs-fw")
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
global_mmaps = [] # protect mmap mappings from garbage collection!
|
||||
|
||||
PAGESZ = 4096
|
||||
HUGEPAGESZ = 2 * 1024 * 1024
|
||||
HUGEPAGE_FILE = "/dev/hugepages/cavs-fw-dma.tmp"
|
||||
|
||||
# Count of active/running cores
|
||||
def ncores(dsp):
|
||||
return bin(dsp.ADSPCS >> 24).count("1")
|
||||
|
||||
def map_regs():
|
||||
# List cribbed from kernel SOF driver. Not all tested!
|
||||
for id in ["119a", "5a98", "1a98", "3198", "9dc8",
|
||||
"a348", "34C8", "38c8", "4dc8", "02c8",
|
||||
"06c8", "a3f0", "a0c8", "4b55", "4b58"]:
|
||||
p = runx(f"grep -il PCI_ID=8086:{id} /sys/bus/pci/devices/*/uevent")
|
||||
if p:
|
||||
pcidir = os.path.dirname(p)
|
||||
break
|
||||
|
||||
# Detect hardware version, this matters in a few spots
|
||||
cavs15 = id in [ "5a98", "1a98", "3198" ]
|
||||
|
||||
# Disengage runtime power management so the kernel doesn't put it to sleep
|
||||
with open(pcidir + b"/power/control", "w") as ctrl:
|
||||
ctrl.write("on")
|
||||
|
||||
# Make sure PCI memory space access and busmastering are enabled.
|
||||
# Also disable interrupts so as not to confuse the kernel.
|
||||
with open(pcidir + b"/config", "wb+") as cfg:
|
||||
cfg.seek(4)
|
||||
cfg.write(b'\x06\x04')
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
hdamem = bar_map(pcidir, 0)
|
||||
|
||||
# Standard HD Audio Registers
|
||||
hda = Regs(hdamem)
|
||||
hda.GCAP = 0x0000
|
||||
hda.GCTL = 0x0008
|
||||
hda.SPBFCTL = 0x0704
|
||||
hda.PPCTL = 0x0804
|
||||
|
||||
# Find the ID of the first output stream
|
||||
hda_ostream_id = (hda.GCAP >> 8) & 0x0f # number of input streams
|
||||
log.info(f"Selected output stream {hda_ostream_id} (GCAP = 0x{hda.GCAP:x})")
|
||||
hda.SD_SPIB = 0x0708 + (8 * hda_ostream_id)
|
||||
|
||||
hda.freeze()
|
||||
|
||||
# Standard HD Audio Stream Descriptor
|
||||
sd = Regs(hdamem + 0x0080 + (hda_ostream_id * 0x20))
|
||||
sd.CTL = 0x00
|
||||
sd.LPIB = 0x04
|
||||
sd.CBL = 0x08
|
||||
sd.LVI = 0x0c
|
||||
sd.FMT = 0x12
|
||||
sd.BDPL = 0x18
|
||||
sd.BDPU = 0x1c
|
||||
sd.freeze()
|
||||
|
||||
# Intel Audio DSP Registers
|
||||
dsp = Regs(bar_map(pcidir, 4))
|
||||
dsp.ADSPCS = 0x00004
|
||||
if cavs15:
|
||||
dsp.HIPCI = 0x00048 # original name of the register...
|
||||
else:
|
||||
dsp.HIPCI = 0x000d0 # ...now named "HIPCR" per 1.8+ docs
|
||||
dsp.HIPCA = 0x000d4
|
||||
dsp.SRAM_FW_STATUS = 0x80000 # Start of first SRAM window
|
||||
dsp.freeze()
|
||||
|
||||
return (hda, sd, dsp, hda_ostream_id, cavs15)
|
||||
|
||||
def setup_dma_mem(fw_bytes):
|
||||
(mem, phys_addr) = map_phys_mem()
|
||||
mem[0:len(fw_bytes)] = fw_bytes
|
||||
|
||||
log.info("Mapped 2M huge page at 0x%x to contain %d bytes of firmware"
|
||||
% (phys_addr, len(fw_bytes)))
|
||||
|
||||
# HDA requires at least two buffers be defined, but we don't care
|
||||
# about boundaries because it's all a contiguous region. Place a
|
||||
# vestigial 128-byte (minimum size and alignment) buffer after the
|
||||
# main one, and put the 4-entry BDL list into the final 128 bytes
|
||||
# of the page.
|
||||
buf0_len = HUGEPAGESZ - 2 * 128
|
||||
buf1_len = 128
|
||||
bdl_off = buf0_len + buf1_len
|
||||
mem[bdl_off:bdl_off + 32] = struct.pack("<QQQQ",
|
||||
phys_addr, buf0_len,
|
||||
phys_addr + buf0_len, buf1_len)
|
||||
log.info("Filled the buffer descriptor list (BDL) for DMA.")
|
||||
return (phys_addr + bdl_off, 2)
|
||||
|
||||
# Maps 2M of contiguous memory using a single page from hugetlbfs,
|
||||
# then locates its physical address for use as a DMA buffer.
|
||||
def map_phys_mem():
|
||||
# Ensure the kernel has enough budget for one new page
|
||||
free = int(runx("awk '/HugePages_Free/ {print $2}' /proc/meminfo"))
|
||||
if free == 0:
|
||||
tot = 1 + int(runx("awk '/HugePages_Total/ {print $2}' /proc/meminfo"))
|
||||
os.system(f"echo {tot} > /proc/sys/vm/nr_hugepages")
|
||||
|
||||
hugef = open(HUGEPAGE_FILE, "w+")
|
||||
hugef.truncate(HUGEPAGESZ)
|
||||
mem = mmap.mmap(hugef.fileno(), HUGEPAGESZ)
|
||||
global_mmaps.append(mem)
|
||||
os.unlink(HUGEPAGE_FILE)
|
||||
|
||||
# Find the local process address of the mapping, then use that to
|
||||
# extract the physical address from the kernel's pagemap
|
||||
# interface. The physical page frame number occupies the bottom
|
||||
# bits of the entry.
|
||||
mem[0] = 0 # Fault the page in so it has an address!
|
||||
vaddr = ctypes.addressof(ctypes.c_int.from_buffer(mem))
|
||||
vpagenum = vaddr >> 12
|
||||
pagemap = open("/proc/self/pagemap", "rb")
|
||||
pagemap.seek(vpagenum * 8)
|
||||
pent = pagemap.read(8)
|
||||
paddr = (struct.unpack("Q", pent)[0] & ((1 << 55) - 1)) * PAGESZ
|
||||
pagemap.close()
|
||||
log.info("Obtained the physical address of the mapped huge page.")
|
||||
|
||||
return (mem, paddr)
|
||||
|
||||
# Maps a PCI BAR and returns the in-process address
|
||||
def bar_map(pcidir, barnum):
|
||||
f = open(pcidir.decode() + "/resource" + str(barnum), "r+")
|
||||
mm = mmap.mmap(f.fileno(), os.fstat(f.fileno()).st_size)
|
||||
global_mmaps.append(mm)
|
||||
log.info("Mapped PCI bar %d of length %d bytes." % (barnum, os.fstat(f.fileno()).st_size))
|
||||
return ctypes.addressof(ctypes.c_int.from_buffer(mm))
|
||||
|
||||
# Syntactic sugar to make register block definition & use look nice.
|
||||
# Instantiate from a base address, assign offsets to (uint32) named
|
||||
# registers as fields, call freeze(), then the field acts as a direct
|
||||
# alias for the register!
|
||||
class Regs:
|
||||
def __init__(self, base_addr):
|
||||
vars(self)["base_addr"] = base_addr
|
||||
vars(self)["ptrs"] = {}
|
||||
vars(self)["frozen"] = False
|
||||
def freeze(self):
|
||||
vars(self)["frozen"] = True
|
||||
def __setattr__(self, name, val):
|
||||
if not self.frozen and name not in self.ptrs:
|
||||
addr = self.base_addr + val
|
||||
self.ptrs[name] = ctypes.c_uint32.from_address(addr)
|
||||
else:
|
||||
self.ptrs[name].value = val
|
||||
def __getattr__(self, name):
|
||||
return self.ptrs[name].value
|
||||
|
||||
def runx(cmd):
|
||||
return subprocess.Popen(["sh", "-c", cmd],
|
||||
stdout=subprocess.PIPE).stdout.read()
|
|
@ -1,117 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Copyright (c) 2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
set -e
|
||||
|
||||
# General purpose loader tool for a remote ssh-accessible CAVS 1.5
|
||||
# device (e.g. an Up Squared board running Linux). Can be used as the
|
||||
# twister hook for both --device-serial-pty and --west-flash, e.g.:
|
||||
#
|
||||
# twister -p intel_adsp_cavs15 \
|
||||
# --device-testing --device-serial-pty=/path/to/cavsload.sh \
|
||||
# --west-flash=/path/to/cavsload.sh
|
||||
#
|
||||
# Alternatively, pass a built "zephyr.elf" file (in a complete build
|
||||
# tree, not just a standalone file) as the single argument and the
|
||||
# script will synchronously flash the device and begin emitting its
|
||||
# logs to standard output.
|
||||
#
|
||||
# The remote host must be accessible via non-interactive ssh access
|
||||
# and the remote account must have password-free sudo ability. (The
|
||||
# intent is that isolating the host like this to be a CAVS test unit
|
||||
# means that simple device access at root is acceptable.) There must
|
||||
# be a current Zephyr tree on the host, and a working loadable
|
||||
# "diag_driver" kernel module.
|
||||
|
||||
# Remote host on which to test
|
||||
HOST=up2
|
||||
|
||||
# Zephyr tree on the host
|
||||
HOST_ZEPHYR_BASE=z/zephyr
|
||||
|
||||
# rimage key to use for signing binaries
|
||||
KEY=$HOME/otc_private_key.pem
|
||||
|
||||
# Local path to a built rimage (https://github.com/thesofproject/rimage)
|
||||
RIMAGE=$ZEPHYR_BASE/../modules/audio/sof/zephyr/ext/rimage
|
||||
|
||||
# Kernel module on host (https://github.com/thesofproject/sof-diagnostic-driver)
|
||||
HOST_DRIVER=sof-diagnostic-driver/diag_driver.ko
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Twister has frustrating runtime behavior with this device. The
|
||||
# flash tool is run via west as part of the build, has a working
|
||||
# directory in the build tree, and is passed the build directory as
|
||||
# its command line argument. The console/serial tool is run globally
|
||||
# in $ZEPHYR_BASE. But the console script has no arguments, and thus
|
||||
# can't find the test directory! And worse, the scripts are
|
||||
# asynchronous and may start in either order, but our console script
|
||||
# can't be allowed to run until after the flash. If it does, it will
|
||||
# pull old data (from the last test run!) out of the buffer and
|
||||
# confuse twister.
|
||||
#
|
||||
# So the solution here is to have the console script do the trace
|
||||
# reading AND the flashing. The flash script merely signs the binary
|
||||
# and places it into ZEPHYR_BASE for the console script to find. The
|
||||
# console script then just has to wait for the binary to appear (which
|
||||
# solves the ordering problem), flash it, delete it (so as not to
|
||||
# confuse the next test run), and emit the adsplog output as expected.
|
||||
#
|
||||
# One side effect is that the logs for the firmware load appear in a
|
||||
# separate file ("cavslog_load.log" in $ZEPHYR_BASE) and not the
|
||||
# device.log file that twister expects.
|
||||
|
||||
if [ "$(basename $1)" = "zephyr.elf" ]; then
|
||||
# Standalone mode (argument is a path to zephyr.elf)
|
||||
BLDDIR=$(dirname $(dirname $1))
|
||||
DO_SIGN=1
|
||||
DO_LOAD=1
|
||||
DO_LOG=1
|
||||
elif [ "$1" = "" ]; then
|
||||
# Twister --device-serial-pty mode
|
||||
DO_LOAD=1
|
||||
DO_LOG=1
|
||||
else
|
||||
# Twister --west-flash mode
|
||||
BLDDIR=$1
|
||||
DO_SIGN=1
|
||||
fi
|
||||
|
||||
IMAGE=$ZEPHYR_BASE/_cavstmp.ri
|
||||
LOADLOG=$ZEPHYR_BASE/_cavsload_load.log
|
||||
HOST_TOOLS=$HOST_ZEPHYR_BASE/boards/xtensa/intel_adsp_cavs15/tools
|
||||
FWLOAD=$HOST_TOOLS/fw_loader.py
|
||||
ADSPLOG=$HOST_TOOLS/adsplog.py
|
||||
|
||||
if [ "$DO_SIGN" = "1" ]; then
|
||||
ELF=$BLDDIR/zephyr/zephyr.elf.mod
|
||||
BOOT=$BLDDIR/zephyr/bootloader.elf.mod
|
||||
$RIMAGE/rimage -v -k $KEY -o $IMAGE -c $RIMAGE/config/apl.toml \
|
||||
-i 3 -e $BOOT $ELF > $BLDDIR/rimage.log
|
||||
fi
|
||||
|
||||
if [ "$DO_LOAD" = "1" ]; then
|
||||
while [ ! -e $IMAGE ]; do
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
scp $IMAGE $HOST:_cavstmp.ri
|
||||
ssh $HOST "(lsmod | grep -q diag_driver) || sudo insmod $HOST_DRIVER"
|
||||
|
||||
# The script sometimes gets stuck
|
||||
ssh $HOST "sudo pkill -f -9 fw_loader.py" || true
|
||||
ssh $HOST "sudo $FWLOAD -f _cavstmp.ri || true" > $LOADLOG 2>&1
|
||||
|
||||
if [ "$DO_SIGN" = "1" ]; then
|
||||
cat $LOADLOG
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
rm -f $IMAGE
|
||||
fi
|
||||
|
||||
if [ "$DO_LOG" = "1" ]; then
|
||||
ssh $HOST "sudo pkill -f -9 adsplog.py" || true
|
||||
ssh $HOST "sudo $ADSPLOG"
|
||||
fi
|
|
@ -1,65 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
from lib.device import Device
|
||||
from lib.etrace import Etrace
|
||||
|
||||
def parse_args():
|
||||
|
||||
arg_parser = argparse.ArgumentParser(description="Dump trace message")
|
||||
|
||||
arg_parser.add_argument("-o", "--output-file", default=None,
|
||||
help="Save to output file")
|
||||
arg_parser.add_argument("-d", "--debug", default=False, action='store_true',
|
||||
help="Display debug information")
|
||||
arg_parser.add_argument("-x", "--hexdump", default=False, action='store_true',
|
||||
help="Display hexdump")
|
||||
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
def main():
|
||||
""" Main Entry Point """
|
||||
|
||||
args = parse_args()
|
||||
|
||||
log_level = logging.INFO
|
||||
if args.debug:
|
||||
log_level = logging.DEBUG
|
||||
|
||||
logging.basicConfig(level=log_level, format="%(message)s")
|
||||
|
||||
dev = Device()
|
||||
dev.open_device()
|
||||
|
||||
etrace = Etrace(dev)
|
||||
etrace.print()
|
||||
|
||||
if args.hexdump:
|
||||
etrace.hexdump()
|
||||
|
||||
if args.output_file:
|
||||
etrace.save(args.output_file)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
os._exit(0)
|
||||
except KeyboardInterrupt: # Ctrl-C
|
||||
os._exit(14)
|
||||
except SystemExit:
|
||||
raise
|
||||
except BaseException:
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
os._exit(16)
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
BUILD=$1
|
||||
FIRMWARE=${BUILD}/zephyr/zephyr.ri
|
||||
FLASHER=${ZEPHYR_BASE}/boards/xtensa/intel_adsp_cavs15/tools/fw_loader.py
|
||||
|
||||
if [ -z "$2" ]
|
||||
then
|
||||
echo "Signing using default key"
|
||||
west sign -d ${BUILD} -t rimage
|
||||
elif [ -n "$3" ] && [ -n "$4" ]
|
||||
then
|
||||
echo "Signing with key " $key
|
||||
west sign -d ${BUILD} -t rimage -p $4 -D $3 -- -k $2 --no-manifest
|
||||
fi
|
||||
echo ${FLASHER} -f ${FIRMWARE}
|
||||
${FLASHER} -f ${FIRMWARE} || /bin/true 2>&1
|
|
@ -1,90 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
from colorama import Fore, Style
|
||||
from lib.loader import FirmwareLoader, FirmwareStatus
|
||||
import lib.platforms as plat_def
|
||||
|
||||
|
||||
def check_args(args):
|
||||
# Check if firmware exists
|
||||
firmware_abs = os.path.abspath(args.firmware)
|
||||
if not os.path.exists(firmware_abs):
|
||||
raise ValueError("File not found: %s" % firmware_abs)
|
||||
|
||||
|
||||
def parse_args():
|
||||
arg_parser = argparse.ArgumentParser(description="ADSP firmware loader")
|
||||
arg_parser.add_argument("-f", "--firmware", required=True,
|
||||
help="ADSP firmware file to load")
|
||||
arg_parser.add_argument("-d", "--debug", default=False, action='store_true',
|
||||
help="Display debug information")
|
||||
args = arg_parser.parse_args()
|
||||
check_args(args)
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
""" Main Entry Point """
|
||||
|
||||
args = parse_args()
|
||||
|
||||
log_level = logging.INFO
|
||||
if args.debug:
|
||||
log_level = logging.DEBUG
|
||||
logging.basicConfig(level=log_level, format="%(message)s")
|
||||
|
||||
logging.info("Start firmware downloading...")
|
||||
fw_loader = FirmwareLoader()
|
||||
|
||||
# Use Stream #7 for firmware download DMA
|
||||
fw_loader.init(plat_def.DMA_ID)
|
||||
|
||||
logging.info("Reset DSP...")
|
||||
fw_loader.reset_dsp()
|
||||
FirmwareStatus(fw_loader.dev.fw_status.value).print()
|
||||
logging.info(" IPC CMD : %s" % fw_loader.dev.ipc_cmd)
|
||||
logging.info(" IPC LEN : %s" % fw_loader.dev.ipc_len)
|
||||
|
||||
logging.info("Booting up DSP...")
|
||||
fw_loader.boot_dsp()
|
||||
FirmwareStatus(fw_loader.dev.fw_status.value).print()
|
||||
|
||||
fw_loader.wait_for_fw_boot_status(plat_def.BOOT_STATUS_INIT_DONE)
|
||||
|
||||
logging.info("Downloading firmware...")
|
||||
fw_loader.download_firmware(args.firmware)
|
||||
|
||||
logging.info("Checking firmware status...")
|
||||
if fw_loader.check_fw_boot_status(plat_def.BOOT_STATUS_FW_ENTERED):
|
||||
logging.info(Fore.LIGHTGREEN_EX +
|
||||
"Firmware download completed successfully"
|
||||
+ Style.RESET_ALL)
|
||||
logging.info("Reading IPC FwReady Message...")
|
||||
fw_loader.ipc.read_fw_ready()
|
||||
else:
|
||||
logging.error(Fore.RED +
|
||||
"!!!!! Failed to download firmware !!!!!"
|
||||
+ Style.RESET_ALL)
|
||||
fw_loader.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
os._exit(0)
|
||||
except KeyboardInterrupt: # Ctrl-C
|
||||
os._exit(14)
|
||||
except SystemExit:
|
||||
raise
|
||||
except BaseException:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
os._exit(16)
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
|
@ -1,245 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import time
|
||||
import logging
|
||||
from ctypes import c_uint16, addressof
|
||||
|
||||
from lib.driver import DiagDriver, Register
|
||||
import lib.registers as regs_def
|
||||
import lib.platforms as plat_def
|
||||
|
||||
|
||||
class Device:
|
||||
|
||||
def __init__(self):
|
||||
self.__opened = False
|
||||
|
||||
self.drv = DiagDriver()
|
||||
self.dev_info = None
|
||||
|
||||
self.hda_bar_mmap = None
|
||||
self.dsp_bar_mmap = None
|
||||
|
||||
self.hda_gctl = None
|
||||
self.hda_gcap = None
|
||||
self.hda_ppctl = None
|
||||
self.hda_spibe = None
|
||||
|
||||
self.dsp_ctl_sts = None
|
||||
self.dsp_hipci = None
|
||||
self.dsp_hipcie = None
|
||||
self.dsp_hipct = None
|
||||
|
||||
self.fw_status = None
|
||||
self.fw_err_code = None
|
||||
|
||||
self.ipc_len = None
|
||||
self.ipc_cmd = None
|
||||
|
||||
self.allocated = []
|
||||
|
||||
def close(self):
|
||||
if not self.__opened:
|
||||
logging.warning("Audio device not opened!!!")
|
||||
return
|
||||
self.__opened = False
|
||||
|
||||
def open_device(self):
|
||||
logging.debug(">>> Device.open_device()")
|
||||
|
||||
# Open device to get HDA BAR and DSP BAR
|
||||
self.dev_info = self.drv.open_device()
|
||||
|
||||
# HDA MMAP
|
||||
self.hda_bar_mmap = self.drv.mmap(self.dev_info.hda_bar.base_p,
|
||||
self.dev_info.hda_bar.size)
|
||||
self.dev_info.hda_bar.base_v = addressof(self.hda_bar_mmap)
|
||||
# DSP MMAP
|
||||
self.dsp_bar_mmap = self.drv.mmap(self.dev_info.dsp_bar.base_p,
|
||||
self.dev_info.dsp_bar.size)
|
||||
self.dev_info.dsp_bar.base_v = addressof(self.dsp_bar_mmap)
|
||||
logging.debug(self.dev_info)
|
||||
|
||||
# Registers from HDA
|
||||
self.hda_gctl = Register(self.hda_bar_mmap,
|
||||
regs_def.HDA_GR_GCTL)
|
||||
self.hda_gcap = Register(self.hda_bar_mmap,
|
||||
regs_def.HDA_GR_GCAP, c_uint16)
|
||||
self.hda_ppctl = Register(self.hda_bar_mmap,
|
||||
regs_def.HDA_PPC_PPCTL)
|
||||
self.hda_spibe = Register(self.hda_bar_mmap,
|
||||
regs_def.HDA_SPBF_SPBFCTL)
|
||||
# Registers from DSP
|
||||
self.dsp_ctl_sts = Register(self.dsp_bar_mmap,
|
||||
regs_def.ADSP_GR_ADSPCS)
|
||||
self.dsp_hipci = Register(self.dsp_bar_mmap,
|
||||
regs_def.ADSP_IPC_HIPCI)
|
||||
self.dsp_hipcie = Register(self.dsp_bar_mmap,
|
||||
regs_def.ADSP_IPC_HIPCIE)
|
||||
self.dsp_hipct = Register(self.dsp_bar_mmap,
|
||||
regs_def.ADSP_IPC_HIPCT)
|
||||
self.fw_status = Register(self.dsp_bar_mmap,
|
||||
plat_def.FW_STATUS)
|
||||
self.fw_err_code = Register(self.dsp_bar_mmap,
|
||||
plat_def.FW_ERR_CODE)
|
||||
self.ipc_len = Register(self.dsp_bar_mmap,
|
||||
plat_def.FW_MBOX_UPLINK + plat_def.IPC_GLOBAL_LEN)
|
||||
self.ipc_cmd = Register(self.dsp_bar_mmap,
|
||||
plat_def.FW_MBOX_UPLINK + plat_def.IPC_GLOBAL_CMD)
|
||||
|
||||
self.__opened = True
|
||||
logging.debug("<<< Device.open_device()")
|
||||
|
||||
def alloc_memory(self, size):
|
||||
logging.debug(">>> Device.alloc_memory()")
|
||||
buf = self.drv.alloc_mem(size)
|
||||
if buf.dma_addr_p == 0:
|
||||
raise RuntimeError("Could not allocate the memory")
|
||||
self.allocated.append(buf)
|
||||
logging.debug("<<< Device.alloc_memory()")
|
||||
return buf
|
||||
|
||||
def free_memory(self, mem):
|
||||
logging.debug(">>> Device.free_memory()")
|
||||
if mem in self.allocated:
|
||||
ret = self.drv.free_mem(mem)
|
||||
if ret != 0:
|
||||
logging.error("Failed to free memory")
|
||||
self.allocated.remove(mem)
|
||||
else:
|
||||
logging.warning("Cannot find the memory from list")
|
||||
logging.debug("<<< Device.free_memory()")
|
||||
|
||||
def power_cycle(self):
|
||||
logging.debug("Controller power down")
|
||||
self.hda_gctl.value = 0
|
||||
while self.hda_gctl.value != 0:
|
||||
time.sleep(0.1)
|
||||
logging.debug(" HDA_GCTL=%s" % self.hda_gctl)
|
||||
|
||||
logging.debug("Controller power up")
|
||||
self.hda_gctl.value = 1
|
||||
while self.hda_gctl.value != 1:
|
||||
time.sleep(0.1)
|
||||
logging.debug(" HDA_GCTL=%s" % self.hda_gctl)
|
||||
|
||||
def enable_proc_pipe_ctl(self):
|
||||
logging.debug("Enable processing pipe control")
|
||||
iss = ((self.hda_gcap.value & regs_def.HDA_GR_GCAP_ISS)
|
||||
>> regs_def.HDA_GR_GCAP_ISS_OFFSET)
|
||||
oss = ((self.hda_gcap.value & regs_def.HDA_GR_GCAP_OSS)
|
||||
>> regs_def.HDA_GR_GCAP_OSS_OFFSET)
|
||||
|
||||
iss_mask = int("1" * iss, 2)
|
||||
oss_mask = int("1" * oss, 2)
|
||||
|
||||
dma_mask = iss_mask + (oss_mask << iss)
|
||||
|
||||
# Enable processing pipe
|
||||
self.hda_ppctl.value = self.hda_ppctl.value | 0x40000000 | dma_mask
|
||||
logging.debug(" HDA_PPCTL=%s" % self.hda_ppctl)
|
||||
|
||||
def get_ipc_message(self):
|
||||
logging.info("Read IPC message from DSP")
|
||||
logging.info("IPC LEN: %s" % self.ipc_len)
|
||||
logging.info("IPC CMD: %s" % self.ipc_cmd)
|
||||
|
||||
def core_reset_enter(self, core_mask):
|
||||
# Set Reset Bit for cores
|
||||
logging.debug("Enter core reset(mask=0x%08X)" % core_mask)
|
||||
|
||||
reset = core_mask << regs_def.ADSP_GR_ADSPCS_CRST_OFFSET
|
||||
self._update_bits(self.dsp_ctl_sts, reset, reset)
|
||||
|
||||
# Check core entered reset
|
||||
reg = self.dsp_ctl_sts.value
|
||||
if (reg & reset) != reset:
|
||||
raise RuntimeError("Reset enter failed: DSP_CTL_STS=%s core_maks=0x%08X"
|
||||
% (self.dsp_ctl_sts, core_mask))
|
||||
logging.debug(" DSP_CTL_STS=%s" % self.dsp_ctl_sts)
|
||||
|
||||
def core_reset_leave(self, core_mask):
|
||||
# Set Reset Bit for cores
|
||||
logging.debug("Leave core reset(mask=0x%08X)" % core_mask)
|
||||
|
||||
leave = core_mask << regs_def.ADSP_GR_ADSPCS_CRST_OFFSET
|
||||
self._update_bits(self.dsp_ctl_sts, leave, 0)
|
||||
|
||||
# Check core entered reset
|
||||
reg = self.dsp_ctl_sts.value
|
||||
if (reg & leave) != 0:
|
||||
raise RuntimeError("Reset leave failed: DSP_CTL_STS=%s core_maks=0x%08X"
|
||||
% (self.dsp_ctl_sts, core_mask))
|
||||
logging.debug(" DSP_CTL_STS=%s" % self.dsp_ctl_sts)
|
||||
|
||||
def core_stall_reset(self, core_mask):
|
||||
logging.debug("Stall core(mask=0x%08X)" % core_mask)
|
||||
stall = core_mask << regs_def.ADSP_GR_ADSPCS_CSTALL_OFFSET
|
||||
self._update_bits(self.dsp_ctl_sts, stall, stall)
|
||||
logging.debug(" DSP_CTL_STS=%s" % self.dsp_ctl_sts)
|
||||
self.core_reset_enter(core_mask)
|
||||
|
||||
def core_run(self, core_mask):
|
||||
self.core_reset_leave(core_mask)
|
||||
|
||||
logging.debug("Run/Unstall core(mask=0x%08X)" % core_mask)
|
||||
run = core_mask << regs_def.ADSP_GR_ADSPCS_CSTALL_OFFSET
|
||||
self._update_bits(self.dsp_ctl_sts, run, 0)
|
||||
logging.debug(" DSP_CTL_STS=%s" % self.dsp_ctl_sts)
|
||||
|
||||
def core_power_down(self, core_mask):
|
||||
logging.debug("Power down core(mask=0x%08X)" % core_mask)
|
||||
mask = core_mask << regs_def.ADSP_GR_ADSPCS_SPA_OFFSET
|
||||
self._update_bits(self.dsp_ctl_sts, mask, 0)
|
||||
|
||||
cnt = 0
|
||||
while cnt < 10:
|
||||
cpa = self.dsp_ctl_sts.value & regs_def.ADSP_GR_ADSPCS_CPA
|
||||
mask = (core_mask & 0) << regs_def.ADSP_GR_ADSPCS_CPA_OFFSET
|
||||
if cpa == mask:
|
||||
logging.debug("Confirmed match value: 0x%04X" % cpa)
|
||||
break
|
||||
time.sleep(0.01)
|
||||
cnt += 1
|
||||
|
||||
if cnt == 10:
|
||||
logging.error(" DSP_CTL_STS=%s" % self.dsp_ctl_sts)
|
||||
raise RuntimeError("Failed to power down the core")
|
||||
logging.debug(" DSP_CTL_STS=%s" % self.dsp_ctl_sts)
|
||||
|
||||
def core_power_up(self, core_mask):
|
||||
logging.debug("Power Up core(mask=0x%08X)" % core_mask)
|
||||
mask = core_mask << regs_def.ADSP_GR_ADSPCS_SPA_OFFSET
|
||||
self._update_bits(self.dsp_ctl_sts, mask, mask)
|
||||
|
||||
cnt = 0
|
||||
while cnt < 10:
|
||||
cpa = self.dsp_ctl_sts.value & regs_def.ADSP_GR_ADSPCS_CPA
|
||||
mask = core_mask << regs_def.ADSP_GR_ADSPCS_CPA_OFFSET
|
||||
|
||||
if cpa == mask:
|
||||
logging.debug("Confirmed match value: 0x%04X" % cpa)
|
||||
break
|
||||
time.sleep(0.01)
|
||||
cnt += 1
|
||||
|
||||
if cnt == 10:
|
||||
logging.error(" DSP_CTL_STS=%s" % self.dsp_ctl_sts)
|
||||
raise RuntimeError("Failed to power up the core")
|
||||
|
||||
logging.debug(" DSP_CTL_STS=%s" % self.dsp_ctl_sts)
|
||||
|
||||
@staticmethod
|
||||
def _update_bits(reg, mask, value):
|
||||
|
||||
old_val = reg.value
|
||||
new_val = (old_val & ~mask) | (value & mask)
|
||||
|
||||
if old_val == new_val:
|
||||
return False
|
||||
|
||||
reg.value = new_val
|
||||
return True
|
|
@ -1,241 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import os
|
||||
import fcntl
|
||||
import struct
|
||||
import mmap
|
||||
import logging
|
||||
|
||||
from ctypes import cast, POINTER, c_uint8, c_uint32, c_uint16, c_uint64,\
|
||||
addressof, byref
|
||||
|
||||
# diag_driver file
|
||||
DIAG_DRV_PATH = "/dev/hda"
|
||||
|
||||
# Diag Driver Definition - sof-diagnostic-driver/ioctl.h
|
||||
|
||||
# IOCTL definition
|
||||
CMD_OPEN_DEVICE = 0x47
|
||||
CMD_ALLOC_MEMORY = 0x3A
|
||||
CMD_FREE_MEMORY = 0x3B
|
||||
|
||||
CMD_OPEN_DEVICE_LEN = 40
|
||||
|
||||
|
||||
class HdaBar:
|
||||
""" Data structure for HDA BAR information """
|
||||
|
||||
def __init__(self, raw):
|
||||
self.base_p = 0
|
||||
self.base_v = 0
|
||||
self.size = 0
|
||||
(self.base_p, self.base_v, self.size) = struct.unpack('=QQL', raw)
|
||||
|
||||
def __str__(self):
|
||||
return " Base Physical Address: 0x%08X\n" \
|
||||
" Base Virtual Address: 0x%08X\n" \
|
||||
" Base Size: 0x%08X" \
|
||||
% (self.base_p, self.base_v, self.size)
|
||||
|
||||
|
||||
class HdaMemory:
|
||||
""" Data structure for HDA memory allocation """
|
||||
|
||||
def __init__(self, size=0):
|
||||
self.dma_addr_p = 0
|
||||
self.dma_addr_v = 0
|
||||
self.size = size
|
||||
self.memmap = None
|
||||
|
||||
def set_value(self, raw):
|
||||
(self.dma_addr_p,
|
||||
self.dma_addr_v,
|
||||
self.size) = struct.unpack('=QQL', raw)
|
||||
|
||||
def get_value(self):
|
||||
data = bytearray(struct.pack('=QQL', self.dma_addr_p,
|
||||
self.dma_addr_v,
|
||||
self.size))
|
||||
return data
|
||||
|
||||
def __str__(self):
|
||||
return " DMA Physical Address: 0x%08X\n" \
|
||||
" DMA Virtual Address: 0x%08X\n" \
|
||||
" DMA Size: 0x%08X" \
|
||||
% (self.dma_addr_p, self.dma_addr_v, self.size)
|
||||
|
||||
|
||||
class HdaHandle:
|
||||
""" Data structure for HDA handles """
|
||||
|
||||
def __init__(self, raw):
|
||||
|
||||
data = struct.unpack('20s20s', raw)
|
||||
self.hda_bar = HdaBar(data[0])
|
||||
self.dsp_bar = HdaBar(data[1])
|
||||
|
||||
def __str__(self):
|
||||
output = (
|
||||
"HDA BAR:\n"
|
||||
"{hda}\n"
|
||||
"DSP BAR:\n"
|
||||
"{dsp}"
|
||||
).format(
|
||||
hda = self.hda_bar, dsp = self.dsp_bar
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
class DiagDriver:
|
||||
""" Interface for diag_driver """
|
||||
|
||||
def __init__(self):
|
||||
self._handle = None
|
||||
self._mem_map_list = []
|
||||
self._buff_list = []
|
||||
|
||||
def open_device(self):
|
||||
"""
|
||||
Send CMD_OPEN_DEVICE and get HDA BAR and DSP BAR
|
||||
|
||||
Returns:
|
||||
(handle)(obj:HdaHandle): HDA and DSP Bars objs
|
||||
"""
|
||||
|
||||
logging.debug(">>> DiagDriver.open_device()")
|
||||
|
||||
# Allocate bytearry for HDABusTest_OpenDevice
|
||||
buf = bytearray(CMD_OPEN_DEVICE_LEN)
|
||||
|
||||
logging.info("Open HDA device: %s" % DIAG_DRV_PATH)
|
||||
# Send CMD_OPEN_DEVICE
|
||||
with open(DIAG_DRV_PATH) as fd:
|
||||
fcntl.ioctl(fd, CMD_OPEN_DEVICE, buf)
|
||||
|
||||
self._handle = HdaHandle(buf)
|
||||
|
||||
logging.debug("<<< DiagDriver.open_device()")
|
||||
|
||||
return self._handle
|
||||
|
||||
def alloc_mem(self, size):
|
||||
"""
|
||||
Send CMD_ALLOC_MEMORY to allocate DMA buffer
|
||||
|
||||
Returns:
|
||||
hda_mem (obj:HDAMemory): Allocated DMA buffer information
|
||||
"""
|
||||
|
||||
logging.debug(">>> Diag_Driver.alloc_mem(size=0x%08X)" % size)
|
||||
|
||||
hda_buf = HdaMemory(size)
|
||||
|
||||
# Allocate bytearray for HDABusTestMem
|
||||
buf = hda_buf.get_value()
|
||||
|
||||
# Send CMD_ALLOC_MEMORY
|
||||
with open(DIAG_DRV_PATH) as fd:
|
||||
fcntl.ioctl(fd, CMD_ALLOC_MEMORY, buf)
|
||||
|
||||
hda_buf.set_value(buf)
|
||||
|
||||
mem = self.mmap(hda_buf.dma_addr_p, hda_buf.size)
|
||||
hda_buf.memmap = mem
|
||||
hda_buf.dma_addr_v = addressof(mem)
|
||||
|
||||
logging.debug("DMA Memory:\n%s" % hda_buf)
|
||||
|
||||
# Append to buffer list for later clean up.
|
||||
self._buff_list.append(hda_buf)
|
||||
|
||||
logging.debug("<<< Diag_Driver.alloc_mem()")
|
||||
|
||||
return hda_buf
|
||||
|
||||
def free_mem(self, hda_buf):
|
||||
"""
|
||||
Send CMD_FREE_MEMORY to free the DMA buffer
|
||||
|
||||
Params:
|
||||
had_mem (obj:HDAMemory): DMA buffer information to be freed
|
||||
|
||||
Returns:
|
||||
0 for success, otherwise fail.
|
||||
"""
|
||||
logging.debug(">>> Diag_Driver.free_mem()")
|
||||
|
||||
if hda_buf not in self._buff_list:
|
||||
logging.error("Cannot find buffer from the list")
|
||||
raise ValueError("Cannot find buffer to free")
|
||||
|
||||
logging.debug("Buffer to Free:\n%s" % hda_buf)
|
||||
|
||||
buf = hda_buf.get_value()
|
||||
|
||||
# Send CMD_FREE_MEMORY
|
||||
with open(DIAG_DRV_PATH) as fd:
|
||||
ret = fcntl.ioctl(fd, CMD_FREE_MEMORY, buf)
|
||||
|
||||
self._buff_list.remove(hda_buf)
|
||||
|
||||
logging.debug("<<< Diag_Driver.free_mem()")
|
||||
return ret
|
||||
|
||||
def mmap(self, addr, length):
|
||||
"""
|
||||
Setup mmap for HDA and DSP from /dev/mem
|
||||
|
||||
Returns:
|
||||
(mem map,..)(uint32_t..): Array of uint32_t in mapped memory
|
||||
"""
|
||||
|
||||
logging.debug(">>> Diag_Driver.mmap(addr=0x%08X, length=0x%08X)"
|
||||
% (addr, length))
|
||||
|
||||
try:
|
||||
fd = os.open(DIAG_DRV_PATH, os.O_RDWR)
|
||||
mem_map = mmap.mmap(fd, length, offset=addr,
|
||||
prot=mmap.PROT_READ | mmap.PROT_WRITE,
|
||||
flags=mmap.MAP_SHARED)
|
||||
|
||||
self._mem_map_list.append(mem_map)
|
||||
|
||||
# Array of uint8
|
||||
mem = (c_uint8 * length).from_buffer(mem_map)
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
logging.debug("<<< Diag_Driver.mmap()")
|
||||
|
||||
return mem
|
||||
|
||||
|
||||
class Register:
|
||||
def __init__(self, base_addr, offset, type=c_uint32):
|
||||
self._type = type
|
||||
self._obj = cast(byref(base_addr, offset), POINTER(type))
|
||||
|
||||
def __str__(self):
|
||||
if self._type == c_uint8:
|
||||
return "0x%02X" % self.value
|
||||
elif self._type == c_uint16:
|
||||
return "0x%04X" % self.value
|
||||
elif self._type == c_uint32:
|
||||
return "0x%08X" % self.value
|
||||
elif self._type == c_uint64:
|
||||
return "0x%08X %08X" % (
|
||||
self.value >> 32,
|
||||
self.value & 0xFFFFFFFF
|
||||
)
|
||||
else:
|
||||
return "0x%08X (unknown type)" % self.value
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._obj.contents.value
|
||||
@value.setter
|
||||
def value(self, value):
|
||||
self._obj[0] = value
|
|
@ -1,71 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import logging
|
||||
from ctypes import c_uint8, addressof
|
||||
|
||||
import lib.platforms as plat_def
|
||||
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from logtool import Loglist
|
||||
|
||||
|
||||
def is_ascii(c):
|
||||
if 32 <= c <= 126:
|
||||
return str(chr(c))
|
||||
else:
|
||||
return "."
|
||||
|
||||
|
||||
class Etrace:
|
||||
def __init__(self, dev, win_id=3, size=0x2000):
|
||||
self.drv = dev.drv
|
||||
self.dsp_base_p = dev.dev_info.dsp_bar.base_p
|
||||
self.win_id = win_id
|
||||
self.size = size
|
||||
|
||||
self.offset = self.get_sram_win_offset(self.win_id)
|
||||
|
||||
# memory map MBOX UPLINK
|
||||
self.mmap = self.drv.mmap(self.dsp_base_p + self.offset, self.size)
|
||||
self.mmap_addr = addressof(self.mmap)
|
||||
|
||||
@staticmethod
|
||||
def get_sram_win_offset(win_id):
|
||||
return plat_def.FW_SRAM + (win_id * 0x20000)
|
||||
|
||||
def hexdump(self):
|
||||
data = (c_uint8 * self.size).from_address(self.mmap_addr)
|
||||
|
||||
i = 1
|
||||
s = ""
|
||||
a = ""
|
||||
offset = 0x00
|
||||
|
||||
for r in data:
|
||||
s = s + ("%02X " % r)
|
||||
a = a + ("%s" % is_ascii(r))
|
||||
offset += 1
|
||||
|
||||
if not i % 16:
|
||||
logging.info("0x%04X: %s %s" % ((offset - 16), s, a))
|
||||
s = ""
|
||||
a = ""
|
||||
|
||||
i += 1
|
||||
|
||||
if s:
|
||||
logging.info("0x%04X: %s %s" % ((offset - 16), s, a))
|
||||
|
||||
def print(self):
|
||||
l = Loglist(self.mmap_addr)
|
||||
l.print()
|
||||
|
||||
def save(self, output_file):
|
||||
data = (c_uint8 * self.size).from_address(self.mmap_addr)
|
||||
with open(output_file, "wb+") as f:
|
||||
f.write(data)
|
|
@ -1,253 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import logging
|
||||
from ctypes import Structure, c_uint64, c_uint32, c_uint16, \
|
||||
c_uint8, addressof, sizeof
|
||||
|
||||
import lib.platforms as plat_def
|
||||
|
||||
# Global Message - Generic
|
||||
IPC_GLB_TYPE_OFFSET = 28
|
||||
IPC_GLB_TYPE_MASK = (0xF << IPC_GLB_TYPE_OFFSET)
|
||||
|
||||
# Command Message
|
||||
IPC_CMD_TYPE_OFFSET = 16
|
||||
IPC_CMD_TYPE_MASK = (0xFFF << IPC_CMD_TYPE_OFFSET)
|
||||
|
||||
# Message Type
|
||||
IPC_FW_READY = 0x07 << IPC_GLB_TYPE_OFFSET
|
||||
|
||||
# Extended data types that can be appended onto end of IpCFwReady message
|
||||
IpcExtData = {
|
||||
0: 'IPC_EXT_DMA_BUFFER',
|
||||
1: 'IPC_EXT_WINDOW'
|
||||
}
|
||||
|
||||
# Extended Firmware Data
|
||||
IpcRegion = {
|
||||
0: 'IPC_REGION_DOWNBOX',
|
||||
1: 'IPC_REGION_UPBOX',
|
||||
2: 'IPC_REGION_TRACE',
|
||||
3: 'IPC_REGION_DEBUG',
|
||||
4: 'IPC_REGION_STREAM',
|
||||
5: 'IPC_REGION_REGS',
|
||||
6: 'IPC_REGION_EXCEPTION'
|
||||
}
|
||||
|
||||
|
||||
class IpcHdr(Structure):
|
||||
""" Data structure for IPC Header """
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("size", c_uint32)
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
output = ("Size: 0x%08X" % self.size)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
class IpcCmdHdr(Structure):
|
||||
""" Data structure for IPC Command Header """
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("size", c_uint32),
|
||||
("cmd", c_uint32)
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
output = (
|
||||
"IPC Command Hdr:\n"
|
||||
" Command: {cmd:>10} (0x{cmd:0>8X})\n"
|
||||
" Size: {size:>10} (0x{size:0>4X})"
|
||||
).format(
|
||||
size = self.size,
|
||||
cmd = self.cmd
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
class IpcFwVersion(Structure):
|
||||
""" Data structure for IPC FwVersion message """
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("hdr", IpcHdr),
|
||||
("major", c_uint16),
|
||||
("minor", c_uint16),
|
||||
("micro", c_uint16),
|
||||
("build", c_uint16),
|
||||
("date", c_uint8 * 12),
|
||||
("time", c_uint8 * 10),
|
||||
("tag", c_uint8 * 6),
|
||||
("abi_version", c_uint32),
|
||||
("reserved", c_uint32 * 4)
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
output = (
|
||||
"Firmware Version:\n"
|
||||
" Major version: {major: >5} (0x{major:0>4X})\n"
|
||||
" Minor version: {minor: >5} (0x{minor:0>4X})\n"
|
||||
" Micro number: {micro: >5} (0x{micro:0>4X})\n"
|
||||
" Build number: {build: >5} (0x{build:0>4X})\n"
|
||||
" Date: {date: >24}\n"
|
||||
" Time: {time: >24}\n"
|
||||
" Tag: {tag: >24}\n"
|
||||
" Abi version: {abi_version: >5} (0x{abi_version:0>4X})"
|
||||
).format(
|
||||
major = self.major,
|
||||
minor = self.minor,
|
||||
micro = self.micro,
|
||||
build = self.build,
|
||||
date=''.join([chr(i) for i in list(self.date)]),
|
||||
time=''.join([chr(i) for i in list(self.time)]),
|
||||
tag=''.join([chr(i) for i in list(self.tag)]),
|
||||
abi_version = self.abi_version)
|
||||
return output
|
||||
|
||||
|
||||
class IpcFwReady(Structure):
|
||||
""" Data structure for IpcFwReady message """
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("hdr", IpcCmdHdr),
|
||||
("dspbox_offset", c_uint32),
|
||||
("hostbox_offset", c_uint32),
|
||||
("dspbox_size", c_uint32),
|
||||
("hostbox_size", c_uint32),
|
||||
("version", IpcFwVersion),
|
||||
("flags", c_uint64),
|
||||
("reserved", c_uint32 * 4)
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
output = (
|
||||
"IPC Firmware Ready Message: (0x{cmd:0>8X}) (0x{size:0>8X})\n"
|
||||
" DSP box offset: {dsp_offset: >5} (0x{dsp_offset:0>4X})\n"
|
||||
" Host box offset:{host_offset: >5} (0x{host_offset:0>4X})\n"
|
||||
" DSP box size: {dsp_size: >5} (0x{dsp_size:0>4X})\n"
|
||||
" Host box size: {host_size: >5} (0x{host_size:0>4X})\n\n"
|
||||
"{version}\n\n"
|
||||
"Flags:"
|
||||
" 0x{flags:0>8X}"
|
||||
).format(
|
||||
cmd = self.hdr.cmd,
|
||||
size = self.hdr.size,
|
||||
dsp_offset = self.dspbox_offset,
|
||||
host_offset = self.hostbox_offset,
|
||||
dsp_size = self.dspbox_size,
|
||||
host_size = self.hostbox_size,
|
||||
version = str(self.version),
|
||||
flags = self.flags
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
class IpcExtDataHdr(Structure):
|
||||
""" Data structure for IPC extended data header """
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("hdr", IpcCmdHdr),
|
||||
("type", c_uint32)
|
||||
]
|
||||
|
||||
|
||||
class IpcWindowElem(Structure):
|
||||
""" Data structure for Window Element message """
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("hdr", IpcHdr),
|
||||
("type", c_uint32),
|
||||
("id", c_uint32),
|
||||
("flags", c_uint32),
|
||||
("size", c_uint32),
|
||||
("offset", c_uint32)
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
output = (
|
||||
"Window type: {type_str:>20} ({type:d})\n"
|
||||
"Window id: {id: >5}\n"
|
||||
"Window flags: {flags: >5} (0x{flags:0>4X})\n"
|
||||
"Window size: {size: >5} (0x{size:0>4X})\n"
|
||||
"Window offset: {offset: >5} (0x{offset:0>4X})\n"
|
||||
).format(
|
||||
type_str = IpcRegion[self.type],
|
||||
type = self.type,
|
||||
id = self.id,
|
||||
flags = self.flags,
|
||||
size = self.size,
|
||||
offset = self.offset
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
class IpcWindow(Structure):
|
||||
""" Data structure for extended data memory windows """
|
||||
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ext_hdr", IpcExtDataHdr),
|
||||
("num_windows", c_uint32),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
output = ("\n"
|
||||
"IPC Firmware Ready Extended Message: (0x{cmd:0>8X}) (0x{size:0>8X})\n"
|
||||
"Message Type: {ext_type: >5d} ({ext_type_str})\n\n"
|
||||
"Number of Windows: {num_windows: >2d}\n"
|
||||
).format(
|
||||
cmd = self.ext_hdr.hdr.cmd,
|
||||
size = self.ext_hdr.hdr.size,
|
||||
ext_type = self.ext_hdr.type,
|
||||
ext_type_str = IpcExtData[self.ext_hdr.type],
|
||||
num_windows = int(self.num_windows)
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
class Ipc:
|
||||
""" Class for IPC handle """
|
||||
|
||||
def __init__(self, dev):
|
||||
self.drv = dev.drv
|
||||
self.dsp_base_p = dev.dev_info.dsp_bar.base_p
|
||||
|
||||
# memory map MBOX UPLINK
|
||||
self.mmap = self.drv.mmap(self.dsp_base_p + (plat_def.FW_MBOX_UPLINK),
|
||||
plat_def.FW_MBOX_SIZE)
|
||||
self.mmap_addr = addressof(self.mmap)
|
||||
|
||||
def read_fw_ready(self):
|
||||
""" FwReady message consist of two messages:
|
||||
1. FwReady
|
||||
2. ExtendedData
|
||||
"""
|
||||
msg = IpcFwReady.from_address(self.mmap_addr)
|
||||
logging.info(str(msg))
|
||||
self.read_fw_ready_ext()
|
||||
|
||||
def read_fw_ready_ext(self):
|
||||
addr_offset = self.mmap_addr + sizeof(IpcFwReady())
|
||||
msg = IpcWindow.from_address(addr_offset)
|
||||
logging.info(str(msg))
|
||||
|
||||
# Extended Windows data type
|
||||
if msg.ext_hdr.type != 1:
|
||||
raise RuntimeError("Not Implemented: ext_hdr.type != 1")
|
||||
|
||||
win_elem_list = []
|
||||
addr_offset += sizeof(IpcWindow())
|
||||
num_win = int(msg.num_windows)
|
||||
for _ in range(num_win):
|
||||
win_elem = IpcWindowElem.from_address(addr_offset)
|
||||
win_elem_list.append(win_elem)
|
||||
addr_offset += sizeof(IpcWindowElem())
|
||||
|
||||
for elem in win_elem_list:
|
||||
logging.info(str(elem))
|
|
@ -1,202 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import time
|
||||
import logging
|
||||
import array
|
||||
|
||||
from lib.stream_desc import StreamDescList
|
||||
from lib.device import Device
|
||||
from lib.ipc import Ipc
|
||||
import lib.registers as regs_def
|
||||
import lib.platforms as plat_def
|
||||
|
||||
|
||||
class FirmwareStatus():
|
||||
""" Data structure for Firmware Status register """
|
||||
|
||||
def __init__(self, value=None):
|
||||
self.value = None
|
||||
self.boot_state = None
|
||||
self.wait_state = None
|
||||
self.moudle = None
|
||||
self.error = None
|
||||
|
||||
if value:
|
||||
self.set(value)
|
||||
|
||||
def set(self, value):
|
||||
self.value = value
|
||||
self.boot_state = self.value & plat_def.FW_STATUS_BOOT_STATE
|
||||
self.wait_state = ((self.value & plat_def.FW_STATUS_WAIT_STATE)
|
||||
>> plat_def.FW_STATUS_WAIT_STATE_OFFSET)
|
||||
self.moudle = ((self.value & plat_def.FW_STATUS_MODULE)
|
||||
>> plat_def.FW_STATUS_MODULE_OFFSET)
|
||||
self.error = ((self.value & plat_def.FW_STATUS_ERROR)
|
||||
>> plat_def.FW_STATUS_ERROR_OFFSET)
|
||||
|
||||
def __str__(self):
|
||||
return "0x%08X" % self.value
|
||||
|
||||
def print(self):
|
||||
output = ("Firmware Status Register (%s)\n"
|
||||
" Boot: 0x%06X (%s)\n"
|
||||
" Wait: 0x%02X (%s)\n"
|
||||
" Module: 0x%02X\n"
|
||||
" Error: 0x%02X" %
|
||||
(self,
|
||||
self.boot_state, plat_def.BOOT_STATUS_STR(self.boot_state),
|
||||
self.wait_state, plat_def.WAIT_STATUS_STR(self.wait_state),
|
||||
self.moudle, self.error))
|
||||
logging.info(output)
|
||||
|
||||
class FirmwareLoader():
|
||||
|
||||
def __init__(self):
|
||||
self._init_done = False
|
||||
self.dma_id = None
|
||||
self.dev = None
|
||||
self.sdl = None
|
||||
|
||||
def init(self, dma_id):
|
||||
if self._init_done:
|
||||
logging.warning("Already initialized! Skip init")
|
||||
return
|
||||
|
||||
self.dma_id = dma_id
|
||||
self.dev = Device()
|
||||
self.dev.open_device()
|
||||
self.sdl = StreamDescList(self.dev)
|
||||
self.ipc = Ipc(self.dev)
|
||||
self._init_done = True
|
||||
|
||||
def close(self):
|
||||
if not self._init_done:
|
||||
logging.warning("Not initialized! Skip closing.")
|
||||
return
|
||||
|
||||
self.sdl.close()
|
||||
self.dev.close()
|
||||
self._init_done = False
|
||||
|
||||
def reset_dsp(self):
|
||||
logging.debug(">>> FirmwareLoader.reset_dsp()")
|
||||
logging.debug("Recycling controller power...")
|
||||
self.dev.power_cycle()
|
||||
|
||||
# This should be enabled prior to power down the cores.
|
||||
self.dev.enable_proc_pipe_ctl()
|
||||
|
||||
logging.debug("Power down cores...")
|
||||
self.dev.core_stall_reset(plat_def.CORE_MASK)
|
||||
self.dev.core_power_down(plat_def.CORE_MASK)
|
||||
logging.debug("<<< FirmwareLoader.reset_dsp()")
|
||||
|
||||
def boot_dsp(self):
|
||||
logging.debug(">>> FirmwareLoader.boot_dsp()")
|
||||
self.dev.enable_proc_pipe_ctl()
|
||||
self.sdl.reset_all()
|
||||
self.dev.core_power_up(0x1)
|
||||
self.dev.dsp_hipct.value = self.dev.dsp_hipct.value
|
||||
|
||||
logging.debug("Purging pending FW request")
|
||||
boot_config = plat_def.FW_IPC_PURGE | regs_def.ADSP_IPC_HIPCI_BUSY
|
||||
boot_config = boot_config | ((self.dma_id - 7) << 9)
|
||||
self.dev.dsp_hipci.value = boot_config
|
||||
time.sleep(0.1)
|
||||
logging.debug(" DSP_HIPCI=%s" % self.dev.dsp_hipci)
|
||||
|
||||
self.dev.core_power_up(plat_def.CORE_MASK)
|
||||
self.dev.core_run(plat_def.CORE_0)
|
||||
self.dev.core_run(plat_def.CORE_1)
|
||||
logging.debug("Wait for IPC DONE bit from ROM")
|
||||
while True:
|
||||
ipc_ack = self.dev.dsp_hipcie.value
|
||||
if (ipc_ack & (1 << regs_def.ADSP_IPC_HIPCIE_DONE_OFFSET)) != 0:
|
||||
break
|
||||
time.sleep(0.1)
|
||||
logging.debug("<<< FirmwareLoader.boot_dsp()")
|
||||
|
||||
def check_fw_boot_status(self, expected):
|
||||
logging.debug(">>> FirmwareLoader.check_fw_boot_status(0x%08X)" % expected)
|
||||
raw_status = self.dev.fw_status.value
|
||||
FirmwareStatus(raw_status).print()
|
||||
|
||||
if (raw_status & plat_def.FW_STATUS_ERROR) != 0:
|
||||
output = ("Firmware Status error:"
|
||||
" Status: 0x%08X\n"
|
||||
" Error Code 0x%08X" %
|
||||
(raw_status, self.dev.fw_err_code.value))
|
||||
raise RuntimeError(output)
|
||||
status = raw_status & plat_def.FW_STATUS_BOOT_STATE
|
||||
logging.debug("<<< FirmwareLoader.check_fw_boot_status()")
|
||||
return status == expected
|
||||
|
||||
def wait_for_fw_boot_status(self, boot_status):
|
||||
logging.debug("Waiting for FW Boot Status: 0x%08X (%s)"
|
||||
% (boot_status,
|
||||
plat_def.BOOT_STATUS_STR(boot_status)))
|
||||
|
||||
for _ in range(10):
|
||||
reg = self.dev.fw_status.value
|
||||
bs = reg & plat_def.FW_STATUS_BOOT_STATE
|
||||
if bs == boot_status:
|
||||
logging.debug("Received Expected Boot Status")
|
||||
return True
|
||||
time.sleep(0.01)
|
||||
logging.error("Failed to receive expected status")
|
||||
return False
|
||||
|
||||
def wait_for_fw_wait_status(self, wait_status):
|
||||
logging.debug("Waiting for FW Wait Status: 0x%08X (%s)"
|
||||
% (wait_status,
|
||||
plat_def.WAIT_STATUS_STR(wait_status)))
|
||||
for _ in range(10):
|
||||
reg = self.dev.fw_status.value
|
||||
ws = reg & plat_def.FW_STATUS_WAIT_STATE
|
||||
if ws == (wait_status << plat_def.FW_STATUS_WAIT_STATE_OFFSET):
|
||||
logging.debug("Received Expected Wait Status")
|
||||
return True
|
||||
time.sleep(0.01)
|
||||
logging.error("Failed to receive expected status")
|
||||
return False
|
||||
|
||||
def load_firmware(self, fw_file):
|
||||
logging.debug(">>> FirmwareLoader.load_firmware()")
|
||||
with open(fw_file, "rb") as fd:
|
||||
data = array.array('B', fd.read())
|
||||
sd = self.sdl.get_sd(self.dma_id)
|
||||
sd.enable = True
|
||||
sd.alloc_memory(len(data))
|
||||
sd.buf.copy(data, len(data))
|
||||
sd.config()
|
||||
sd.set_stream_id(1)
|
||||
sd.set_traffic_priority(1)
|
||||
sd.set_bitrate(0x4)
|
||||
time.sleep(0.1)
|
||||
logging.debug("<<< FirmwareLoader.load_firmware()")
|
||||
return sd
|
||||
|
||||
def download_firmware(self, fw_file):
|
||||
logging.debug(">>> FirmwareLoader.download_firmware(fw_file=%s)" % fw_file)
|
||||
|
||||
# Load firmware to DMA buffer and update SD and SDL
|
||||
sd = self.load_firmware(fw_file)
|
||||
try:
|
||||
self.dev.hda_spibe.value |= (1 << self.dma_id)
|
||||
self.wait_for_fw_wait_status(plat_def.WAIT_STATUS_DMA_BUFFER_FULL)
|
||||
|
||||
logging.info("Start firmware downloading...")
|
||||
sd.start()
|
||||
time.sleep(0.5)
|
||||
self.wait_for_fw_boot_status(plat_def.BOOT_STATUS_FW_ENTERED)
|
||||
finally:
|
||||
sd.pause()
|
||||
sd.reset()
|
||||
self.sdl.release_sd(sd.idx)
|
||||
self.dev.hda_spibe.value = 0
|
||||
|
||||
logging.debug("<<< FirmwareLoader.download_firmware()")
|
|
@ -1,56 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from ctypes import string_at
|
||||
|
||||
MAGIC = 0x55aa
|
||||
SLOT_LEN = 64
|
||||
SLOT_NUM = int(8192 / SLOT_LEN)
|
||||
|
||||
def read_bytes(buffer):
|
||||
return int.from_bytes(buffer, byteorder='little')
|
||||
|
||||
class Loglist:
|
||||
"""Loglist class"""
|
||||
|
||||
def __init__(self, argument, debug=False):
|
||||
"""Constructor for the loglist takes argument filename or buffer"""
|
||||
|
||||
if isinstance(argument, str):
|
||||
f = open(argument, "rb")
|
||||
self.buffer = f.read(SLOT_NUM * SLOT_LEN)
|
||||
elif isinstance(argument, int):
|
||||
self.buffer = string_at(argument, SLOT_NUM * SLOT_LEN)
|
||||
else:
|
||||
return
|
||||
|
||||
self.loglist = []
|
||||
self.parse()
|
||||
self.debug = debug
|
||||
|
||||
def parse_slot(self, slot):
|
||||
magic = read_bytes(slot[0:2])
|
||||
|
||||
if magic == MAGIC:
|
||||
# Sequence number starting from 1, see
|
||||
# soc/xtensa/intel_adsp/common/trace_out.c
|
||||
id_num = read_bytes(slot[2:4])
|
||||
before_first_zero = slot[4:].split(b'\x00')[0]
|
||||
logstr = before_first_zero.decode(errors='replace')
|
||||
self.loglist.append((id_num, logstr))
|
||||
|
||||
def parse(self):
|
||||
for x in range(0, SLOT_NUM):
|
||||
slot = self.buffer[x * SLOT_LEN : (x + 1) * SLOT_LEN]
|
||||
self.parse_slot(slot)
|
||||
|
||||
def print(self):
|
||||
for pair in sorted(self.loglist):
|
||||
if self.debug:
|
||||
# Add slot number when debug is enabled
|
||||
print('{{[{}] : {}}}; '.format(*pair), end='')
|
||||
else:
|
||||
print('{}'.format(pair[1]), end='')
|
|
@ -1,92 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
from enum import Enum
|
||||
|
||||
# BXT
|
||||
|
||||
# CORE ID MASK
|
||||
CORE_0 = 0x1
|
||||
CORE_1 = 0x2
|
||||
CORE_MASK = 0x3
|
||||
|
||||
# Number of Input Streams Supported (GCAP[11:8])
|
||||
NUM_ISS = 6
|
||||
# Number of Output Streams Supported (GCAP[15:12])
|
||||
NUM_OSS = 7
|
||||
# Total Number of Streams supported
|
||||
NUM_STREAMS = NUM_ISS + NUM_OSS
|
||||
|
||||
# DMA Index for FW download
|
||||
DMA_ID = 7
|
||||
|
||||
# DMA Page Size
|
||||
DMA_PAGE_SIZE = 0x1000
|
||||
|
||||
# FW Registers in SRAM
|
||||
FW_SRAM = 0x80000
|
||||
FW_REGS = FW_SRAM + 0x00
|
||||
FW_MBOX_UPLINK = FW_SRAM + 0x1000
|
||||
FW_MBOX_DWLINK = FW_SRAM + 0x20000
|
||||
FW_MBOX_SIZE = 0x1000
|
||||
|
||||
# FW Status Register
|
||||
FW_STATUS = FW_REGS + 0x0000
|
||||
FW_STATUS_BOOT_STATE = 0x00FFFFFF
|
||||
FW_STATUS_BOOT_STATE_OFFSET = 0
|
||||
FW_STATUS_WAIT_STATE = 0x0F000000
|
||||
FW_STATUS_WAIT_STATE_OFFSET = 24
|
||||
FW_STATUS_MODULE = 0x70000000
|
||||
FW_STATUS_MODULE_OFFSET = 28
|
||||
FW_STATUS_ERROR = 0x80000000
|
||||
FW_STATUS_ERROR_OFFSET = 31
|
||||
|
||||
|
||||
class BOOT_STATUS(Enum):
|
||||
INIT = 0
|
||||
INIT_DONE = 1
|
||||
FW_ENTERED = 5
|
||||
|
||||
|
||||
def BOOT_STATUS_STR(status):
|
||||
try:
|
||||
e = BOOT_STATUS(status)
|
||||
except Exception:
|
||||
return "UNKNOWN"
|
||||
|
||||
return e.name
|
||||
|
||||
|
||||
# Boot Status
|
||||
BOOT_STATUS_INIT = 0x00
|
||||
BOOT_STATUS_INIT_DONE = 0x01
|
||||
BOOT_STATUS_FW_ENTERED = 0x05
|
||||
|
||||
|
||||
class WAIT_STATUS(Enum):
|
||||
DMA_BUFFER_FULL = 5
|
||||
|
||||
|
||||
def WAIT_STATUS_STR(status):
|
||||
try:
|
||||
e = WAIT_STATUS(status)
|
||||
except Exception:
|
||||
return "UNKNOWN"
|
||||
|
||||
return e.name
|
||||
|
||||
|
||||
# Wait Status
|
||||
WAIT_STATUS_DMA_BUFFER_FULL = 0x05
|
||||
|
||||
# FW Error Status
|
||||
FW_ERR_CODE = FW_SRAM + 0x0004
|
||||
|
||||
# IPC Purge FW message
|
||||
FW_IPC_PURGE = 0x01004000
|
||||
|
||||
# IPC GLOBAL LENGTH register
|
||||
IPC_GLOBAL_LEN = 0x00
|
||||
IPC_GLOBAL_CMD = 0x04
|
|
@ -1,150 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Registers
|
||||
|
||||
######################################
|
||||
# High Definition Audio Memory Space #
|
||||
######################################
|
||||
|
||||
# HDA Register Blocks
|
||||
HDA_GR_BASE = 0x0000 # HDA Global Register Block
|
||||
HDA_SD_BASE = 0x0080 # HDA Stream Descriptor Register Block - index 0
|
||||
HDA_SPBF_BASE = 0x0700 # HDA Software Position Based FIFO Capability Structure
|
||||
HDA_PPC_BASE = 0x0800 # HDA Processing Pipe Capabilities Structure
|
||||
|
||||
# Global Capabilities
|
||||
HDA_GR_GCAP = HDA_GR_BASE + 0x0000
|
||||
HDA_GR_GCAP_ISS = 0x0F00 # Number of Input Streams Supported
|
||||
HDA_GR_GCAP_ISS_OFFSET = 8 # Number of Input Streams Supported Offset
|
||||
HDA_GR_GCAP_OSS = 0xF000 # Number of Output Streams Supported
|
||||
HDA_GR_GCAP_OSS_OFFSET = 12 # Number of Offset Streams Supported Offset
|
||||
|
||||
# Golbal Control
|
||||
HDA_GR_GCTL = HDA_GR_BASE + 0x0008
|
||||
|
||||
# Stream Descriptor X Control/Status - only within the blcok
|
||||
HDA_SD_CS = 0x0000
|
||||
HDA_SD_CS_SRST = 0x000001 # Stream Reset
|
||||
HDA_SD_CS_SRST_OFFSET = 0 # Stream Reset Offset
|
||||
HDA_SD_CS_RUN = 0x000002 # Stream Run
|
||||
HDA_SD_CS_RUN_OFFSET = 1 # Stream Run Offset
|
||||
HDA_SD_CS_TP = 0x040000 # Traffic Priority
|
||||
HDA_SD_CS_TP_OFFSET = 18 # Traffic Priority Offset
|
||||
HDA_SD_CS_STRM = 0xF00000 # Stream Number
|
||||
HDA_SD_CS_STRM_OFFSET = 20 # Stream Number Offset
|
||||
|
||||
# Stream Descriptor X Link Position in Buffer
|
||||
HDA_SD_LPIB = 0x0004
|
||||
|
||||
# Stream Descriptor X Cyclic Buffer Length
|
||||
HDA_SD_CBL = 0x0008
|
||||
|
||||
# Stream Descriptor X Last Valid Index
|
||||
HDA_SD_LVI = 0x000C
|
||||
|
||||
# Stream Descriptor X FIFO Eviction Watermark
|
||||
HDA_SD_FIFOW = 0x000E
|
||||
|
||||
# Stream Descriptor X FIFO Size
|
||||
HDA_SD_FIFOS = 0x0010
|
||||
|
||||
# Stream Descriptor X Format
|
||||
HDA_SD_FMT = 0x0012
|
||||
HDA_SD_FMT_BITS = 0x00F0 # Bit Rate
|
||||
HDA_SD_FMT_BITS_OFFSET = 4 # Bit Rate Offset
|
||||
|
||||
# Stream Descriptor X FIFO Limit
|
||||
HDA_SD_FIFOL = 0x0014
|
||||
|
||||
# Stream Descriptor X Buffer Descriptor List Pointer Lower Base Address
|
||||
HDA_SD_BDLPLBA = 0x0018
|
||||
|
||||
# Stream Descriptor X Buffer Descriptor List Pointer Upper Base Address
|
||||
HDA_SD_BDLPUBA = 0x001C
|
||||
|
||||
# Stream Descriptor Size
|
||||
HDA_SD_SIZE = 0x20
|
||||
|
||||
|
||||
# Software Position Based FIFO Capability Control
|
||||
HDA_SPBF_SPBFCTL = HDA_SPBF_BASE + 0x0004
|
||||
HDA_SPBF_SPBFCTL_SPIBE = 0xFFFFFFFF # Software Position in Buffer Enable
|
||||
HDA_SPBF_SPBFCTL_SPIBE_OFFSET = 0 # Software Position in Buffer Enable Offset
|
||||
|
||||
# Stream Descriptor X Software Position in Buffer
|
||||
HDA_SPBF_SD_BASE = HDA_SPBF_BASE + 0x0008
|
||||
HDA_SPBF_SDSPIB = 0x00
|
||||
|
||||
# Stream Descriptor X Max FIFO Size
|
||||
HDA_SPBF_SDMAXFIFOS = 0x04
|
||||
|
||||
# Software Position Based FIFO Stream Descritpro Size
|
||||
HDA_SPBF_SD_SIZE = 0x08
|
||||
|
||||
# Processing Pipe Control
|
||||
HDA_PPC_PPCTL = HDA_PPC_BASE + 0x0004
|
||||
HDA_PPC_PPCTL_PROCEN = 0x3FFFFFFF # Processing Enable
|
||||
HDA_PPC_PPCTL_PROCEN_OFFSET = 0 # Processing Enable Offset
|
||||
HDA_PPC_PPCTL_GPROCEN = 0x40000000 # Global Processing Enable
|
||||
HDA_PPC_PPCTL_GPROCEN_OFFSET = 30 # Global Processing Enable Offset
|
||||
|
||||
# ADSP Register Blocks
|
||||
ADSP_GR_BASE = 0x0000 # ADSP General DSP Registers
|
||||
ADSP_IPC_BASE = 0x0040 # ADSP IPC Register
|
||||
|
||||
# ADSP Control & Status
|
||||
ADSP_GR_ADSPCS = ADSP_GR_BASE + 0x0004
|
||||
ADSP_GR_ADSPCS_CRST = 0x000000FF # Core Reset
|
||||
ADSP_GR_ADSPCS_CRST_OFFSET = 0 # Core Reset Offset
|
||||
ADSP_GR_ADSPCS_CSTALL = 0x0000FF00 # Core Run#/Stall
|
||||
ADSP_GR_ADSPCS_CSTALL_OFFSET = 8 # Core Run#/Stall Offset
|
||||
ADSP_GR_ADSPCS_SPA = 0x00FF0000 # Set Power Active
|
||||
ADSP_GR_ADSPCS_SPA_OFFSET = 16 # Set Power Active Offset
|
||||
ADSP_GR_ADSPCS_CPA = 0xFF000000 # Current Power Active
|
||||
ADSP_GR_ADSPCS_CPA_OFFSET = 24 # Current Power Active Offset
|
||||
|
||||
# ADSP Interrupt Control
|
||||
ADSP_GR_ADSPIC = ADSP_GR_BASE + 0x0008
|
||||
ADSP_GR_ADSPIC_IPC = 0x00000001 # IPC Interrupt
|
||||
ADSP_GR_ADSPIC_IPC_OFFSET = 0 # IPC Interrupt Offset
|
||||
ADSP_GR_ADSPIC_CLDMA = 0x00000002 # Code Loader DMA Interrupt
|
||||
ADSP_GR_ADSPIC_CLDMA_OFFSET = 1 # Code Loader DMA Interrupt Offset
|
||||
|
||||
# ADSP IPC DSP to Host
|
||||
ADSP_IPC_HIPCT = ADSP_IPC_BASE + 0x0000
|
||||
ADSP_IPC_HIPCT_BUSY = 0x80000000 # Busy
|
||||
ADSP_IPC_HIPCT_BUSY_OFFSET = 31 # Busy Offset
|
||||
ADSP_IPC_HIPCT_MSG = 0x7FFFFFFF # Message
|
||||
ADSP_IPC_HIPCT_MSG_OFFSET = 0 # Message Offset
|
||||
|
||||
# ADSP IPC DSP to Host Extension
|
||||
ADSP_IPC_HIPCTE = ADSP_IPC_BASE + 0x0004
|
||||
ADSP_IPC_HIPCTE_MSGEXT = 0x3FFFFFFF # Message Extension
|
||||
ADSP_IPC_HIPCTE_MSGEXT_OFFSET = 0 # Message Extension Offset
|
||||
|
||||
# ADSP IPC Host to DSP
|
||||
ADSP_IPC_HIPCI = ADSP_IPC_BASE + 0x0008
|
||||
ADSP_IPC_HIPCI_BUSY = 0x80000000 # Busy
|
||||
ADSP_IPC_HIPCI_BUSY_OFFSET = 31 # Busy Offset
|
||||
ADSP_IPC_HIPCI_MSG = 0x7FFFFFFF # Message
|
||||
ADSP_IPC_HIPCI_MSG_OFFSET = 0 # Message Offset
|
||||
|
||||
# ADSP IPC Host to DSP Extension
|
||||
ADSP_IPC_HIPCIE = ADSP_IPC_BASE + 0x000C
|
||||
ADSP_IPC_HIPCIE_ERR = 0x80000000 # Error
|
||||
ADSP_IPC_HIPCIE_ERR_OFFSET = 31 # Error Offset
|
||||
ADSP_IPC_HIPCIE_DONE = 0x40000000 # Done
|
||||
ADSP_IPC_HIPCIE_DONE_OFFSET = 30 # Done Offset
|
||||
ADSP_IPC_HIPCIE_MSGEXT = 0x3FFFFFFF # Message Extension
|
||||
ADSP_IPC_HIPCIE_MSGEXT_OFFSET = 0 # Message Extension Offset
|
||||
|
||||
# ADSP IPC Control
|
||||
ADSP_IPC_HIPCCTL = ADSP_IPC_BASE + 0x0010
|
||||
ADSP_IPC_HIPCCTL_IPCTBIE = 0x00000001 # IPC Target Busy Interrupt Enable
|
||||
ADSP_IPC_HIPCCTL_IPCTBIE_OFFSET = 0 # IPC Target Busy Interrupt Enable Offset
|
||||
ADSP_IPC_HIPCCTL_IPCIDIE = 0x00000002 # IPC Initiator Done Interrupt Enable
|
||||
ADSP_IPC_HIPCCTL_IPCIDIE_OFFSET = 1 # IPC Initiator Done Interrupt Enable Offset
|
|
@ -1,228 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import math
|
||||
import logging
|
||||
from time import sleep
|
||||
from ctypes import c_uint16, POINTER, cast, c_uint8, c_uint64
|
||||
|
||||
from lib.driver import Register
|
||||
import lib.registers as regs_def
|
||||
import lib.platforms as plat_def
|
||||
|
||||
|
||||
class DmaBuf:
|
||||
""" Class for DMA buffer """
|
||||
|
||||
def __init__(self, drv, size):
|
||||
self.drv = drv
|
||||
self.size = size
|
||||
|
||||
# Allocated DMA buffer should be a multiplication of page size
|
||||
self.page_count = math.ceil(self.size / plat_def.DMA_PAGE_SIZE)
|
||||
logging.debug("Page Count: %d" % self.page_count)
|
||||
|
||||
self.alloc_size = self.page_count * plat_def.DMA_PAGE_SIZE
|
||||
logging.debug("Allocate DMA Buffer: size=0x%08X alloc_size=0x%08X"
|
||||
% (self.size, self.alloc_size))
|
||||
self.mem = self.drv.alloc_mem(self.alloc_size)
|
||||
self.addr_p = self.mem.dma_addr_p
|
||||
self.buf = cast(self.mem.dma_addr_v,
|
||||
POINTER(c_uint8 * self.alloc_size)).contents
|
||||
|
||||
def copy(self, data, size):
|
||||
""" Copying data to allocated DMA buffer """
|
||||
if size > self.alloc_size:
|
||||
raise ValueError("Not enough buffer. allocated: %d requested: %d"
|
||||
% (self.alloc_size, size))
|
||||
logging.debug("Copying Data to DMA buffer")
|
||||
self.buf[:size] = data[:size]
|
||||
|
||||
def free(self):
|
||||
if self.mem:
|
||||
self.drv.free_mem(self.mem)
|
||||
self.mem = None
|
||||
|
||||
|
||||
class DmaBufDescList:
|
||||
""" Class DMA Buffer Descriptor List """
|
||||
|
||||
def __init__(self, drv, fw_buf):
|
||||
self.drv = drv
|
||||
self.bd_count = fw_buf.page_count
|
||||
|
||||
# Single Page for Buffer Descriptor List
|
||||
self.buf = DmaBuf(drv, plat_def.DMA_PAGE_SIZE)
|
||||
|
||||
curr_ptr = 0
|
||||
# Map BDLE with data buffer
|
||||
logging.debug("Update Buffer Descriptor List:")
|
||||
for i in range(self.bd_count):
|
||||
bdle_addr = Register(self.buf.mem.memmap, (i * 16) + 0x00, c_uint64)
|
||||
bdle_len = Register(self.buf.mem.memmap, (i * 16) + 0x08)
|
||||
bdle_ioc = Register(self.buf.mem.memmap, (i * 16) + 0x0C)
|
||||
|
||||
if fw_buf.alloc_size - curr_ptr > plat_def.DMA_PAGE_SIZE:
|
||||
bdle_len.value = plat_def.DMA_PAGE_SIZE
|
||||
bdle_ioc.value = 0
|
||||
bdle_addr.value = fw_buf.addr_p + curr_ptr
|
||||
else:
|
||||
bdle_len.value = fw_buf.alloc_size - curr_ptr
|
||||
bdle_ioc.value = 1
|
||||
bdle_addr.value = fw_buf.addr_p + curr_ptr
|
||||
|
||||
logging.debug(" BDLE#%02d: ADDR: %s LEN: %s IOC: %s"
|
||||
% (i, bdle_addr, bdle_len, bdle_ioc))
|
||||
break
|
||||
curr_ptr += plat_def.DMA_PAGE_SIZE
|
||||
logging.debug(" BDLE#%02d: ADDR: %s LEN: %s IOC: %s"
|
||||
% (i, bdle_addr, bdle_len, bdle_ioc))
|
||||
|
||||
def free(self):
|
||||
if self.buf:
|
||||
self.drv.free_mem(self.buf.mem)
|
||||
self.buf = None
|
||||
|
||||
|
||||
class StreamDesc:
|
||||
""" Class for Stream Descriptor """
|
||||
|
||||
def __init__(self, idx, dev):
|
||||
self.idx = idx
|
||||
self.dev = dev
|
||||
self.used = False
|
||||
self.buf = None
|
||||
self.bdl = None
|
||||
|
||||
offset = regs_def.HDA_SD_BASE + (regs_def.HDA_SD_SIZE * (idx))
|
||||
# Registers in SD
|
||||
self.ctl_sts = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_CS)
|
||||
self.lpib = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_LPIB)
|
||||
self.cbl = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_CBL)
|
||||
self.lvi = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_LVI, c_uint16)
|
||||
self.fifow = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_FIFOW, c_uint16)
|
||||
self.fifos = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_FIFOS, c_uint16)
|
||||
self.fmt = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_FMT, c_uint16)
|
||||
self.fifol = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_FIFOL)
|
||||
self.bdlplba = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_BDLPLBA)
|
||||
self.bdlpuba = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SD_BDLPUBA)
|
||||
|
||||
# Register for SPIB
|
||||
offset = regs_def.HDA_SPBF_SD_BASE + (regs_def.HDA_SPBF_SD_SIZE * (idx))
|
||||
self.sdspib = Register(self.dev.hda_bar_mmap,
|
||||
offset + regs_def.HDA_SPBF_SDSPIB)
|
||||
|
||||
def free_memory(self):
|
||||
if self.buf is not None:
|
||||
self.buf.free()
|
||||
self.buf = None
|
||||
if self.bdl is not None:
|
||||
self.bdl.free()
|
||||
self.bdl = None
|
||||
|
||||
def alloc_memory(self, size):
|
||||
self.free_memory()
|
||||
self.buf = DmaBuf(self.dev.drv, size)
|
||||
self.bdl = DmaBufDescList(self.dev.drv, self.buf)
|
||||
|
||||
def config(self):
|
||||
self.bdlplba.value = self.bdl.buf.addr_p & 0xFFFFFFFF
|
||||
self.bdlpuba.value = self.bdl.buf.addr_p >> 32
|
||||
self.cbl.value = self.buf.size
|
||||
self.lvi.value = self.bdl.bd_count - 1
|
||||
self.sdspib.value = self.cbl.value
|
||||
|
||||
def set_bitrate(self, bit_rate):
|
||||
logging.debug("SD#%02d: Set Bitrate: 0x%04X" % (self.idx, bit_rate))
|
||||
sdfmt = self.fmt.value
|
||||
sdfmt |= (bit_rate << 4)
|
||||
self.fmt.value = sdfmt
|
||||
logging.debug("SD#%02d: SD_FMT=%s" % (self.idx, self.fmt))
|
||||
|
||||
def set_stream_id(self, stream_id):
|
||||
logging.debug("SD#%02d: Set Stream ID: 0x%04X" % (self.idx, stream_id))
|
||||
sd_ctl = self.ctl_sts.value
|
||||
sd_ctl &= ~(0xF << 20)
|
||||
sd_ctl |= (stream_id << 20)
|
||||
self.ctl_sts.value = sd_ctl
|
||||
logging.debug("SD#%02d: SD_CTL_STS=%s" % (self.idx, self.ctl_sts))
|
||||
|
||||
def set_traffic_priority(self, value):
|
||||
logging.debug("SD#%02d: Set Traffic Priority(0x%02X)" % (self.idx, value))
|
||||
sd_ctl = self.ctl_sts.value
|
||||
sd_ctl |= (value << 18)
|
||||
self.ctl_sts.value = sd_ctl
|
||||
logging.debug("SD#%02d: SD_CTL_STS=%s" % (self.idx, self.ctl_sts))
|
||||
|
||||
def start(self):
|
||||
""" Start DMA transfer """
|
||||
logging.debug("SD#%02d: Start DMA stream" % self.idx)
|
||||
self.ctl_sts.value = self.ctl_sts.value | (1 << 1)
|
||||
logging.debug("SD#%02d: SD_CTL_STS=%s" % (self.idx, self.ctl_sts))
|
||||
while self.ctl_sts.value & (1 << 1) == 0:
|
||||
sleep(0.001)
|
||||
|
||||
def pause(self):
|
||||
logging.debug("SD#%02d: Pause DMA stream" % self.idx)
|
||||
self.ctl_sts.value = self.ctl_sts.value & ~(1 << 1)
|
||||
while self.ctl_sts.value & (1 << 1):
|
||||
sleep(0.001)
|
||||
|
||||
def reset(self):
|
||||
logging.debug("SD#%02d: Reset DAM stream" % self.idx)
|
||||
self.pause()
|
||||
self.ctl_sts.value = self.ctl_sts.value | 1
|
||||
sleep(0.01)
|
||||
self.ctl_sts.value = self.ctl_sts.value & ~1
|
||||
sleep(0.01)
|
||||
|
||||
|
||||
class StreamDescList:
|
||||
""" Class for DMA Stream Descriptor List """
|
||||
|
||||
def __init__(self, dev):
|
||||
self.dev = dev
|
||||
self.sdl = []
|
||||
for i in range(plat_def.NUM_STREAMS):
|
||||
sd = StreamDesc(i, self.dev)
|
||||
self.sdl.append(sd)
|
||||
|
||||
def close(self):
|
||||
for sd in self.sdl:
|
||||
if sd.used:
|
||||
self.release(sd)
|
||||
|
||||
def reset_all(self):
|
||||
for sd in self.sdl:
|
||||
sd.reset()
|
||||
|
||||
def get_sd(self, idx):
|
||||
sd = self.sdl[idx]
|
||||
if sd.used:
|
||||
raise ResourceWarning("IOB #%d already in use!" % idx)
|
||||
sd.used = True
|
||||
return sd
|
||||
|
||||
def release(self, sd):
|
||||
return self.release_sd(sd.idx)
|
||||
|
||||
def release_sd(self, idx, reset_hw=True):
|
||||
if not self.sdl[idx].used:
|
||||
logging.warning("SD#%d: Not used!!!" % idx)
|
||||
self.sdl[idx].used = False
|
||||
if reset_hw:
|
||||
self.sdl[idx].pause()
|
||||
self.sdl[idx].reset()
|
||||
self.sdl[idx].free_memory()
|
|
@ -1,53 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""Logging reader tool"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from lib.loglist import Loglist
|
||||
|
||||
QEMU_ETRACE = "/dev/shm/qemu-bridge-hp-sram-mem"
|
||||
SOF_ETRACE = "/sys/kernel/debug/sof/etrace"
|
||||
|
||||
def parse_args():
|
||||
"""Parsing command line arguments"""
|
||||
|
||||
parser = argparse.ArgumentParser(description='Logging tool')
|
||||
|
||||
parser.add_argument('-e', '--etrace', choices=['sof', 'qemu'], default="sof",
|
||||
help="Specify the trace target")
|
||||
|
||||
parser.add_argument('-f', '--file', help="Specify the trace file created by"
|
||||
" dump_trace tool")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
def main():
|
||||
"""Main"""
|
||||
|
||||
args = parse_args()
|
||||
|
||||
if os.geteuid() != 0:
|
||||
sys.exit("Please run this program as root / sudo")
|
||||
|
||||
if args.file is not None:
|
||||
etrace = args.file
|
||||
else:
|
||||
if args.etrace == 'sof':
|
||||
etrace = SOF_ETRACE
|
||||
else:
|
||||
etrace = QEMU_ETRACE
|
||||
|
||||
l = Loglist(etrace)
|
||||
l.print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
main()
|
|
@ -1,66 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from time import sleep
|
||||
from mmap import mmap, ACCESS_COPY
|
||||
from ctypes import c_uint8
|
||||
|
||||
from lib.device import Device
|
||||
import lib.registers as regs
|
||||
|
||||
MBOX = 0x91281000
|
||||
LENGTH = 0x1000
|
||||
|
||||
with open("/dev/mem", "rb") as f:
|
||||
mem_map = mmap(f.fileno(), LENGTH, access=ACCESS_COPY, offset=MBOX)
|
||||
mem = (c_uint8 * LENGTH).from_buffer(mem_map)
|
||||
|
||||
def mailbox_poll_mem(dev):
|
||||
while True:
|
||||
if dev.dsp_hipct.value & regs.ADSP_IPC_HIPCT_BUSY:
|
||||
|
||||
# Use only id for passing character
|
||||
line_len = dev.dsp_hipct.value & regs.ADSP_IPC_HIPCT_MSG
|
||||
|
||||
# Mask out internal bits
|
||||
line_len &= 0x10FFFF
|
||||
|
||||
if line_len:
|
||||
print(bytes(mem[:line_len]).decode())
|
||||
|
||||
# Clear interrupt
|
||||
dev.dsp_hipct.value |= regs.ADSP_IPC_HIPCT_BUSY
|
||||
else:
|
||||
sleep(0.005)
|
||||
|
||||
# Character passed in mailbox ID field
|
||||
def mailbox_poll_char(dev):
|
||||
while True:
|
||||
if dev.dsp_hipct.value & regs.ADSP_IPC_HIPCT_BUSY:
|
||||
|
||||
# Use only id for passing character
|
||||
character = dev.dsp_hipct.value & regs.ADSP_IPC_HIPCT_MSG
|
||||
|
||||
# Get readable character
|
||||
character &= 0x10FFFF
|
||||
|
||||
print('{}'.format(chr(character)), end='')
|
||||
|
||||
# Clear interrupt
|
||||
dev.dsp_hipct.value |= regs.ADSP_IPC_HIPCT_BUSY
|
||||
else:
|
||||
sleep(0.005)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Clear Done if needed
|
||||
#dev.dsp_hipct.value |= regs.ADSP_IPC_HIPCT_BUSY
|
||||
|
||||
# Use Device library for controlling registers
|
||||
device = Device()
|
||||
device.open_device()
|
||||
|
||||
mailbox_poll_mem(device)
|
Loading…
Add table
Add a link
Reference in a new issue