#!/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()")