1 /* Copyright (c) 2025 Intel Corporation. All rights reserved.
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 
5 #include <adsp_memory.h>
6 #include <adsp_debug_window.h>
7 #include <zephyr/cache.h>
8 
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(debug_window, CONFIG_SOC_LOG_LEVEL);
11 
12 struct adsp_debug_window {
13 	struct adsp_dw_desc descs[ADSP_DW_DESC_COUNT];
14 	uint8_t reserved[ADSP_DW_PAGE0_SLOT_OFFSET -
15 			 ADSP_DW_DESC_COUNT * sizeof(struct adsp_dw_desc)];
16 	uint8_t partial_page0[ADSP_DW_SLOT_SIZE - ADSP_DW_PAGE0_SLOT_OFFSET];
17 	uint8_t slots[ADSP_DW_SLOT_COUNT][ADSP_DW_SLOT_SIZE];
18 } __packed;
19 
20 #define WIN2_MBASE		DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window2), memory))
21 #define WIN2_SLOTS		((HP_SRAM_WIN2_SIZE / ADSP_DW_PAGE_SIZE) - 1)
22 #define ADSP_DW_FULL_SLOTS	MIN(WIN2_SLOTS, ADSP_DW_SLOT_COUNT)
23 
24 #define ADSP_DW ((struct adsp_debug_window *) \
25 		  (sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \
26 				     (WIN2_MBASE + WIN2_OFFSET))))
27 
adsp_dw_find_unused_slot(bool prefer_partial)28 static int adsp_dw_find_unused_slot(bool prefer_partial)
29 {
30 	int i;
31 
32 	if (prefer_partial) {
33 		if (ADSP_DW->descs[ADSP_DW_SLOT_COUNT].type == ADSP_DW_SLOT_UNUSED) {
34 			return ADSP_DW_SLOT_COUNT;
35 		}
36 	}
37 
38 	for (i = 0; i < ADSP_DW_FULL_SLOTS; i++) {
39 		if (ADSP_DW->descs[i].type == ADSP_DW_SLOT_UNUSED) {
40 			return i;
41 		}
42 	}
43 
44 	if (!prefer_partial) {
45 		if (ADSP_DW->descs[ADSP_DW_SLOT_COUNT].type == ADSP_DW_SLOT_UNUSED) {
46 			return ADSP_DW_SLOT_COUNT;
47 		}
48 	}
49 
50 	return -ENOENT;
51 }
52 
adsp_dw_find_slot_by_type(uint32_t type)53 static int adsp_dw_find_slot_by_type(uint32_t type)
54 {
55 	int i;
56 
57 	for (i = 0; i < ADSP_DW_FULL_SLOTS; i++) {
58 		if (ADSP_DW->descs[i].type == type) {
59 			return i;
60 		}
61 	}
62 
63 	if (ADSP_DW->descs[ADSP_DW_SLOT_COUNT].type == type) {
64 		return ADSP_DW_SLOT_COUNT;
65 	}
66 
67 	return -ENOENT;
68 }
69 
adsp_dw_request_slot(struct adsp_dw_desc * dw_desc,size_t * slot_size)70 void *adsp_dw_request_slot(struct adsp_dw_desc *dw_desc, size_t *slot_size)
71 {
72 	int slot_idx;
73 
74 	if (!dw_desc->type) {
75 		return NULL;
76 	}
77 
78 	/* Check if a slot has been allocated for this type */
79 	slot_idx = adsp_dw_find_slot_by_type(dw_desc->type);
80 	if (slot_idx >= 0) {
81 		if (slot_size) {
82 			*slot_size = ADSP_DW_SLOT_SIZE;
83 		}
84 
85 		if (slot_idx == ADSP_DW_SLOT_COUNT) {
86 			if (slot_size) {
87 				*slot_size -= ADSP_DW_PAGE0_SLOT_OFFSET;
88 			}
89 			return ADSP_DW->partial_page0;
90 		}
91 
92 		return ADSP_DW->slots[slot_idx];
93 	}
94 
95 	/* Look for an empty slot */
96 	slot_idx = adsp_dw_find_unused_slot(!!slot_size);
97 	if (slot_idx < 0) {
98 		LOG_INF("No available slot for %#x", dw_desc->type);
99 		return NULL;
100 	}
101 
102 	ADSP_DW->descs[slot_idx].resource_id = dw_desc->resource_id;
103 	ADSP_DW->descs[slot_idx].type = dw_desc->type;
104 	ADSP_DW->descs[slot_idx].vma = dw_desc->vma;
105 
106 	if (slot_size) {
107 		*slot_size = ADSP_DW_SLOT_SIZE;
108 	}
109 
110 	if (slot_idx == ADSP_DW_SLOT_COUNT) {
111 		if (slot_size) {
112 			*slot_size -= ADSP_DW_PAGE0_SLOT_OFFSET;
113 		}
114 
115 		LOG_DBG("Allocating partial page0 to be used for %#x", dw_desc->type);
116 
117 		return ADSP_DW->partial_page0;
118 	}
119 
120 	LOG_DBG("Allocating debug slot %d to be used for %#x", slot_idx, dw_desc->type);
121 
122 	return ADSP_DW->slots[slot_idx];
123 }
124 
adsp_dw_seize_slot(uint32_t slot_index,struct adsp_dw_desc * dw_desc,size_t * slot_size)125 void *adsp_dw_seize_slot(uint32_t slot_index, struct adsp_dw_desc *dw_desc,
126 				  size_t *slot_size)
127 {
128 	if ((slot_index >= ADSP_DW_FULL_SLOTS && slot_index != ADSP_DW_SLOT_COUNT) ||
129 	    !dw_desc->type) {
130 		return NULL;
131 	}
132 
133 	if (slot_index < ADSP_DW_FULL_SLOTS) {
134 		if (ADSP_DW->descs[slot_index].type != ADSP_DW_SLOT_UNUSED) {
135 			LOG_INF("Overtaking debug slot %d, used by %#x for %#x", slot_index,
136 				ADSP_DW->descs[slot_index].type, dw_desc->type);
137 		}
138 
139 		if (slot_size) {
140 			*slot_size = ADSP_DW_SLOT_SIZE;
141 		}
142 
143 		ADSP_DW->descs[slot_index].resource_id = dw_desc->resource_id;
144 		ADSP_DW->descs[slot_index].type = dw_desc->type;
145 		ADSP_DW->descs[slot_index].vma = dw_desc->vma;
146 
147 		return ADSP_DW->slots[slot_index];
148 	}
149 
150 	/* The caller is not prepared to handle partial debug slot */
151 	if (!slot_size) {
152 		return NULL;
153 	}
154 
155 	if (ADSP_DW->descs[slot_index].type != ADSP_DW_SLOT_UNUSED) {
156 		LOG_INF("Overtaking partial page0, used by %#x for %#x",
157 			ADSP_DW->descs[slot_index].type, dw_desc->type);
158 	}
159 
160 	*slot_size = ADSP_DW_SLOT_SIZE - ADSP_DW_PAGE0_SLOT_OFFSET;
161 
162 	ADSP_DW->descs[slot_index].resource_id = dw_desc->resource_id;
163 	ADSP_DW->descs[slot_index].type = dw_desc->type;
164 	ADSP_DW->descs[slot_index].vma = dw_desc->vma;
165 
166 	return ADSP_DW->partial_page0;
167 }
168 
adsp_dw_release_slot(uint32_t type)169 void adsp_dw_release_slot(uint32_t type)
170 {
171 	int slot_idx;
172 
173 	slot_idx = adsp_dw_find_slot_by_type(type);
174 	if (slot_idx < 0) {
175 		return;
176 	}
177 
178 	if (slot_idx == ADSP_DW_SLOT_COUNT) {
179 		LOG_DBG("Releasing partial page0 used by %#x", type);
180 	} else {
181 		LOG_DBG("Releasing debug slot %d used by %#x", slot_idx, type);
182 	}
183 
184 	ADSP_DW->descs[slot_idx].resource_id = 0;
185 	ADSP_DW->descs[slot_idx].type = ADSP_DW_SLOT_UNUSED;
186 	ADSP_DW->descs[slot_idx].vma = 0;
187 }
188