1 /*
2  * Copyright (c) 2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Driver to utilize TLB on Intel Audio DSP
10  *
11  * TLB (Translation Lookup Buffer) table is used to map between
12  * physical and virtual memory. This is global to all cores
13  * on the DSP, as changes to the TLB table are visible to
14  * all cores.
15  *
16  * Note that all passed in addresses should be in cached range
17  * (aka cached addresses). Due to the need to calculate TLB
18  * indexes, virtual addresses will be converted internally to
19  * cached one via z_soc_cached_ptr(). However, physical addresses
20  * are untouched.
21  */
22 
23 #include "mm_drv_intel_adsp.h"
24 #include <soc_util.h>
25 #include <zephyr/drivers/mm/mm_drv_intel_adsp_mtl_tlb.h>
26 #include <zephyr/drivers/mm/mm_drv_bank.h>
27 #include <zephyr/debug/sparse.h>
28 #include <zephyr/cache.h>
29 
30 static struct k_spinlock tlb_lock;
31 extern struct k_spinlock sys_mm_drv_common_lock;
32 
33 static struct mem_drv_bank hpsram_bank[L2_SRAM_BANK_NUM];
34 
35 #ifdef CONFIG_SOC_INTEL_COMM_WIDGET
36 #include <adsp_comm_widget.h>
37 
38 static uint32_t used_pages;
39 /* PMC uses 32 KB banks */
40 static uint32_t used_pmc_banks_reported;
41 #endif
42 
43 
44 /* Define a marker which is placed by the linker script just after
45  * last explicitly defined section. All .text, .data, .bss and .heap
46  * sections should be placed before this marker in the memory.
47  * This driver is using the location of the marker to
48  * unmap the unused L2 memory and power off corresponding memory banks.
49  */
50 __attribute__((__section__(".unused_ram_start_marker")))
51 static int unused_l2_sram_start_marker = 0xba0babce;
52 #define UNUSED_L2_START_ALIGNED ROUND_UP(POINTER_TO_UINT(&unused_l2_sram_start_marker), \
53 					 CONFIG_MM_DRV_PAGE_SIZE)
54 
55 /* declare L2 physical memory block */
56 SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(
57 		L2_PHYS_SRAM_REGION,
58 		CONFIG_MM_DRV_PAGE_SIZE,
59 		L2_SRAM_PAGES_NUM,
60 		(uint8_t *) L2_SRAM_BASE);
61 
62 /**
63  * Calculate the index to the TLB table.
64  *
65  * @param vaddr Page-aligned virutal address.
66  * @return Index to the TLB table.
67  */
get_tlb_entry_idx(uintptr_t vaddr)68 static uint32_t get_tlb_entry_idx(uintptr_t vaddr)
69 {
70 	return (POINTER_TO_UINT(vaddr) - CONFIG_KERNEL_VM_BASE) /
71 	       CONFIG_MM_DRV_PAGE_SIZE;
72 }
73 
74 /**
75  * Calculate the index of the HPSRAM bank.
76  *
77  * @param pa physical address.
78  * @return Index of the HPSRAM bank.
79  */
get_hpsram_bank_idx(uintptr_t pa)80 static uint32_t get_hpsram_bank_idx(uintptr_t pa)
81 {
82 	uint32_t phys_offset = pa - L2_SRAM_BASE;
83 
84 	return (phys_offset / SRAM_BANK_SIZE);
85 }
86 
87 /**
88  * Convert the SYS_MM_MEM_PERM_* flags into TLB entry permission bits.
89  *
90  * @param flags Access flags (SYS_MM_MEM_PERM_*)
91  * @return TLB entry permission bits
92  */
flags_to_tlb_perms(uint32_t flags)93 static uint16_t flags_to_tlb_perms(uint32_t flags)
94 {
95 #if defined(CONFIG_SOC_SERIES_INTEL_ACE)
96 	uint16_t perms = 0;
97 
98 	if ((flags & SYS_MM_MEM_PERM_RW) == SYS_MM_MEM_PERM_RW) {
99 		perms |= TLB_WRITE_BIT;
100 	}
101 
102 	if ((flags & SYS_MM_MEM_PERM_EXEC) == SYS_MM_MEM_PERM_EXEC) {
103 		perms |= TLB_EXEC_BIT;
104 	}
105 
106 	return perms;
107 #else
108 	return 0;
109 #endif
110 }
111 
112 #if defined(CONFIG_SOC_SERIES_INTEL_ACE)
113 /**
114  * Convert TLB entry permission bits to the SYS_MM_MEM_PERM_* flags.
115  *
116  * @param perms TLB entry permission bits
117  * @return Access flags (SYS_MM_MEM_PERM_*)
118  */
tlb_perms_to_flags(uint16_t perms)119 static uint16_t tlb_perms_to_flags(uint16_t perms)
120 {
121 	uint32_t flags = 0;
122 
123 	if ((perms & TLB_WRITE_BIT) == TLB_WRITE_BIT) {
124 		flags |= SYS_MM_MEM_PERM_RW;
125 	}
126 
127 	if ((perms & TLB_EXEC_BIT) == TLB_EXEC_BIT) {
128 		flags |= SYS_MM_MEM_PERM_EXEC;
129 	}
130 
131 	return flags;
132 }
133 #endif
134 
sys_mm_drv_hpsram_pwr(uint32_t bank_idx,bool enable,bool non_blocking)135 static int sys_mm_drv_hpsram_pwr(uint32_t bank_idx, bool enable, bool non_blocking)
136 {
137 #if defined(CONFIG_SOC_SERIES_INTEL_ACE)
138 	if (bank_idx > ace_hpsram_get_bank_count()) {
139 		return -1;
140 	}
141 
142 	HPSRAM_REGS(bank_idx)->HSxPGCTL = !enable;
143 
144 	if (!non_blocking) {
145 		while (HPSRAM_REGS(bank_idx)->HSxPGISTS == enable) {
146 			k_busy_wait(1);
147 		}
148 	}
149 #endif
150 	return 0;
151 }
152 
153 #ifdef CONFIG_SOC_INTEL_COMM_WIDGET
sys_mm_drv_report_page_usage(void)154 static void sys_mm_drv_report_page_usage(void)
155 {
156 	/* PMC uses 32 KB banks */
157 	uint32_t pmc_banks = DIV_ROUND_UP(used_pages, KB(32) / CONFIG_MM_DRV_PAGE_SIZE);
158 
159 	if (used_pmc_banks_reported != pmc_banks) {
160 		if (!adsp_comm_widget_pmc_send_ipc(pmc_banks)) {
161 			/* Store reported value if message was sent successfully. */
162 			used_pmc_banks_reported = pmc_banks;
163 		}
164 	}
165 }
166 #endif
167 
sys_mm_drv_map_page(void * virt,uintptr_t phys,uint32_t flags)168 int sys_mm_drv_map_page(void *virt, uintptr_t phys, uint32_t flags)
169 {
170 	k_spinlock_key_t key;
171 	uint32_t entry_idx, bank_idx;
172 	uint16_t entry;
173 	volatile uint16_t *tlb_entries = UINT_TO_POINTER(TLB_BASE);
174 	int ret = 0;
175 	void *phys_block_ptr;
176 
177 	/*
178 	 * Cached addresses for both physical and virtual.
179 	 *
180 	 * As the main memory is in cached address ranges,
181 	 * the cached physical address is needed to perform
182 	 * bound check.
183 	 */
184 	uintptr_t pa = POINTER_TO_UINT(z_soc_cached_ptr(UINT_TO_POINTER(phys)));
185 	uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt));
186 
187 	ARG_UNUSED(flags);
188 
189 	/* Make sure VA is page-aligned */
190 	CHECKIF(!sys_mm_drv_is_addr_aligned(va)) {
191 		ret = -EINVAL;
192 		goto out;
193 	}
194 
195 	/* Check bounds of virtual address space */
196 	CHECKIF((va < UNUSED_L2_START_ALIGNED) ||
197 		(va >= (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE))) {
198 		ret = -EINVAL;
199 		goto out;
200 	}
201 
202 	/*
203 	 * When the provided physical address is NULL
204 	 * then it is a signal to the Intel ADSP TLB driver to
205 	 * select the first available free physical address
206 	 * autonomously within the driver.
207 	 */
208 	if (UINT_TO_POINTER(phys) == NULL) {
209 		ret = sys_mem_blocks_alloc_contiguous(&L2_PHYS_SRAM_REGION, 1,
210 						      &phys_block_ptr);
211 		if (ret != 0) {
212 			__ASSERT(false,
213 				 "unable to assign free phys page %d\n", ret);
214 			goto out;
215 		}
216 		pa = POINTER_TO_UINT(z_soc_cached_ptr(phys_block_ptr));
217 	}
218 
219 	/* Check bounds of physical address space */
220 	CHECKIF((pa < L2_SRAM_BASE) ||
221 		(pa >= (L2_SRAM_BASE + L2_SRAM_SIZE))) {
222 		ret = -EINVAL;
223 		goto out;
224 	}
225 
226 	/* Make sure PA is page-aligned */
227 	CHECKIF(!sys_mm_drv_is_addr_aligned(pa)) {
228 		ret = -EINVAL;
229 		goto out;
230 	}
231 
232 	key = k_spin_lock(&tlb_lock);
233 
234 	entry_idx = get_tlb_entry_idx(va);
235 
236 #ifdef CONFIG_SOC_INTEL_COMM_WIDGET
237 	used_pages++;
238 	sys_mm_drv_report_page_usage();
239 #endif
240 
241 	bank_idx = get_hpsram_bank_idx(pa);
242 	if (sys_mm_drv_bank_page_mapped(&hpsram_bank[bank_idx]) == 1) {
243 		sys_mm_drv_hpsram_pwr(bank_idx, true, false);
244 	}
245 
246 	/*
247 	 * The address part of the TLB entry takes the lowest
248 	 * TLB_PADDR_SIZE bits of the physical page number,
249 	 * and discards the highest bits.  This is due to the
250 	 * architecture design where the same physical page
251 	 * can be accessed via two addresses. One address goes
252 	 * through the cache, and the other one accesses
253 	 * memory directly (without cache). The difference
254 	 * between these two addresses are in the higher bits,
255 	 * and the lower bits are the same.  And this is why
256 	 * TLB only cares about the lower part of the physical
257 	 * address.
258 	 */
259 	entry = pa_to_tlb_entry(pa);
260 
261 	/* Enable the translation in the TLB entry */
262 	entry |= TLB_ENABLE_BIT;
263 
264 	/* Set permissions for this entry */
265 	entry |= flags_to_tlb_perms(flags);
266 
267 	tlb_entries[entry_idx] = entry;
268 
269 	/*
270 	 * Invalid the cache of the newly mapped virtual page to
271 	 * avoid stale data.
272 	 */
273 	sys_cache_data_invd_range(virt, CONFIG_MM_DRV_PAGE_SIZE);
274 
275 	k_spin_unlock(&tlb_lock, key);
276 
277 out:
278 	return ret;
279 }
280 
sys_mm_drv_map_region(void * virt,uintptr_t phys,size_t size,uint32_t flags)281 int sys_mm_drv_map_region(void *virt, uintptr_t phys,
282 			  size_t size, uint32_t flags)
283 {
284 	k_spinlock_key_t key;
285 	int ret = 0;
286 	size_t offset;
287 	uintptr_t pa;
288 	uint8_t *va;
289 
290 	CHECKIF(!sys_mm_drv_is_addr_aligned(phys) ||
291 		!sys_mm_drv_is_virt_addr_aligned(virt) ||
292 		!sys_mm_drv_is_size_aligned(size)) {
293 		ret = -EINVAL;
294 		goto out;
295 	}
296 
297 	va = (__sparse_force uint8_t *)z_soc_cached_ptr(virt);
298 	pa = phys;
299 
300 	key = k_spin_lock(&sys_mm_drv_common_lock);
301 
302 	for (offset = 0; offset < size; offset += CONFIG_MM_DRV_PAGE_SIZE) {
303 		int ret2 = sys_mm_drv_map_page(va, pa, flags);
304 
305 		if (ret2 != 0) {
306 			__ASSERT(false, "cannot map 0x%lx to %p\n", pa, va);
307 
308 			ret = ret2;
309 		}
310 		va += CONFIG_MM_DRV_PAGE_SIZE;
311 		if (phys != 0) {
312 			pa += CONFIG_MM_DRV_PAGE_SIZE;
313 		}
314 	}
315 
316 	k_spin_unlock(&sys_mm_drv_common_lock, key);
317 
318 out:
319 	return ret;
320 }
321 
sys_mm_drv_map_array(void * virt,uintptr_t * phys,size_t cnt,uint32_t flags)322 int sys_mm_drv_map_array(void *virt, uintptr_t *phys,
323 			 size_t cnt, uint32_t flags)
324 {
325 	void *va = (__sparse_force void *)z_soc_cached_ptr(virt);
326 
327 	return sys_mm_drv_simple_map_array(va, phys, cnt, flags);
328 }
329 
sys_mm_drv_unmap_page(void * virt)330 int sys_mm_drv_unmap_page(void *virt)
331 {
332 	k_spinlock_key_t key;
333 	uint32_t entry_idx, bank_idx;
334 	uint16_t entry;
335 	uint16_t *tlb_entries = UINT_TO_POINTER(TLB_BASE);
336 	uintptr_t pa;
337 	int ret = 0;
338 
339 	/* Use cached virtual address */
340 	uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt));
341 
342 	/* Check bounds of virtual address space */
343 	CHECKIF((va < UNUSED_L2_START_ALIGNED) ||
344 		(va >= (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE))) {
345 		ret = -EINVAL;
346 		goto out;
347 	}
348 
349 	/* Make sure inputs are page-aligned */
350 	CHECKIF(!sys_mm_drv_is_addr_aligned(va)) {
351 		ret = -EINVAL;
352 		goto out;
353 	}
354 
355 	key = k_spin_lock(&tlb_lock);
356 
357 	/*
358 	 * Flush the cache to make sure the backing physical page
359 	 * has the latest data.
360 	 */
361 	sys_cache_data_flush_range(virt, CONFIG_MM_DRV_PAGE_SIZE);
362 
363 	entry_idx = get_tlb_entry_idx(va);
364 	/* Restore default entry settings */
365 	entry = pa_to_tlb_entry(va) | TLB_EXEC_BIT | TLB_WRITE_BIT;
366 	/* Clear the enable bit */
367 	entry &= ~TLB_ENABLE_BIT;
368 	tlb_entries[entry_idx] = entry;
369 
370 	pa = tlb_entry_to_pa(tlb_entries[entry_idx]);
371 
372 	/* Check bounds of physical address space. */
373 	/* Initial TLB mappings could point to non existing physical pages. */
374 	if ((pa >= L2_SRAM_BASE) && (pa < (L2_SRAM_BASE + L2_SRAM_SIZE))) {
375 		sys_mem_blocks_free_contiguous(&L2_PHYS_SRAM_REGION,
376 					       UINT_TO_POINTER(pa), 1);
377 
378 		bank_idx = get_hpsram_bank_idx(pa);
379 #ifdef CONFIG_SOC_INTEL_COMM_WIDGET
380 		used_pages--;
381 		sys_mm_drv_report_page_usage();
382 #endif
383 
384 		if (sys_mm_drv_bank_page_unmapped(&hpsram_bank[bank_idx]) == SRAM_BANK_PAGE_NUM) {
385 			sys_mm_drv_hpsram_pwr(bank_idx, false, false);
386 		}
387 	}
388 
389 	k_spin_unlock(&tlb_lock, key);
390 
391 out:
392 	return ret;
393 }
394 
sys_mm_drv_unmap_region(void * virt,size_t size)395 int sys_mm_drv_unmap_region(void *virt, size_t size)
396 {
397 	void *va = (__sparse_force void *)z_soc_cached_ptr(virt);
398 
399 	return sys_mm_drv_simple_unmap_region(va, size);
400 }
401 
sys_mm_drv_page_phys_get(void * virt,uintptr_t * phys)402 int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys)
403 {
404 	uint16_t *tlb_entries = UINT_TO_POINTER(TLB_BASE);
405 	uintptr_t ent;
406 	int ret = 0;
407 
408 	/* Use cached address */
409 	uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt));
410 
411 	CHECKIF(!sys_mm_drv_is_addr_aligned(va)) {
412 		ret = -EINVAL;
413 		goto out;
414 	}
415 
416 	/* Check bounds of virtual address space */
417 	CHECKIF((va < CONFIG_KERNEL_VM_BASE) ||
418 		(va >= (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE))) {
419 		ret = -EINVAL;
420 		goto out;
421 	}
422 
423 	ent = tlb_entries[get_tlb_entry_idx(va)];
424 
425 	if ((ent & TLB_ENABLE_BIT) != TLB_ENABLE_BIT) {
426 		ret = -EFAULT;
427 	} else {
428 		if (phys != NULL) {
429 			*phys = (ent & TLB_PADDR_MASK) *
430 				CONFIG_MM_DRV_PAGE_SIZE + TLB_PHYS_BASE;
431 		}
432 
433 		ret = 0;
434 	}
435 
436 out:
437 	return ret;
438 }
439 
sys_mm_drv_page_flag_get(void * virt,uint32_t * flags)440 int sys_mm_drv_page_flag_get(void *virt, uint32_t *flags)
441 {
442 	ARG_UNUSED(virt);
443 	int ret = 0;
444 
445 #if defined(CONFIG_SOC_SERIES_INTEL_ACE)
446 	uint16_t *tlb_entries = UINT_TO_POINTER(TLB_BASE);
447 	uint16_t ent;
448 
449 	/* Use cached address */
450 	uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt));
451 
452 	CHECKIF(!sys_mm_drv_is_addr_aligned(va)) {
453 		ret = -EINVAL;
454 		goto out;
455 	}
456 
457 	/* Check bounds of virtual address space */
458 	CHECKIF((va < CONFIG_KERNEL_VM_BASE) ||
459 		(va >= (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE))) {
460 		ret = -EINVAL;
461 		goto out;
462 	}
463 
464 	ent = tlb_entries[get_tlb_entry_idx(va)];
465 
466 	if ((ent & TLB_ENABLE_BIT) != TLB_ENABLE_BIT) {
467 		ret = -EFAULT;
468 	} else {
469 		*flags = tlb_perms_to_flags(ent);
470 	}
471 
472 out:
473 #else
474 	/*
475 	 * There are no caching mode, or R/W, or eXecution (etc.) bits.
476 	 * So just return 0.
477 	 */
478 
479 	*flags = 0U;
480 #endif
481 
482 	return ret;
483 }
484 
sys_mm_drv_remap_region(void * virt_old,size_t size,void * virt_new)485 int sys_mm_drv_remap_region(void *virt_old, size_t size,
486 			    void *virt_new)
487 {
488 	void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new);
489 	void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old);
490 
491 	return sys_mm_drv_simple_remap_region(va_old, size, va_new);
492 }
493 
sys_mm_drv_move_region(void * virt_old,size_t size,void * virt_new,uintptr_t phys_new)494 int sys_mm_drv_move_region(void *virt_old, size_t size, void *virt_new,
495 			   uintptr_t phys_new)
496 {
497 	k_spinlock_key_t key;
498 	size_t offset;
499 	int ret = 0;
500 
501 	virt_new = (__sparse_force void *)z_soc_cached_ptr(virt_new);
502 	virt_old = (__sparse_force void *)z_soc_cached_ptr(virt_old);
503 
504 	CHECKIF(!sys_mm_drv_is_virt_addr_aligned(virt_old) ||
505 		!sys_mm_drv_is_virt_addr_aligned(virt_new) ||
506 		!sys_mm_drv_is_size_aligned(size)) {
507 		ret = -EINVAL;
508 		goto out;
509 	}
510 
511 	if ((POINTER_TO_UINT(virt_new) >= POINTER_TO_UINT(virt_old)) &&
512 	    (POINTER_TO_UINT(virt_new) < (POINTER_TO_UINT(virt_old) + size))) {
513 		ret = -EINVAL; /* overlaps */
514 		goto out;
515 	}
516 
517 	/*
518 	 * The function's behavior has been updated to accept
519 	 * phys_new == NULL and get the physical addresses from
520 	 * the actual TLB instead of from the caller.
521 	 */
522 	if (phys_new != POINTER_TO_UINT(NULL) &&
523 	    !sys_mm_drv_is_addr_aligned(phys_new)) {
524 		ret = -EINVAL;
525 		goto out;
526 	}
527 
528 	key = k_spin_lock(&sys_mm_drv_common_lock);
529 
530 	if (!sys_mm_drv_is_virt_region_mapped(virt_old, size) ||
531 	    !sys_mm_drv_is_virt_region_unmapped(virt_new, size)) {
532 		ret = -EINVAL;
533 		goto unlock_out;
534 	}
535 
536 	for (offset = 0; offset < size; offset += CONFIG_MM_DRV_PAGE_SIZE) {
537 		uint8_t *va_old = (uint8_t *)virt_old + offset;
538 		uint8_t *va_new = (uint8_t *)virt_new + offset;
539 		uintptr_t pa;
540 		uint32_t flags;
541 		int ret2;
542 
543 		ret2 = sys_mm_drv_page_flag_get(va_old, &flags);
544 		if (ret2 != 0) {
545 			__ASSERT(false, "cannot query page flags %p\n", va_old);
546 
547 			ret = ret2;
548 			goto unlock_out;
549 		}
550 
551 		ret2 = sys_mm_drv_page_phys_get(va_old, &pa);
552 		if (ret2 != 0) {
553 			__ASSERT(false, "cannot query page paddr %p\n", va_old);
554 
555 			ret = ret2;
556 			goto unlock_out;
557 		}
558 
559 		/*
560 		 * Only map the new page when we can retrieve
561 		 * flags and phys addr of the old mapped page as We don't
562 		 * want to map with unknown random flags.
563 		 */
564 		ret2 = sys_mm_drv_map_page(va_new, pa, flags);
565 		if (ret2 != 0) {
566 			__ASSERT(false, "cannot map 0x%lx to %p\n", pa, va_new);
567 
568 			ret = ret2;
569 		}
570 
571 		ret2 = sys_mm_drv_unmap_page(va_old);
572 		if (ret2 != 0) {
573 			__ASSERT(false, "cannot unmap %p\n", va_old);
574 
575 			ret = ret2;
576 		}
577 	}
578 
579 unlock_out:
580 	k_spin_unlock(&sys_mm_drv_common_lock, key);
581 
582 out:
583 	/*
584 	 * Since move is done in virtual space, need to
585 	 * flush the cache to make sure the backing physical
586 	 * pages have the new data.
587 	 */
588 	sys_cache_data_flush_range(virt_new, size);
589 	sys_cache_data_flush_and_invd_range(virt_old, size);
590 
591 	return ret;
592 }
593 
sys_mm_drv_move_array(void * virt_old,size_t size,void * virt_new,uintptr_t * phys_new,size_t phys_cnt)594 int sys_mm_drv_move_array(void *virt_old, size_t size, void *virt_new,
595 			  uintptr_t *phys_new, size_t phys_cnt)
596 {
597 	int ret;
598 
599 	void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new);
600 	void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old);
601 
602 	ret = sys_mm_drv_simple_move_array(va_old, size, va_new,
603 					    phys_new, phys_cnt);
604 
605 	/*
606 	 * Since memcpy() is done in virtual space, need to
607 	 * flush the cache to make sure the backing physical
608 	 * pages have the new data.
609 	 */
610 	sys_cache_data_flush_range(va_new, size);
611 
612 	return ret;
613 }
614 
sys_mm_drv_mm_init(const struct device * dev)615 static int sys_mm_drv_mm_init(const struct device *dev)
616 {
617 	int ret;
618 
619 	ARG_UNUSED(dev);
620 
621 	/*
622 	 * Change size of avalible physical memory according to fw register information
623 	 * in runtime.
624 	 */
625 
626 	uint32_t avalible_memory_size = ace_hpsram_get_bank_count() * SRAM_BANK_SIZE;
627 
628 	L2_PHYS_SRAM_REGION.info.num_blocks = avalible_memory_size / CONFIG_MM_DRV_PAGE_SIZE;
629 
630 	ret = calculate_memory_regions(UNUSED_L2_START_ALIGNED);
631 	CHECKIF(ret != 0) {
632 		return ret;
633 	}
634 	/*
635 	 * Initialize memblocks that will store physical
636 	 * page usage. Initially all physical pages are
637 	 * mapped in linear way to virtual address space
638 	 * so mark all pages as allocated.
639 	 */
640 
641 	ret = sys_mem_blocks_get(&L2_PHYS_SRAM_REGION,
642 				 (void *) L2_SRAM_BASE, L2_SRAM_PAGES_NUM);
643 	CHECKIF(ret != 0) {
644 		return ret;
645 	}
646 
647 	/*
648 	 * Initialize refcounts for all HPSRAM banks
649 	 * as fully used because entire HPSRAM is powered on
650 	 * at system boot. Set reference count to a number
651 	 * of pages within single memory bank.
652 	 */
653 	for (int i = 0; i < L2_SRAM_BANK_NUM; i++) {
654 		sys_mm_drv_bank_init(&hpsram_bank[i],
655 				     SRAM_BANK_PAGE_NUM);
656 	}
657 #ifdef CONFIG_SOC_INTEL_COMM_WIDGET
658 	used_pages = L2_SRAM_BANK_NUM * SRAM_BANK_SIZE / CONFIG_MM_DRV_PAGE_SIZE;
659 #endif
660 
661 #ifdef CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM
662 	/*
663 	 * find virtual address range which are unused
664 	 * in the system
665 	 */
666 	if (L2_SRAM_BASE + L2_SRAM_SIZE < UNUSED_L2_START_ALIGNED ||
667 	    L2_SRAM_BASE > UNUSED_L2_START_ALIGNED) {
668 
669 		__ASSERT(false,
670 			 "unused l2 pointer is outside of l2 sram range %p\n",
671 			 (void *)UNUSED_L2_START_ALIGNED);
672 		return -EFAULT;
673 	}
674 
675 	/*
676 	 * Unmap all unused physical pages from the entire
677 	 * virtual address space to save power
678 	 */
679 	size_t unused_size = CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE -
680 			     UNUSED_L2_START_ALIGNED;
681 
682 	ret = sys_mm_drv_unmap_region(UINT_TO_POINTER(UNUSED_L2_START_ALIGNED),
683 				      unused_size);
684 
685 	/* Need to reset max pages statistics after unmap */
686 	for (int i = 0; i < L2_SRAM_BANK_NUM; i++) {
687 		sys_mm_drv_bank_stats_reset_max(&hpsram_bank[i]);
688 	}
689 #endif
690 
691 	/*
692 	 * Notify PMC about used HP-SRAM pages.
693 	 */
694 #ifdef CONFIG_SOC_INTEL_COMM_WIDGET
695 	sys_mm_drv_report_page_usage();
696 #endif
697 
698 	return 0;
699 }
700 
adsp_mm_save_context(void * storage_buffer)701 static void adsp_mm_save_context(void *storage_buffer)
702 {
703 	uint16_t entry;
704 	uint32_t entry_idx;
705 	int page_idx;
706 	uint32_t phys_addr;
707 	volatile uint16_t *tlb_entries = UINT_TO_POINTER(TLB_BASE);
708 	uint8_t *location = (uint8_t *) storage_buffer;
709 
710 	/* first, store the existing TLB */
711 	memcpy(location, UINT_TO_POINTER(TLB_BASE), TLB_SIZE);
712 	location += TLB_SIZE;
713 
714 	/* save context of all the pages */
715 	for (page_idx = 0; page_idx < L2_SRAM_PAGES_NUM; page_idx++) {
716 		phys_addr = POINTER_TO_UINT(L2_SRAM_BASE) +
717 				CONFIG_MM_DRV_PAGE_SIZE * page_idx;
718 		if (sys_mem_blocks_is_region_free(
719 				&L2_PHYS_SRAM_REGION,
720 				UINT_TO_POINTER(phys_addr), 1)) {
721 			/* skip a free page */
722 			continue;
723 		}
724 
725 		/* map the physical addr 1:1 to virtual address */
726 		entry_idx = get_tlb_entry_idx(phys_addr);
727 		entry = pa_to_tlb_entry(phys_addr);
728 
729 		if (((tlb_entries[entry_idx] & TLB_PADDR_MASK) != entry) ||
730 		    ((tlb_entries[entry_idx] & TLB_ENABLE_BIT) != TLB_ENABLE_BIT)) {
731 			/* this page needs remapping, invalidate cache to avoid stalled data
732 			 * all cache data has been flushed before
733 			 * do this for pages to remap only
734 			 */
735 			sys_cache_data_invd_range(UINT_TO_POINTER(phys_addr),
736 						  CONFIG_MM_DRV_PAGE_SIZE);
737 
738 			/* Enable the translation in the TLB entry */
739 			entry |= TLB_ENABLE_BIT;
740 
741 			/* map the page 1:1 virtual to physical */
742 			tlb_entries[entry_idx] = entry;
743 		}
744 
745 		/* save physical address */
746 		*((uint32_t *) location) = phys_addr;
747 		location += sizeof(uint32_t);
748 
749 		/* save the page */
750 		memcpy(location,
751 			UINT_TO_POINTER(phys_addr),
752 			CONFIG_MM_DRV_PAGE_SIZE);
753 		location += CONFIG_MM_DRV_PAGE_SIZE;
754 	}
755 
756 	/* write end marker - a null address */
757 	*((uint32_t *) location) = 0;
758 	location += sizeof(uint32_t);
759 
760 	sys_cache_data_flush_range(
761 		storage_buffer,
762 		(uint32_t)location - (uint32_t)storage_buffer);
763 
764 
765 	/* system state is frozen, ready to poweroff, no further changes will be stored */
766 }
767 
adsp_mm_restore_context(void * storage_buffer)768 __imr void adsp_mm_restore_context(void *storage_buffer)
769 {
770 	/* at this point system must be in a startup state
771 	 * TLB must be set to initial state
772 	 * Note! the stack must NOT be in the area being restored
773 	 */
774 	uint32_t phys_addr;
775 	uint8_t *location;
776 
777 	/* restore context of all the pages */
778 	location = (uint8_t *) storage_buffer + TLB_SIZE;
779 
780 	phys_addr = *((uint32_t *) location);
781 
782 	while (phys_addr != 0) {
783 		uint32_t phys_addr_uncached =
784 				POINTER_TO_UINT(z_soc_uncached_ptr(
785 					(void __sparse_cache *)UINT_TO_POINTER(phys_addr)));
786 		uint32_t phys_offset = phys_addr - L2_SRAM_BASE;
787 		uint32_t bank_idx = (phys_offset / SRAM_BANK_SIZE);
788 
789 		location += sizeof(uint32_t);
790 
791 		/* turn on memory bank power, wait till the power is on */
792 		__ASSERT_NO_MSG(bank_idx <= ace_hpsram_get_bank_count());
793 		HPSRAM_REGS(bank_idx)->HSxPGCTL = 0;
794 		while (HPSRAM_REGS(bank_idx)->HSxPGISTS == 1) {
795 			/* k_busy_wait cannot be used here - not available */
796 		}
797 
798 		/* copy data to uncached alias and invalidate cache */
799 		bmemcpy(UINT_TO_POINTER(phys_addr_uncached),
800 			location,
801 			CONFIG_MM_DRV_PAGE_SIZE);
802 		sys_cache_data_invd_range(UINT_TO_POINTER(phys_addr), CONFIG_MM_DRV_PAGE_SIZE);
803 
804 		location += CONFIG_MM_DRV_PAGE_SIZE;
805 		phys_addr = *((uint32_t *) location);
806 	}
807 
808 	/* restore original TLB table */
809 	bmemcpy(UINT_TO_POINTER(TLB_BASE), storage_buffer, TLB_SIZE);
810 
811 	/* HPSRAM memory is restored */
812 }
813 
adsp_mm_get_storage_size(void)814 static uint32_t adsp_mm_get_storage_size(void)
815 {
816 	/*
817 	 * FIXME - currently the function returns a maximum possible size of the buffer
818 	 * as L3 memory is generally a huge area its OK (and fast)
819 	 * in future the function may go through the mapping and calculate a required size
820 	 */
821 	return	L2_SRAM_SIZE + TLB_SIZE + (L2_SRAM_PAGES_NUM * sizeof(void *))
822 		+ sizeof(void *);
823 }
824 
825 static const struct intel_adsp_tlb_api adsp_tlb_api_func = {
826 	.save_context = adsp_mm_save_context,
827 	.get_storage_size = adsp_mm_get_storage_size
828 };
829 
830 DEVICE_DT_DEFINE(DT_INST(0, intel_adsp_mtl_tlb),
831 		sys_mm_drv_mm_init,
832 		NULL,
833 		NULL,
834 		NULL,
835 		POST_KERNEL,
836 		0,
837 		&adsp_tlb_api_func);
838