1#!/usr/bin/env python3 2# 3# Copyright (c) 2019 Intel Corporation 4# 5# SPDX-License-Identifier: Apache-2.0 6 7import time 8import logging 9import array 10 11from lib.stream_desc import StreamDescList 12from lib.device import Device 13from lib.ipc import Ipc 14import lib.registers as regs_def 15import lib.platforms as plat_def 16 17 18class FirmwareStatus(): 19 """ Data structure for Firmware Status register """ 20 21 def __init__(self, value=None): 22 self.value = None 23 self.boot_state = None 24 self.wait_state = None 25 self.moudle = None 26 self.error = None 27 28 if value: 29 self.set(value) 30 31 def set(self, value): 32 self.value = value 33 self.boot_state = self.value & plat_def.FW_STATUS_BOOT_STATE 34 self.wait_state = ((self.value & plat_def.FW_STATUS_WAIT_STATE) 35 >> plat_def.FW_STATUS_WAIT_STATE_OFFSET) 36 self.moudle = ((self.value & plat_def.FW_STATUS_MODULE) 37 >> plat_def.FW_STATUS_MODULE_OFFSET) 38 self.error = ((self.value & plat_def.FW_STATUS_ERROR) 39 >> plat_def.FW_STATUS_ERROR_OFFSET) 40 41 def __str__(self): 42 return "0x%08X" % self.value 43 44 def print(self): 45 output = ("Firmware Status Register (%s)\n" 46 " Boot: 0x%06X (%s)\n" 47 " Wait: 0x%02X (%s)\n" 48 " Module: 0x%02X\n" 49 " Error: 0x%02X" % 50 (self, 51 self.boot_state, plat_def.BOOT_STATUS_STR(self.boot_state), 52 self.wait_state, plat_def.WAIT_STATUS_STR(self.wait_state), 53 self.moudle, self.error)) 54 logging.info(output) 55 56class FirmwareLoader(): 57 58 def __init__(self): 59 self._init_done = False 60 self.dma_id = None 61 self.dev = None 62 self.sdl = None 63 64 def init(self, dma_id): 65 if self._init_done: 66 logging.warning("Already initialized! Skip init") 67 return 68 69 self.dma_id = dma_id 70 self.dev = Device() 71 self.dev.open_device() 72 self.sdl = StreamDescList(self.dev) 73 self.ipc = Ipc(self.dev) 74 self._init_done = True 75 76 def close(self): 77 if not self._init_done: 78 logging.warning("Not initialized! Skip closing.") 79 return 80 81 self.sdl.close() 82 self.dev.close() 83 self._init_done = False 84 85 def reset_dsp(self): 86 logging.debug(">>> FirmwareLoader.reset_dsp()") 87 logging.debug("Recycling controller power...") 88 self.dev.power_cycle() 89 90 # This should be enabled prior to power down the cores. 91 self.dev.enable_proc_pipe_ctl() 92 93 logging.debug("Power down cores...") 94 self.dev.core_stall_reset(plat_def.CORE_MASK) 95 self.dev.core_power_down(plat_def.CORE_MASK) 96 logging.debug("<<< FirmwareLoader.reset_dsp()") 97 98 def boot_dsp(self): 99 logging.debug(">>> FirmwareLoader.boot_dsp()") 100 self.dev.enable_proc_pipe_ctl() 101 self.sdl.reset_all() 102 self.dev.core_power_up(0x1) 103 self.dev.dsp_hipct.value = self.dev.dsp_hipct.value 104 105 logging.debug("Purging pending FW request") 106 boot_config = plat_def.FW_IPC_PURGE | regs_def.ADSP_IPC_HIPCI_BUSY 107 boot_config = boot_config | ((self.dma_id - 7) << 9) 108 self.dev.dsp_hipci.value = boot_config 109 time.sleep(0.1) 110 logging.debug(" DSP_HIPCI=%s" % self.dev.dsp_hipci) 111 112 self.dev.core_power_up(plat_def.CORE_MASK) 113 self.dev.core_run(plat_def.CORE_0) 114 self.dev.core_run(plat_def.CORE_1) 115 logging.debug("Wait for IPC DONE bit from ROM") 116 while True: 117 ipc_ack = self.dev.dsp_hipcie.value 118 if (ipc_ack & (1 << regs_def.ADSP_IPC_HIPCIE_DONE_OFFSET)) != 0: 119 break 120 time.sleep(0.1) 121 logging.debug("<<< FirmwareLoader.boot_dsp()") 122 123 def check_fw_boot_status(self, expected): 124 logging.debug(">>> FirmwareLoader.check_fw_boot_status(0x%08X)" % expected) 125 raw_status = self.dev.fw_status.value 126 FirmwareStatus(raw_status).print() 127 128 if (raw_status & plat_def.FW_STATUS_ERROR) != 0: 129 output = ("Firmware Status error:" 130 " Status: 0x%08X\n" 131 " Error Code 0x%08X" % 132 (raw_status, self.dev.fw_err_code.value)) 133 raise RuntimeError(output) 134 status = raw_status & plat_def.FW_STATUS_BOOT_STATE 135 logging.debug("<<< FirmwareLoader.check_fw_boot_status()") 136 return status == expected 137 138 def wait_for_fw_boot_status(self, boot_status): 139 logging.debug("Waiting for FW Boot Status: 0x%08X (%s)" 140 % (boot_status, 141 plat_def.BOOT_STATUS_STR(boot_status))) 142 143 for _ in range(10): 144 reg = self.dev.fw_status.value 145 bs = reg & plat_def.FW_STATUS_BOOT_STATE 146 if bs == boot_status: 147 logging.debug("Received Expected Boot Status") 148 return True 149 time.sleep(0.01) 150 logging.error("Failed to receive expected status") 151 return False 152 153 def wait_for_fw_wait_status(self, wait_status): 154 logging.debug("Waiting for FW Wait Status: 0x%08X (%s)" 155 % (wait_status, 156 plat_def.WAIT_STATUS_STR(wait_status))) 157 for _ in range(10): 158 reg = self.dev.fw_status.value 159 ws = reg & plat_def.FW_STATUS_WAIT_STATE 160 if ws == (wait_status << plat_def.FW_STATUS_WAIT_STATE_OFFSET): 161 logging.debug("Received Expected Wait Status") 162 return True 163 time.sleep(0.01) 164 logging.error("Failed to receive expected status") 165 return False 166 167 def load_firmware(self, fw_file): 168 logging.debug(">>> FirmwareLoader.load_firmware()") 169 with open(fw_file, "rb") as fd: 170 data = array.array('B', fd.read()) 171 sd = self.sdl.get_sd(self.dma_id) 172 sd.enable = True 173 sd.alloc_memory(len(data)) 174 sd.buf.copy(data, len(data)) 175 sd.config() 176 sd.set_stream_id(1) 177 sd.set_traffic_priority(1) 178 sd.set_bitrate(0x4) 179 time.sleep(0.1) 180 logging.debug("<<< FirmwareLoader.load_firmware()") 181 return sd 182 183 def download_firmware(self, fw_file): 184 logging.debug(">>> FirmwareLoader.download_firmware(fw_file=%s)" % fw_file) 185 186 # Load firmware to DMA buffer and update SD and SDL 187 sd = self.load_firmware(fw_file) 188 try: 189 self.dev.hda_spibe.value |= (1 << self.dma_id) 190 self.wait_for_fw_wait_status(plat_def.WAIT_STATUS_DMA_BUFFER_FULL) 191 192 logging.info("Start firmware downloading...") 193 sd.start() 194 time.sleep(0.5) 195 self.wait_for_fw_boot_status(plat_def.BOOT_STATUS_FW_ENTERED) 196 finally: 197 sd.pause() 198 sd.reset() 199 self.sdl.release_sd(sd.idx) 200 self.dev.hda_spibe.value = 0 201 202 logging.debug("<<< FirmwareLoader.download_firmware()") 203