1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 /**
8 * @brief File containing memory read/write specific definitions for the
9 * HAL Layer of the Wi-Fi driver.
10 */
11
12 #include "common/pal.h"
13 #include "common/hal_common.h"
14 #include "common/hal_reg.h"
15 #include "common/hal_mem.h"
16
17
hal_rpu_is_mem_ram(enum RPU_PROC_TYPE proc,unsigned int addr_val)18 static bool hal_rpu_is_mem_ram(enum RPU_PROC_TYPE proc, unsigned int addr_val)
19 {
20 if (((addr_val >= RPU_ADDR_GRAM_START) &&
21 (addr_val <= RPU_ADDR_GRAM_END)) ||
22 ((addr_val >= RPU_ADDR_PKTRAM_START) &&
23 (addr_val <= RPU_ADDR_PKTRAM_END))) {
24 return true;
25 } else {
26 return false;
27 }
28 }
29
30
hal_rpu_is_mem_bev(unsigned int addr_val)31 static bool hal_rpu_is_mem_bev(unsigned int addr_val)
32 {
33 if (((addr_val >= RPU_ADDR_BEV_START) &&
34 (addr_val <= RPU_ADDR_BEV_END))) {
35 return true;
36 } else {
37 return false;
38 }
39 }
40
hal_rpu_is_mem_core_direct(enum RPU_PROC_TYPE proc,unsigned int addr_val)41 static bool hal_rpu_is_mem_core_direct(enum RPU_PROC_TYPE proc,
42 unsigned int addr_val)
43 {
44 return pal_check_rpu_mcu_regions(proc, addr_val);
45 }
46
47
hal_rpu_is_mem_core_indirect(enum RPU_PROC_TYPE proc,unsigned int addr_val)48 static bool hal_rpu_is_mem_core_indirect(enum RPU_PROC_TYPE proc,
49 unsigned int addr_val)
50 {
51 return ((addr_val & 0xFF000000) == RPU_MCU_CORE_INDIRECT_BASE);
52 }
53
54
hal_rpu_is_mem_readable(enum RPU_PROC_TYPE proc,unsigned int addr)55 static bool hal_rpu_is_mem_readable(enum RPU_PROC_TYPE proc, unsigned int addr)
56 {
57 return hal_rpu_is_mem_ram(proc, addr);
58 }
59
60
hal_rpu_is_mem_writable(enum RPU_PROC_TYPE proc,unsigned int addr)61 static bool hal_rpu_is_mem_writable(enum RPU_PROC_TYPE proc,
62 unsigned int addr)
63 {
64 if (hal_rpu_is_mem_ram(proc, addr) ||
65 hal_rpu_is_mem_core_indirect(proc, addr) ||
66 hal_rpu_is_mem_core_direct(proc, addr) ||
67 hal_rpu_is_mem_bev(addr)) {
68 return true;
69 }
70
71 return false;
72 }
73
74
rpu_mem_read_ram(struct nrf_wifi_hal_dev_ctx * hal_dev_ctx,void * src_addr,unsigned int ram_addr_val,unsigned int len)75 static enum nrf_wifi_status rpu_mem_read_ram(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
76 void *src_addr,
77 unsigned int ram_addr_val,
78 unsigned int len)
79 {
80 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
81 unsigned long addr_offset = 0;
82 #ifdef NRF_WIFI_LOW_POWER
83 unsigned long flags = 0;
84 #endif /* NRF_WIFI_LOW_POWER */
85
86 status = pal_rpu_addr_offset_get(ram_addr_val,
87 &addr_offset,
88 hal_dev_ctx->curr_proc);
89
90 if (status != NRF_WIFI_STATUS_SUCCESS) {
91 nrf_wifi_osal_log_err("%s: pal_rpu_addr_offset_get failed",
92 __func__);
93 return status;
94 }
95
96 #ifdef NRF_WIFI_LOW_POWER
97 nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->rpu_ps_lock,
98 &flags);
99
100 status = hal_rpu_ps_wake(hal_dev_ctx);
101
102 if (status != NRF_WIFI_STATUS_SUCCESS) {
103 nrf_wifi_osal_log_err("%s: RPU wake failed",
104 __func__);
105 goto out;
106 }
107 #endif /* NRF_WIFI_LOW_POWER */
108
109 nrf_wifi_bal_read_block(hal_dev_ctx->bal_dev_ctx,
110 src_addr,
111 addr_offset,
112 len);
113
114 status = NRF_WIFI_STATUS_SUCCESS;
115
116 #ifdef NRF_WIFI_LOW_POWER
117 out:
118 nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->rpu_ps_lock,
119 &flags);
120 #endif /* NRF_WIFI_LOW_POWER */
121
122 return status;
123 }
124
125
rpu_mem_write_ram(struct nrf_wifi_hal_dev_ctx * hal_dev_ctx,unsigned int ram_addr_val,void * src_addr,unsigned int len)126 static enum nrf_wifi_status rpu_mem_write_ram(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
127 unsigned int ram_addr_val,
128 void *src_addr,
129 unsigned int len)
130 {
131 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
132 unsigned long addr_offset = 0;
133 #ifdef NRF_WIFI_LOW_POWER
134 unsigned long flags = 0;
135 #endif /* NRF_WIFI_LOW_POWER */
136
137 status = pal_rpu_addr_offset_get(ram_addr_val,
138 &addr_offset,
139 hal_dev_ctx->curr_proc);
140
141 if (status != NRF_WIFI_STATUS_SUCCESS) {
142 nrf_wifi_osal_log_err("%s: pal_rpu_addr_offset_get failed",
143 __func__);
144 return status;
145 }
146
147 #ifdef NRF_WIFI_LOW_POWER
148 nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->rpu_ps_lock,
149 &flags);
150
151 status = hal_rpu_ps_wake(hal_dev_ctx);
152
153 if (status != NRF_WIFI_STATUS_SUCCESS) {
154 nrf_wifi_osal_log_err("%s: RPU wake failed",
155 __func__);
156 goto out;
157 }
158 #endif /* NRF_WIFI_LOW_POWER */
159
160 nrf_wifi_bal_write_block(hal_dev_ctx->bal_dev_ctx,
161 addr_offset,
162 src_addr,
163 len);
164
165 status = NRF_WIFI_STATUS_SUCCESS;
166
167 #ifdef NRF_WIFI_LOW_POWER
168 out:
169 nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->rpu_ps_lock,
170 &flags);
171 #endif /* NRF_WIFI_LOW_POWER */
172
173 return status;
174 }
175
176
rpu_mem_write_core(struct nrf_wifi_hal_dev_ctx * hal_dev_ctx,unsigned int core_addr_val,void * src_addr,unsigned int len)177 static enum nrf_wifi_status rpu_mem_write_core(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
178 unsigned int core_addr_val,
179 void *src_addr,
180 unsigned int len)
181 {
182 int status = NRF_WIFI_STATUS_FAIL;
183 unsigned int addr_reg = 0;
184 unsigned int data_reg = 0;
185 unsigned int addr = 0;
186 unsigned int data = 0;
187 unsigned int i = 0;
188
189 /* The RPU core address is expected to be in multiples of 4 bytes (word
190 * size). If not then something is amiss.
191 */
192 if (!hal_rpu_is_mem_core_indirect(hal_dev_ctx->curr_proc,
193 core_addr_val)) {
194 nrf_wifi_osal_log_err("%s: Invalid memory address",
195 __func__);
196 goto out;
197 }
198
199 if (core_addr_val % 4 != 0) {
200 nrf_wifi_osal_log_err("%s: Address not multiple of 4 bytes",
201 __func__);
202 goto out;
203 }
204
205 /* The register expects the word address offset to be programmed
206 * (i.e. it will write 4 bytes at once to the given address).
207 * whereas we receive the address in byte address offset.
208 */
209 addr = (core_addr_val & RPU_ADDR_MASK_OFFSET) / 4;
210
211 addr_reg = RPU_REG_MIPS_MCU_SYS_CORE_MEM_CTRL;
212 data_reg = RPU_REG_MIPS_MCU_SYS_CORE_MEM_WDATA;
213
214 if (hal_dev_ctx->curr_proc == RPU_PROC_TYPE_MCU_UMAC) {
215 addr_reg = RPU_REG_MIPS_MCU2_SYS_CORE_MEM_CTRL;
216 data_reg = RPU_REG_MIPS_MCU2_SYS_CORE_MEM_WDATA;
217 }
218
219 status = hal_rpu_reg_write(hal_dev_ctx,
220 addr_reg,
221 addr);
222
223 if (status != NRF_WIFI_STATUS_SUCCESS) {
224 nrf_wifi_osal_log_err("%s: Writing to address reg failed",
225 __func__);
226 goto out;
227 }
228
229 for (i = 0; i < (len / sizeof(int)); i++) {
230 data = *((unsigned int *)src_addr + i);
231
232 status = hal_rpu_reg_write(hal_dev_ctx,
233 data_reg,
234 data);
235
236 if (status != NRF_WIFI_STATUS_SUCCESS) {
237 nrf_wifi_osal_log_err("%s: Writing to data reg failed",
238 __func__);
239 goto out;
240 }
241 }
242 out:
243 return status;
244 }
245
246
rpu_get_bev_addr_remap(struct nrf_wifi_hal_dev_ctx * hal_dev_ctx,unsigned int bev_addr_val)247 static unsigned int rpu_get_bev_addr_remap(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
248 unsigned int bev_addr_val)
249 {
250 unsigned int addr = 0;
251 unsigned int offset = 0;
252
253 offset = bev_addr_val & RPU_ADDR_MASK_BEV_OFFSET;
254
255 /* Base of the Boot Exception Vector 0xBFC00000 maps to 0xA4000050 */
256 addr = RPU_REG_MIPS_MCU_BOOT_EXCP_INSTR_0 + offset;
257
258 if (hal_dev_ctx->curr_proc == RPU_PROC_TYPE_MCU_UMAC) {
259 addr = RPU_REG_MIPS_MCU2_BOOT_EXCP_INSTR_0 + offset;
260 }
261
262 return addr;
263 }
264
265
rpu_mem_write_bev(struct nrf_wifi_hal_dev_ctx * hal_dev_ctx,unsigned int bev_addr_val,void * src_addr,unsigned int len)266 static enum nrf_wifi_status rpu_mem_write_bev(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
267 unsigned int bev_addr_val,
268 void *src_addr,
269 unsigned int len)
270 {
271 int status = NRF_WIFI_STATUS_FAIL;
272 unsigned int addr = 0;
273 unsigned int data = 0;
274 unsigned int i = 0;
275
276 /* The RPU BEV address is expected to be in multiples of 4 bytes (word
277 * size). If not then something is amiss.
278 */
279 if ((bev_addr_val < RPU_ADDR_BEV_START) ||
280 (bev_addr_val > RPU_ADDR_BEV_END) ||
281 (bev_addr_val % 4 != 0)) {
282 nrf_wifi_osal_log_err("%s: Address not in range or not a multiple of 4 bytes",
283 __func__);
284 goto out;
285 }
286
287 for (i = 0; i < (len / sizeof(int)); i++) {
288 /* The BEV addresses need remapping
289 * to an address on the SYSBUS.
290 */
291 addr = rpu_get_bev_addr_remap(hal_dev_ctx,
292 bev_addr_val +
293 (i * sizeof(int)));
294
295 data = *((unsigned int *)src_addr + i);
296
297 status = hal_rpu_reg_write(hal_dev_ctx,
298 addr,
299 data);
300
301 if (status != NRF_WIFI_STATUS_SUCCESS) {
302 nrf_wifi_osal_log_err("%s: Writing to BEV reg failed",
303 __func__);
304 goto out;
305 }
306 }
307
308 out:
309 return status;
310 }
311
312
hal_rpu_mem_read(struct nrf_wifi_hal_dev_ctx * hal_dev_ctx,void * src_addr,unsigned int rpu_mem_addr_val,unsigned int len)313 enum nrf_wifi_status hal_rpu_mem_read(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
314 void *src_addr,
315 unsigned int rpu_mem_addr_val,
316 unsigned int len)
317 {
318 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
319
320 if (!hal_dev_ctx) {
321 goto out;
322 }
323
324 if (!src_addr) {
325 nrf_wifi_osal_log_err("%s: Invalid params",
326 __func__);
327 goto out;
328 }
329
330 if (!hal_rpu_is_mem_readable(hal_dev_ctx->curr_proc, rpu_mem_addr_val)) {
331 nrf_wifi_osal_log_err("%s: Invalid memory address 0x%X",
332 __func__,
333 rpu_mem_addr_val);
334 goto out;
335 }
336
337 status = rpu_mem_read_ram(hal_dev_ctx,
338 src_addr,
339 rpu_mem_addr_val,
340 len);
341 out:
342 return status;
343 }
344
345
hal_rpu_mem_write(struct nrf_wifi_hal_dev_ctx * hal_dev_ctx,unsigned int rpu_mem_addr_val,void * src_addr,unsigned int len)346 enum nrf_wifi_status hal_rpu_mem_write(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
347 unsigned int rpu_mem_addr_val,
348 void *src_addr,
349 unsigned int len)
350 {
351 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
352
353 if (!hal_dev_ctx) {
354 return status;
355 }
356
357 if (!src_addr) {
358 nrf_wifi_osal_log_err("%s: Invalid params",
359 __func__);
360 return status;
361 }
362
363 if (!hal_rpu_is_mem_writable(hal_dev_ctx->curr_proc,
364 rpu_mem_addr_val)) {
365 nrf_wifi_osal_log_err("%s: Invalid memory address 0x%X",
366 __func__,
367 rpu_mem_addr_val);
368 return status;
369 }
370
371 if (hal_rpu_is_mem_core_indirect(hal_dev_ctx->curr_proc,
372 rpu_mem_addr_val)) {
373 status = rpu_mem_write_core(hal_dev_ctx,
374 rpu_mem_addr_val,
375 src_addr,
376 len);
377 } else if (hal_rpu_is_mem_core_direct(hal_dev_ctx->curr_proc, rpu_mem_addr_val) ||
378 hal_rpu_is_mem_ram(hal_dev_ctx->curr_proc, rpu_mem_addr_val)) {
379 status = rpu_mem_write_ram(hal_dev_ctx,
380 rpu_mem_addr_val,
381 src_addr,
382 len);
383 } else if (hal_rpu_is_mem_bev(rpu_mem_addr_val)) {
384 status = rpu_mem_write_bev(hal_dev_ctx,
385 rpu_mem_addr_val,
386 src_addr,
387 len);
388 } else {
389 nrf_wifi_osal_log_err("%s: Invalid memory address 0x%X",
390 __func__,
391 rpu_mem_addr_val);
392 goto out;
393 }
394
395 out:
396 return status;
397 }
398
399
hal_rpu_mem_clr(struct nrf_wifi_hal_dev_ctx * hal_dev_ctx,enum RPU_PROC_TYPE proc,enum HAL_RPU_MEM_TYPE mem_type)400 enum nrf_wifi_status hal_rpu_mem_clr(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
401 enum RPU_PROC_TYPE proc,
402 enum HAL_RPU_MEM_TYPE mem_type)
403 {
404 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
405 unsigned int mem_addr = 0;
406 unsigned int start_addr = 0;
407 unsigned int end_addr = 0;
408 unsigned int mem_val = 0;
409 enum RPU_MCU_ADDR_REGIONS mcu_region = pal_mem_type_to_region(mem_type);
410
411 if (!hal_dev_ctx) {
412 goto out;
413 }
414
415 if (mem_type == HAL_RPU_MEM_TYPE_GRAM) {
416 start_addr = RPU_ADDR_GRAM_START;
417 end_addr = RPU_ADDR_GRAM_END;
418 } else if (mem_type == HAL_RPU_MEM_TYPE_PKTRAM) {
419 start_addr = RPU_ADDR_PKTRAM_START;
420 end_addr = RPU_ADDR_PKTRAM_END;
421 } else if (mcu_region != RPU_MCU_ADDR_REGION_MAX) {
422 const struct rpu_addr_map *map = &RPU_ADDR_MAP_MCU[proc];
423 const struct rpu_addr_region *region = &map->regions[mcu_region];
424
425 start_addr = region->start;
426 end_addr = region->end;
427 } else {
428 nrf_wifi_osal_log_err("%s: Invalid mem_type(%d)",
429 __func__,
430 mem_type);
431 goto out;
432 }
433
434 for (mem_addr = start_addr;
435 mem_addr <= end_addr;
436 mem_addr += sizeof(mem_val)) {
437 status = hal_rpu_mem_write(hal_dev_ctx,
438 mem_addr,
439 &mem_val,
440 sizeof(mem_val));
441
442 if (status != NRF_WIFI_STATUS_SUCCESS) {
443 nrf_wifi_osal_log_err("%s: hal_rpu_mem_write failed",
444 __func__);
445 goto out;
446 }
447 }
448
449
450
451 status = NRF_WIFI_STATUS_SUCCESS;
452 out:
453 return status;
454 }
455