22# Copyright 2023 The ChromiumOS Authors
33# SPDX-License-Identifier: Apache-2.0
44import ctypes
5+ import mmap
56import os
7+ import re
8+ import struct
69import sys
7- import mmap
810import time
9- import struct
1011from glob import glob
11- import re
1212
1313# MT8195 audio firmware load/debug gadget
1414
3434# phandles pointing to "adsp_mem_region" and "adsp_dma_mem_region"
3535# nodes under "/reserved-memory").
3636
37- FILE_MAGIC = 0xe463be95
37+ FILE_MAGIC = 0xE463BE95
3838
3939# Runtime mmap objects for each MAPPINGS entry
4040maps = {}
4141
42+
4243# Returns a string (e.g. "mt8195", "mt8186", "mt8188") if a supported
4344# adsp is detected, or None if not
4445def detect ():
45- compat = readfile (glob ("/proc/device-tree/**/adsp@*/compatible" ,
46- recursive = True )[0 ], "r" )
46+ compat = readfile (glob ("/proc/device-tree/**/adsp@*/compatible" , recursive = True )[0 ], "r" )
4747 m = re .match (r'.*(mt\d{4})-dsp' , compat )
4848 if m :
4949 return m .group (1 )
5050
51+
5152# Parse devicetree to find the MMIO mappings: there is an "adsp" node
5253# (in various locations) with an array of named "reg" mappings. It
5354# also refers by reference to reserved-memory regions of system
@@ -59,7 +60,7 @@ def mappings():
5960 path = glob ("/proc/device-tree/**/adsp@*/" , recursive = True )[0 ]
6061 rnames = readfile (path + "reg-names" , "r" ).split ('\0 ' )[:- 1 ]
6162 regs = struct .unpack (f">{ 2 * len (rnames )} Q" , readfile (path + "reg" ))
62- maps = { n : (regs [2 * i ], regs [2 * i + 1 ]) for i , n in enumerate (rnames ) }
63+ maps = {n : (regs [2 * i ], regs [2 * i + 1 ]) for i , n in enumerate (rnames )}
6364 for i , ph in enumerate (struct .unpack (">II" , readfile (path + "memory-region" ))):
6465 for rmem in glob ("/proc/device-tree/reserved-memory/*/" ):
6566 phf = rmem + "phandle"
@@ -69,78 +70,81 @@ def mappings():
6970 break
7071 return maps
7172
73+
7274# Register API for 8195
73- class MT8195 () :
75+ class MT8195 :
7476 def __init__ (self , maps ):
7577 # Create a Regs object for the registers
7678 r = Regs (ctypes .addressof (ctypes .c_int .from_buffer (maps ["cfg" ])))
77- r .ALTRESETVEC = 0x0004 # Xtensa boot address
78- r .RESET_SW = 0x0024 # Xtensa halt/reset/boot control
79- r .PDEBUGBUS0 = 0x000c # Unclear, enabled by host, unused by SOF?
80- r .SRAM_POOL_CON = 0x0930 # SRAM power control: low 4 bits (banks?) enable
81- r .EMI_MAP_ADDR = 0x981c # == host SRAM mapping - 0x40000000 (controls MMIO map?)
79+ r .ALTRESETVEC = 0x0004 # Xtensa boot address
80+ r .RESET_SW = 0x0024 # Xtensa halt/reset/boot control
81+ r .PDEBUGBUS0 = 0x000C # Unclear, enabled by host, unused by SOF?
82+ r .SRAM_POOL_CON = 0x0930 # SRAM power control: low 4 bits (banks?) enable
83+ r .EMI_MAP_ADDR = 0x981C # == host SRAM mapping - 0x40000000 (controls MMIO map?)
8284 r .freeze ()
8385 self .cfg = r
8486
8587 def logrange (self ):
8688 return range (0x700000 , 0x800000 )
8789
8890 def stop (self ):
89- self .cfg .RESET_SW |= 8 # Set RUNSTALL: halt CPU
90- self .cfg .RESET_SW |= 3 # Set low two bits: "BRESET|DRESET"
91+ self .cfg .RESET_SW |= 8 # Set RUNSTALL: halt CPU
92+ self .cfg .RESET_SW |= 3 # Set low two bits: "BRESET|DRESET"
9193
9294 def start (self , boot_vector ):
9395 self .stop ()
94- self .cfg .RESET_SW |= 0x10 # Enable "alternate reset" boot vector
96+ self .cfg .RESET_SW |= 0x10 # Enable "alternate reset" boot vector
9597 self .cfg .ALTRESETVEC = boot_vector
96- self .cfg .RESET_SW &= ~ 3 # Release reset bits
97- self .cfg .RESET_SW &= ~ 8 # Clear RUNSTALL: go!
98+ self .cfg .RESET_SW &= ~ 3 # Release reset bits
99+ self .cfg .RESET_SW &= ~ 8 # Clear RUNSTALL: go!
100+
98101
99102# Register API for 8186/8188
100- class MT818x () :
103+ class MT818x :
101104 def __init__ (self , maps ):
102105 # These have registers spread across two blocks
103106 cfg_base = ctypes .addressof (ctypes .c_int .from_buffer (maps ["cfg" ]))
104107 sec_base = ctypes .addressof (ctypes .c_int .from_buffer (maps ["sec" ]))
105108 self .cfg = Regs (cfg_base )
106109 self .cfg .SW_RSTN = 0x00
107- self .cfg .IO_CONFIG = 0x0c
110+ self .cfg .IO_CONFIG = 0x0C
108111 self .cfg .freeze ()
109112 self .sec = Regs (sec_base )
110113 self .sec .ALTVEC_C0 = 0x04
111- self .sec .ALTVECSEL = 0x0c
114+ self .sec .ALTVECSEL = 0x0C
112115 self .sec .freeze ()
113116
114117 def logrange (self ):
115118 return range (0x700000 , 0x800000 )
116119
117120 def stop (self ):
118- self .cfg .IO_CONFIG |= ( 1 << 31 ) # Set RUNSTALL to stop core
121+ self .cfg .IO_CONFIG |= 1 << 31 # Set RUNSTALL to stop core
119122 time .sleep (0.1 )
120- self .cfg .SW_RSTN |= 0x11 # Assert reset: SW_RSTN_C0|SW_DBG_RSTN_C0
123+ self .cfg .SW_RSTN |= 0x11 # Assert reset: SW_RSTN_C0|SW_DBG_RSTN_C0
121124
122125 # Note: 8186 and 8188 use different bits in ALTVECSEC, but
123126 # it's safe to write both to enable the alternate boot vector
124127 def start (self , boot_vector ):
125- self .cfg .IO_CONFIG |= ( 1 << 31 ) # Set RUNSTALL
128+ self .cfg .IO_CONFIG |= 1 << 31 # Set RUNSTALL
126129 self .sec .ALTVEC_C0 = boot_vector
127- self .sec .ALTVECSEL = 0x03 # Enable alternate vector
128- self .cfg .SW_RSTN |= 0x00000011 # Assert reset
129- self .cfg .SW_RSTN &= 0xffffffee # Release reset
130- self .cfg .IO_CONFIG &= 0x7fffffff # Clear RUNSTALL
130+ self .sec .ALTVECSEL = 0x03 # Enable alternate vector
131+ self .cfg .SW_RSTN |= 0x00000011 # Assert reset
132+ self .cfg .SW_RSTN &= 0xFFFFFFEE # Release reset
133+ self .cfg .IO_CONFIG &= 0x7FFFFFFF # Clear RUNSTALL
131134
132- class MT8196 ():
135+
136+ class MT8196 :
133137 def __init__ (self , maps ):
134138 cfg_base = ctypes .addressof (ctypes .c_int .from_buffer (maps ["cfg" ]))
135139 sec_base = ctypes .addressof (ctypes .c_int .from_buffer (maps ["sec" ]))
136140 self .cfg = Regs (cfg_base )
137141 self .cfg .CFGREG_SW_RSTN = 0x0000
138- self .cfg .MBOX_IRQ_EN = 0x009c
142+ self .cfg .MBOX_IRQ_EN = 0x009C
139143 self .cfg .HIFI_RUNSTALL = 0x0108
140144 self .cfg .freeze ()
141145 self .sec = Regs (sec_base )
142146 self .sec .ALTVEC_C0 = 0x04
143- self .sec .ALTVECSEL = 0x0c
147+ self .sec .ALTVECSEL = 0x0C
144148 self .sec .freeze ()
145149
146150 def logrange (self ):
@@ -162,6 +166,7 @@ def start(self, boot_vector):
162166 self .cfg .CFGREG_SW_RSTN &= ~ 0x11
163167 self .cfg .HIFI_RUNSTALL &= ~ 0x1000
164168
169+
165170# Temporary logging protocol: watch the 1M null-terminated log
166171# stream at 0x60700000 -- the top of the linkable region of
167172# existing SOF firmware, before the heap. Nothing uses this
@@ -182,30 +187,37 @@ def log(dev):
182187 sys .stdout .buffer .write (msg )
183188 sys .stdout .buffer .flush ()
184189
190+
185191# (Cribbed from cavstool.py)
186192class Regs :
187193 def __init__ (self , base_addr ):
188194 vars (self )["base_addr" ] = base_addr
189195 vars (self )["ptrs" ] = {}
190196 vars (self )["frozen" ] = False
197+
191198 def freeze (self ):
192199 vars (self )["frozen" ] = True
200+
193201 def __setattr__ (self , name , val ):
194202 if not self .frozen and name not in self .ptrs :
195203 addr = self .base_addr + val
196204 self .ptrs [name ] = ctypes .c_uint32 .from_address (addr )
197205 else :
198206 self .ptrs [name ].value = val
207+
199208 def __getattr__ (self , name ):
200209 return self .ptrs [name ].value
201210
211+
202212def readfile (f , mode = "rb" ):
203213 return open (f , mode ).read ()
204214
215+
205216def le4 (bstr ):
206217 assert len (bstr ) == 4
207218 return struct .unpack ("<I" , bstr )[0 ]
208219
220+
209221def main ():
210222 dsp = detect ()
211223 assert dsp
@@ -214,13 +226,18 @@ def main():
214226 mmio = mappings ()
215227
216228 # Open device and establish mappings
217- devmem_fd = open ("/dev/mem" , "wb+" )
218- for mp in mmio :
219- paddr = mmio [mp ][0 ]
220- mapsz = mmio [mp ][1 ]
221- mapsz = int ((mapsz + 4095 ) / 4096 ) * 4096
222- maps [mp ] = mmap .mmap (devmem_fd .fileno (), mapsz , offset = paddr ,
223- flags = mmap .MAP_SHARED , prot = mmap .PROT_WRITE | mmap .PROT_READ )
229+ with open ("/dev/mem" , "wb+" ) as devmem_fd :
230+ for mp in mmio :
231+ paddr = mmio [mp ][0 ]
232+ mapsz = mmio [mp ][1 ]
233+ mapsz = int ((mapsz + 4095 ) / 4096 ) * 4096
234+ maps [mp ] = mmap .mmap (
235+ devmem_fd .fileno (),
236+ mapsz ,
237+ offset = paddr ,
238+ flags = mmap .MAP_SHARED ,
239+ prot = mmap .PROT_WRITE | mmap .PROT_READ ,
240+ )
224241
225242 if dsp == "mt8195" :
226243 dev = MT8195 (maps )
@@ -230,12 +247,14 @@ def main():
230247 dev = MT8196 (maps )
231248
232249 if sys .argv [1 ] == "load" :
233- dat = open (sys .argv [2 ], "rb" ).read ()
234- assert le4 (dat [0 :4 ])== FILE_MAGIC
250+ dat = None
251+ with open (sys .argv [2 ], "rb" ) as f :
252+ dat = f .read ()
253+ assert le4 (dat [0 :4 ]) == FILE_MAGIC
235254 sram_len = le4 (dat [4 :8 ])
236255 boot_vector = le4 (dat [8 :12 ])
237- sram = dat [12 : 12 + sram_len ]
238- dram = dat [12 + sram_len :]
256+ sram = dat [12 : 12 + sram_len ]
257+ dram = dat [12 + sram_len :]
239258 assert len (sram ) <= mmio ["sram" ][1 ]
240259 assert len (dram ) <= mmio ["dram1" ][1 ]
241260
@@ -246,7 +265,7 @@ def main():
246265 # pylint: disable=consider-using-enumerate
247266 for i in range (sram_len ):
248267 maps ["sram" ][i ] = sram [i ]
249- #for i in range(sram_len, mmio["sram"][1]):
268+ # for i in range(sram_len, mmio["sram"][1]):
250269 # maps["sram"][i] = 0
251270 for i in range (len (dram )):
252271 maps ["dram1" ][i ] = dram [i ]
@@ -266,5 +285,6 @@ def main():
266285 else :
267286 print (f"Usage: { sys .argv [0 ]} log | load <file>" )
268287
288+
269289if __name__ == "__main__" :
270290 main ()
0 commit comments