2
2
# Copyright 2023 The ChromiumOS Authors
3
3
# SPDX-License-Identifier: Apache-2.0
4
4
import ctypes
5
+ import mmap
5
6
import os
7
+ import re
8
+ import struct
6
9
import sys
7
- import mmap
8
10
import time
9
- import struct
10
11
from glob import glob
11
- import re
12
12
13
13
# MT8195 audio firmware load/debug gadget
14
14
34
34
# phandles pointing to "adsp_mem_region" and "adsp_dma_mem_region"
35
35
# nodes under "/reserved-memory").
36
36
37
- FILE_MAGIC = 0xe463be95
37
+ FILE_MAGIC = 0xE463BE95
38
38
39
39
# Runtime mmap objects for each MAPPINGS entry
40
40
maps = {}
41
41
42
+
42
43
# Returns a string (e.g. "mt8195", "mt8186", "mt8188") if a supported
43
44
# adsp is detected, or None if not
44
45
def 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" )
47
47
m = re .match (r'.*(mt\d{4})-dsp' , compat )
48
48
if m :
49
49
return m .group (1 )
50
50
51
+
51
52
# Parse devicetree to find the MMIO mappings: there is an "adsp" node
52
53
# (in various locations) with an array of named "reg" mappings. It
53
54
# also refers by reference to reserved-memory regions of system
@@ -59,7 +60,7 @@ def mappings():
59
60
path = glob ("/proc/device-tree/**/adsp@*/" , recursive = True )[0 ]
60
61
rnames = readfile (path + "reg-names" , "r" ).split ('\0 ' )[:- 1 ]
61
62
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 )}
63
64
for i , ph in enumerate (struct .unpack (">II" , readfile (path + "memory-region" ))):
64
65
for rmem in glob ("/proc/device-tree/reserved-memory/*/" ):
65
66
phf = rmem + "phandle"
@@ -69,78 +70,81 @@ def mappings():
69
70
break
70
71
return maps
71
72
73
+
72
74
# Register API for 8195
73
- class MT8195 () :
75
+ class MT8195 :
74
76
def __init__ (self , maps ):
75
77
# Create a Regs object for the registers
76
78
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?)
82
84
r .freeze ()
83
85
self .cfg = r
84
86
85
87
def logrange (self ):
86
88
return range (0x700000 , 0x800000 )
87
89
88
90
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"
91
93
92
94
def start (self , boot_vector ):
93
95
self .stop ()
94
- self .cfg .RESET_SW |= 0x10 # Enable "alternate reset" boot vector
96
+ self .cfg .RESET_SW |= 0x10 # Enable "alternate reset" boot vector
95
97
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
+
98
101
99
102
# Register API for 8186/8188
100
- class MT818x () :
103
+ class MT818x :
101
104
def __init__ (self , maps ):
102
105
# These have registers spread across two blocks
103
106
cfg_base = ctypes .addressof (ctypes .c_int .from_buffer (maps ["cfg" ]))
104
107
sec_base = ctypes .addressof (ctypes .c_int .from_buffer (maps ["sec" ]))
105
108
self .cfg = Regs (cfg_base )
106
109
self .cfg .SW_RSTN = 0x00
107
- self .cfg .IO_CONFIG = 0x0c
110
+ self .cfg .IO_CONFIG = 0x0C
108
111
self .cfg .freeze ()
109
112
self .sec = Regs (sec_base )
110
113
self .sec .ALTVEC_C0 = 0x04
111
- self .sec .ALTVECSEL = 0x0c
114
+ self .sec .ALTVECSEL = 0x0C
112
115
self .sec .freeze ()
113
116
114
117
def logrange (self ):
115
118
return range (0x700000 , 0x800000 )
116
119
117
120
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
119
122
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
121
124
122
125
# Note: 8186 and 8188 use different bits in ALTVECSEC, but
123
126
# it's safe to write both to enable the alternate boot vector
124
127
def start (self , boot_vector ):
125
- self .cfg .IO_CONFIG |= ( 1 << 31 ) # Set RUNSTALL
128
+ self .cfg .IO_CONFIG |= 1 << 31 # Set RUNSTALL
126
129
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
131
134
132
- class MT8196 ():
135
+
136
+ class MT8196 :
133
137
def __init__ (self , maps ):
134
138
cfg_base = ctypes .addressof (ctypes .c_int .from_buffer (maps ["cfg" ]))
135
139
sec_base = ctypes .addressof (ctypes .c_int .from_buffer (maps ["sec" ]))
136
140
self .cfg = Regs (cfg_base )
137
141
self .cfg .CFGREG_SW_RSTN = 0x0000
138
- self .cfg .MBOX_IRQ_EN = 0x009c
142
+ self .cfg .MBOX_IRQ_EN = 0x009C
139
143
self .cfg .HIFI_RUNSTALL = 0x0108
140
144
self .cfg .freeze ()
141
145
self .sec = Regs (sec_base )
142
146
self .sec .ALTVEC_C0 = 0x04
143
- self .sec .ALTVECSEL = 0x0c
147
+ self .sec .ALTVECSEL = 0x0C
144
148
self .sec .freeze ()
145
149
146
150
def logrange (self ):
@@ -162,6 +166,7 @@ def start(self, boot_vector):
162
166
self .cfg .CFGREG_SW_RSTN &= ~ 0x11
163
167
self .cfg .HIFI_RUNSTALL &= ~ 0x1000
164
168
169
+
165
170
# Temporary logging protocol: watch the 1M null-terminated log
166
171
# stream at 0x60700000 -- the top of the linkable region of
167
172
# existing SOF firmware, before the heap. Nothing uses this
@@ -182,30 +187,37 @@ def log(dev):
182
187
sys .stdout .buffer .write (msg )
183
188
sys .stdout .buffer .flush ()
184
189
190
+
185
191
# (Cribbed from cavstool.py)
186
192
class Regs :
187
193
def __init__ (self , base_addr ):
188
194
vars (self )["base_addr" ] = base_addr
189
195
vars (self )["ptrs" ] = {}
190
196
vars (self )["frozen" ] = False
197
+
191
198
def freeze (self ):
192
199
vars (self )["frozen" ] = True
200
+
193
201
def __setattr__ (self , name , val ):
194
202
if not self .frozen and name not in self .ptrs :
195
203
addr = self .base_addr + val
196
204
self .ptrs [name ] = ctypes .c_uint32 .from_address (addr )
197
205
else :
198
206
self .ptrs [name ].value = val
207
+
199
208
def __getattr__ (self , name ):
200
209
return self .ptrs [name ].value
201
210
211
+
202
212
def readfile (f , mode = "rb" ):
203
213
return open (f , mode ).read ()
204
214
215
+
205
216
def le4 (bstr ):
206
217
assert len (bstr ) == 4
207
218
return struct .unpack ("<I" , bstr )[0 ]
208
219
220
+
209
221
def main ():
210
222
dsp = detect ()
211
223
assert dsp
@@ -214,13 +226,18 @@ def main():
214
226
mmio = mappings ()
215
227
216
228
# 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
+ )
224
241
225
242
if dsp == "mt8195" :
226
243
dev = MT8195 (maps )
@@ -230,12 +247,14 @@ def main():
230
247
dev = MT8196 (maps )
231
248
232
249
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
235
254
sram_len = le4 (dat [4 :8 ])
236
255
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 :]
239
258
assert len (sram ) <= mmio ["sram" ][1 ]
240
259
assert len (dram ) <= mmio ["dram1" ][1 ]
241
260
@@ -246,7 +265,7 @@ def main():
246
265
# pylint: disable=consider-using-enumerate
247
266
for i in range (sram_len ):
248
267
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]):
250
269
# maps["sram"][i] = 0
251
270
for i in range (len (dram )):
252
271
maps ["dram1" ][i ] = dram [i ]
@@ -266,5 +285,6 @@ def main():
266
285
else :
267
286
print (f"Usage: { sys .argv [0 ]} log | load <file>" )
268
287
288
+
269
289
if __name__ == "__main__" :
270
290
main ()
0 commit comments