diff --git a/soc/mediatek/mt8xxx/gen_img.py b/soc/mediatek/mt8xxx/gen_img.py index 3f2d48567c7..83b69ec1b9a 100755 --- a/soc/mediatek/mt8xxx/gen_img.py +++ b/soc/mediatek/mt8xxx/gen_img.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 # Copyright 2023 The ChromiumOS Authors # SPDX-License-Identifier: Apache-2.0 -import sys import struct +import sys + import elftools.elf.elffile import elftools.elf.sections @@ -19,13 +20,11 @@ import elftools.elf.sections # # No padding or uninterpreted bytes. -FILE_MAGIC = 0xe463be95 +FILE_MAGIC = 0xE463BE95 elf_file = sys.argv[1] out_file = sys.argv[2] -ef = elftools.elf.elffile.ELFFile(open(elf_file, "rb")) - sram = bytearray() dram = bytearray() @@ -34,11 +33,13 @@ dram = bytearray() # SOCs, but it's always a <=1M region in 0x4xxxxxxx. Just use what we # get, but validate that it fits. sram_block = 0 + + def sram_off(addr): global sram_block if addr < 0x40000000 or addr >= 0x50000000: return -1 - block = addr & ~0xfffff + block = addr & ~0xFFFFF assert sram_block in (0, block) sram_block = block @@ -46,44 +47,53 @@ def sram_off(addr): assert off < 0x100000 return off + # Similar heuristics: current platforms put DRAM either at 0x60000000 # or 0x90000000 with no more than 16M of range def dram_off(addr): - if (addr >> 28 not in [6, 9]) or (addr & 0x0f000000 != 0): + if (addr >> 28 not in [6, 9]) or (addr & 0x0F000000 != 0): return -1 - return addr & 0xffffff - -for seg in ef.iter_segments(): - h = seg.header - if h.p_type == "PT_LOAD": - soff = sram_off(h.p_paddr) - doff = dram_off(h.p_paddr) - if soff >= 0: - buf = sram - off = soff - elif doff >= 0: - buf = dram - off = doff - else: - print(f"Invalid PT_LOAD address {h.p_paddr:x}") - sys.exit(1) - - dat = seg.data() - end = off + len(dat) - if end > len(buf): - buf.extend(b'\x00' * (end - len(buf))) - - # pylint: disable=consider-using-enumerate - for i in range(len(dat)): - buf[i + off] = dat[i] - -for sec in ef.iter_sections(): - if isinstance(sec, elftools.elf.sections.SymbolTableSection): - for sym in sec.iter_symbols(): - if sym.name == "mtk_adsp_boot_entry": - boot_vector = sym.entry['st_value'] - -of = open(out_file, "wb") -of.write(struct.pack("= 0: + buf = sram + off = soff + elif doff >= 0: + buf = dram + off = doff + else: + print(f"Invalid PT_LOAD address {h.p_paddr:x}") + sys.exit(1) + + dat = seg.data() + end = off + len(dat) + if end > len(buf): + buf.extend(b'\x00' * (end - len(buf))) + + # pylint: disable=consider-using-enumerate + for i in range(len(dat)): + buf[i + off] = dat[i] + + for sec in ef.iter_sections(): + if isinstance(sec, elftools.elf.sections.SymbolTableSection): + for sym in sec.iter_symbols(): + if sym.name == "mtk_adsp_boot_entry": + boot_vector = sym.entry['st_value'] + + with open(out_file, "wb") as of: + of.write(struct.pack("{2 * len(rnames)}Q", readfile(path + "reg")) - maps = { n : (regs[2*i], regs[2*i+1]) for i, n in enumerate(rnames) } + maps = {n: (regs[2 * i], regs[2 * i + 1]) for i, n in enumerate(rnames)} for i, ph in enumerate(struct.unpack(">II", readfile(path + "memory-region"))): for rmem in glob("/proc/device-tree/reserved-memory/*/"): phf = rmem + "phandle" @@ -69,16 +70,17 @@ def mappings(): break return maps + # Register API for 8195 -class MT8195(): +class MT8195: def __init__(self, maps): # Create a Regs object for the registers r = Regs(ctypes.addressof(ctypes.c_int.from_buffer(maps["cfg"]))) - r.ALTRESETVEC = 0x0004 # Xtensa boot address - r.RESET_SW = 0x0024 # Xtensa halt/reset/boot control - r.PDEBUGBUS0 = 0x000c # Unclear, enabled by host, unused by SOF? - r.SRAM_POOL_CON = 0x0930 # SRAM power control: low 4 bits (banks?) enable - r.EMI_MAP_ADDR = 0x981c # == host SRAM mapping - 0x40000000 (controls MMIO map?) + r.ALTRESETVEC = 0x0004 # Xtensa boot address + r.RESET_SW = 0x0024 # Xtensa halt/reset/boot control + r.PDEBUGBUS0 = 0x000C # Unclear, enabled by host, unused by SOF? + r.SRAM_POOL_CON = 0x0930 # SRAM power control: low 4 bits (banks?) enable + r.EMI_MAP_ADDR = 0x981C # == host SRAM mapping - 0x40000000 (controls MMIO map?) r.freeze() self.cfg = r @@ -86,61 +88,63 @@ class MT8195(): return range(0x700000, 0x800000) def stop(self): - self.cfg.RESET_SW |= 8 # Set RUNSTALL: halt CPU - self.cfg.RESET_SW |= 3 # Set low two bits: "BRESET|DRESET" + self.cfg.RESET_SW |= 8 # Set RUNSTALL: halt CPU + self.cfg.RESET_SW |= 3 # Set low two bits: "BRESET|DRESET" def start(self, boot_vector): self.stop() - self.cfg.RESET_SW |= 0x10 # Enable "alternate reset" boot vector + self.cfg.RESET_SW |= 0x10 # Enable "alternate reset" boot vector self.cfg.ALTRESETVEC = boot_vector - self.cfg.RESET_SW &= ~3 # Release reset bits - self.cfg.RESET_SW &= ~8 # Clear RUNSTALL: go! + self.cfg.RESET_SW &= ~3 # Release reset bits + self.cfg.RESET_SW &= ~8 # Clear RUNSTALL: go! + # Register API for 8186/8188 -class MT818x(): +class MT818x: def __init__(self, maps): # These have registers spread across two blocks cfg_base = ctypes.addressof(ctypes.c_int.from_buffer(maps["cfg"])) sec_base = ctypes.addressof(ctypes.c_int.from_buffer(maps["sec"])) self.cfg = Regs(cfg_base) self.cfg.SW_RSTN = 0x00 - self.cfg.IO_CONFIG = 0x0c + self.cfg.IO_CONFIG = 0x0C self.cfg.freeze() self.sec = Regs(sec_base) self.sec.ALTVEC_C0 = 0x04 - self.sec.ALTVECSEL = 0x0c + self.sec.ALTVECSEL = 0x0C self.sec.freeze() def logrange(self): return range(0x700000, 0x800000) def stop(self): - self.cfg.IO_CONFIG |= (1<<31) # Set RUNSTALL to stop core + self.cfg.IO_CONFIG |= 1 << 31 # Set RUNSTALL to stop core time.sleep(0.1) - self.cfg.SW_RSTN |= 0x11 # Assert reset: SW_RSTN_C0|SW_DBG_RSTN_C0 + self.cfg.SW_RSTN |= 0x11 # Assert reset: SW_RSTN_C0|SW_DBG_RSTN_C0 # Note: 8186 and 8188 use different bits in ALTVECSEC, but # it's safe to write both to enable the alternate boot vector def start(self, boot_vector): - self.cfg.IO_CONFIG |= (1<<31) # Set RUNSTALL + self.cfg.IO_CONFIG |= 1 << 31 # Set RUNSTALL self.sec.ALTVEC_C0 = boot_vector - self.sec.ALTVECSEL = 0x03 # Enable alternate vector - self.cfg.SW_RSTN |= 0x00000011 # Assert reset - self.cfg.SW_RSTN &= 0xffffffee # Release reset - self.cfg.IO_CONFIG &= 0x7fffffff # Clear RUNSTALL + self.sec.ALTVECSEL = 0x03 # Enable alternate vector + self.cfg.SW_RSTN |= 0x00000011 # Assert reset + self.cfg.SW_RSTN &= 0xFFFFFFEE # Release reset + self.cfg.IO_CONFIG &= 0x7FFFFFFF # Clear RUNSTALL -class MT8196(): + +class MT8196: def __init__(self, maps): cfg_base = ctypes.addressof(ctypes.c_int.from_buffer(maps["cfg"])) sec_base = ctypes.addressof(ctypes.c_int.from_buffer(maps["sec"])) self.cfg = Regs(cfg_base) self.cfg.CFGREG_SW_RSTN = 0x0000 - self.cfg.MBOX_IRQ_EN = 0x009c + self.cfg.MBOX_IRQ_EN = 0x009C self.cfg.HIFI_RUNSTALL = 0x0108 self.cfg.freeze() self.sec = Regs(sec_base) self.sec.ALTVEC_C0 = 0x04 - self.sec.ALTVECSEL = 0x0c + self.sec.ALTVECSEL = 0x0C self.sec.freeze() def logrange(self): @@ -162,6 +166,7 @@ class MT8196(): self.cfg.CFGREG_SW_RSTN &= ~0x11 self.cfg.HIFI_RUNSTALL &= ~0x1000 + # Temporary logging protocol: watch the 1M null-terminated log # stream at 0x60700000 -- the top of the linkable region of # existing SOF firmware, before the heap. Nothing uses this @@ -182,30 +187,37 @@ def log(dev): sys.stdout.buffer.write(msg) sys.stdout.buffer.flush() + # (Cribbed from cavstool.py) 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 readfile(f, mode="rb"): return open(f, mode).read() + def le4(bstr): assert len(bstr) == 4 return struct.unpack("") + if __name__ == "__main__": main()