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