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