1 /*
2 * Copyright (c) 2025 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /* @file
8 * @brief NRF Wi-Fi debug shell module
9 */
10 #include <stdlib.h>
11 #include <zephyr/shell/shell.h>
12 #include "host_rpu_umac_if.h"
13 #include "fmac_main.h"
14
15 extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
16 struct nrf_wifi_ctx_zep *dbg_ctx = &rpu_drv_priv_zep.rpu_ctx_zep;
17
18
nrf_wifi_dbg_read_mem(const struct shell * sh,size_t argc,const char * argv[])19 static int nrf_wifi_dbg_read_mem(const struct shell *sh,
20 size_t argc,
21 const char *argv[])
22 {
23 enum nrf_wifi_status status;
24 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx;
25 char *ptr;
26 unsigned long mem_type;
27 unsigned long mem_offset;
28 unsigned long num_words;
29 unsigned int mem_val;
30 unsigned int mem_start_addr;
31 unsigned int mem_end_addr;
32 unsigned int i;
33
34 fmac_dev_ctx = dbg_ctx->rpu_ctx;
35 mem_type = strtoul(argv[1], &ptr, 10);
36 mem_offset = strtoul(argv[2], &ptr, 10);
37 num_words = strtoul(argv[3], &ptr, 10);
38
39 if (mem_type == 0) {
40 mem_start_addr = RPU_ADDR_PKTRAM_START + (mem_offset * 4);
41 mem_end_addr = RPU_ADDR_PKTRAM_END;
42 } else if (mem_type == 1) {
43 mem_start_addr = RPU_ADDR_GRAM_START + (mem_offset * 4);
44 mem_end_addr = RPU_ADDR_GRAM_END;
45 } else {
46 shell_fprintf(sh,
47 SHELL_ERROR,
48 "Invalid memory type(%lu).\n",
49 mem_type);
50 return -ENOEXEC;
51 }
52
53 if ((mem_start_addr % 4) != 0) {
54 shell_fprintf(sh,
55 SHELL_ERROR,
56 "Invalid memory word offset(%lu). Needs to be a multiple of 4\n",
57 mem_offset);
58 return -ENOEXEC;
59 }
60
61 if (mem_start_addr + (num_words * 4) - 1 > mem_end_addr) {
62 shell_fprintf(sh,
63 SHELL_ERROR,
64 "Invalid number of words(%lu). Exceeds memory region\n",
65 num_words);
66 return -ENOEXEC;
67 }
68
69 for (i = 0; i < (num_words * 4); i += 4) {
70 status = hal_rpu_mem_read(fmac_dev_ctx->hal_dev_ctx,
71 &mem_val,
72 mem_start_addr + i,
73 sizeof(mem_val));
74
75 if (status != NRF_WIFI_STATUS_SUCCESS) {
76 shell_fprintf(sh,
77 SHELL_ERROR,
78 "Failed to read memory at 0x%x.\n",
79 mem_start_addr + i);
80 return -ENOEXEC;
81 }
82
83 if (i % 16 == 0) {
84 shell_fprintf(sh,
85 SHELL_INFO,
86 "\n0x%x: ", mem_start_addr + i);
87 }
88
89 shell_fprintf(sh,
90 SHELL_INFO,
91 "0x%08x ",
92 mem_val);
93 }
94
95 shell_fprintf(sh,
96 SHELL_INFO,
97 "\n");
98 return 0;
99 }
100
101
nrf_wifi_dbg_write_mem(const struct shell * sh,size_t argc,const char * argv[])102 static int nrf_wifi_dbg_write_mem(const struct shell *sh,
103 size_t argc,
104 const char *argv[])
105 {
106 enum nrf_wifi_status status;
107 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx;
108 char *ptr;
109 unsigned long mem_type;
110 unsigned long mem_offset;
111 unsigned int val;
112 unsigned int mem_start_addr;
113 unsigned int mem_end_addr;
114
115 fmac_dev_ctx = dbg_ctx->rpu_ctx;
116 mem_type = strtoul(argv[1], &ptr, 10);
117 mem_offset = strtoul(argv[2], &ptr, 10);
118 val = strtoul(argv[3], &ptr, 10);
119
120 if (mem_type == 0) {
121 mem_start_addr = RPU_ADDR_PKTRAM_START + (mem_offset * 4);
122 mem_end_addr = RPU_ADDR_PKTRAM_END;
123 } else if (mem_type == 1) {
124 mem_start_addr = RPU_ADDR_GRAM_START + (mem_offset * 4);
125 mem_end_addr = RPU_ADDR_GRAM_END;
126 } else {
127 shell_fprintf(sh,
128 SHELL_ERROR,
129 "Invalid memory type(%lu).\n",
130 mem_type);
131 return -ENOEXEC;
132 }
133
134 if ((mem_start_addr % 4) != 0) {
135 shell_fprintf(sh,
136 SHELL_ERROR,
137 "Invalid memory word offset(%lu). Needs to be a multiple of 4\n",
138 mem_offset);
139 return -ENOEXEC;
140 }
141
142 if (mem_start_addr + 3 > mem_end_addr) {
143 shell_fprintf(sh,
144 SHELL_ERROR,
145 "Invalid memory word offset. Exceeds memory region\n");
146 return -ENOEXEC;
147 }
148
149 status = hal_rpu_mem_write(fmac_dev_ctx->hal_dev_ctx,
150 mem_start_addr,
151 &val,
152 sizeof(val));
153
154 if (status != NRF_WIFI_STATUS_SUCCESS) {
155 shell_fprintf(sh,
156 SHELL_ERROR,
157 "Failed to write memory at 0x%x.\n",
158 mem_start_addr);
159 return -ENOEXEC;
160 }
161
162 return 0;
163 }
164
165
nrf_wifi_dbg_read_reg(const struct shell * sh,size_t argc,const char * argv[])166 static int nrf_wifi_dbg_read_reg(const struct shell *sh,
167 size_t argc,
168 const char *argv[])
169 {
170 enum nrf_wifi_status status;
171 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx;
172 char *ptr;
173 unsigned long reg_type;
174 unsigned long reg_offset;
175 unsigned long num_regs;
176 unsigned int reg_val;
177 unsigned int reg_start_addr;
178 unsigned int reg_end_addr;
179 unsigned int i;
180
181 fmac_dev_ctx = dbg_ctx->rpu_ctx;
182 reg_type = strtoul(argv[1], &ptr, 10);
183 reg_offset = strtoul(argv[2], &ptr, 10);
184 num_regs = strtoul(argv[3], &ptr, 10);
185
186 if (reg_type == 0) {
187 reg_start_addr = RPU_ADDR_SBUS_START + (reg_offset * 4);
188 reg_end_addr = RPU_ADDR_SBUS_END;
189 } else if (reg_type == 1) {
190 reg_start_addr = RPU_ADDR_PBUS_START + (reg_offset * 4);
191 reg_end_addr = RPU_ADDR_PBUS_END;
192 } else {
193 shell_fprintf(sh,
194 SHELL_ERROR,
195 "Invalid register type(%lu).\n",
196 reg_type);
197 return -ENOEXEC;
198 }
199
200 if ((reg_start_addr % 4) != 0) {
201 shell_fprintf(sh,
202 SHELL_ERROR,
203 "Invalid register offset(%lu). Needs to be a multiple of 4\n",
204 reg_offset);
205 return -ENOEXEC;
206 }
207
208 if (reg_start_addr + (num_regs * 4) - 1 > reg_end_addr) {
209 shell_fprintf(sh,
210 SHELL_ERROR,
211 "Invalid number of registers(%lu). Exceeds bus region\n",
212 num_regs);
213 return -ENOEXEC;
214 }
215
216 for (i = 0; i < num_regs * 4; i += 4) {
217 status = hal_rpu_reg_read(fmac_dev_ctx->hal_dev_ctx,
218 ®_val,
219 reg_start_addr + i);
220
221 if (status != NRF_WIFI_STATUS_SUCCESS) {
222 shell_fprintf(sh,
223 SHELL_ERROR,
224 "Failed to read register at 0x%x.\n",
225 reg_start_addr + i);
226 return -ENOEXEC;
227 }
228
229 shell_fprintf(sh,
230 SHELL_INFO,
231 "0x%x: 0x%08x\n",
232 reg_start_addr + i,
233 reg_val);
234 }
235
236 shell_fprintf(sh,
237 SHELL_INFO,
238 "\n");
239 return 0;
240 }
241
242
nrf_wifi_dbg_write_reg(const struct shell * sh,size_t argc,const char * argv[])243 static int nrf_wifi_dbg_write_reg(const struct shell *sh,
244 size_t argc,
245 const char *argv[])
246 {
247 enum nrf_wifi_status status;
248 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx;
249 char *ptr;
250 unsigned long reg_type;
251 unsigned long reg_offset;
252 unsigned int val;
253 unsigned int reg_start_addr;
254 unsigned int reg_end_addr;
255
256 fmac_dev_ctx = dbg_ctx->rpu_ctx;
257 reg_type = strtoul(argv[1], &ptr, 10);
258 reg_offset = strtoul(argv[2], &ptr, 10);
259 val = strtoul(argv[3], &ptr, 10);
260
261 if (reg_type == 0) {
262 reg_start_addr = RPU_ADDR_SBUS_START + (reg_offset * 4);
263 reg_end_addr = RPU_ADDR_SBUS_END;
264 } else if (reg_type == 1) {
265 reg_start_addr = RPU_ADDR_PBUS_START + (reg_offset * 4);
266 reg_end_addr = RPU_ADDR_PBUS_END;
267 } else {
268 shell_fprintf(sh,
269 SHELL_ERROR,
270 "Invalid register type(%lu).\n",
271 reg_type);
272 return -ENOEXEC;
273 }
274
275 if ((reg_start_addr % 4) != 0) {
276 shell_fprintf(sh,
277 SHELL_ERROR,
278 "Invalid register offset(%lu). Needs to be a multiple of 4\n",
279 reg_offset);
280 return -ENOEXEC;
281 }
282
283 if (reg_start_addr + 3 > reg_end_addr) {
284 shell_fprintf(sh,
285 SHELL_ERROR,
286 "Invalid register offset. Exceeds bus region\n");
287 return -ENOEXEC;
288 }
289
290 status = hal_rpu_reg_write(fmac_dev_ctx->hal_dev_ctx,
291 reg_start_addr,
292 val);
293
294 if (status != NRF_WIFI_STATUS_SUCCESS) {
295 shell_fprintf(sh,
296 SHELL_ERROR,
297 "Failed to write register at 0x%x.\n",
298 reg_start_addr);
299 return -ENOEXEC;
300 }
301
302 return 0;
303 }
304
305
306
307 SHELL_STATIC_SUBCMD_SET_CREATE(
308 nrf70_dbg,
309 SHELL_CMD_ARG(read_mem,
310 NULL,
311 "<mem_type> <offset> <num_words>\n"
312 "where:\n"
313 "<mem_type> : One of the memory regions below\n"
314 "0 - PKTRAM\n"
315 "1 - GRAM\n"
316 "<offset> : Word offset in the memory region\n"
317 "<num_words> : Number of words to read\n",
318 nrf_wifi_dbg_read_mem,
319 4,
320 0),
321 SHELL_CMD_ARG(write_mem,
322 NULL,
323 "<mem_type> <offset> <val>\n"
324 "where:\n"
325 "<mem_type> : One of the memory regions below\n"
326 "0 - PKTRAM\n"
327 "1 - GRAM\n"
328 "<offset> : Word offset in the memory region\n"
329 "<val> : Value to be written\n",
330 nrf_wifi_dbg_write_mem,
331 4,
332 0),
333 SHELL_CMD_ARG(read_reg,
334 NULL,
335 "<reg_type> <offset> <num_regs>\n"
336 "where:\n"
337 "<reg_type> : One of the bus regions below\n"
338 "0 - SYSBUS\n"
339 "1 - PBUS\n"
340 "<offset> : Register offset\n"
341 "<num_words> : Number of registers to read\n",
342 nrf_wifi_dbg_read_reg,
343 4,
344 0),
345 SHELL_CMD_ARG(write_reg,
346 NULL,
347 "<reg_type> <offset> <val>\n"
348 "where:\n"
349 "<reg_type> : One of the bus regions below\n"
350 "0 - SYSBUS\n"
351 "1 - PBUS\n"
352 "<offset> : Register offset\n"
353 "<val> : Value to be written\n",
354 nrf_wifi_dbg_write_reg,
355 4,
356 0),
357 SHELL_SUBCMD_SET_END
358 );
359
360
361 SHELL_SUBCMD_ADD((nrf70), dbg, &nrf70_dbg,
362 "nRF70 advanced debug commands\n",
363 NULL,
364 0, 0);
365