1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2018 Intel Corporation. All rights reserved.
4 //
5 // Author: Marcin Maka <marcin.maka@linux.intel.com>
6
7 #include <sof/lib/dai.h>
8 #include <rtos/alloc.h>
9 #include <sof/lib/cpu.h>
10 #include <sof/lib/memory.h>
11 #include <sof/lib/uuid.h>
12 #include <rtos/spinlock.h>
13 #include <sof/trace/trace.h>
14 #include <ipc/topology.h>
15 #include <ipc/dai.h>
16 #include <user/trace.h>
17 #include <errno.h>
18 #include <stddef.h>
19 #include <stdint.h>
20
21 #if CONFIG_ZEPHYR_NATIVE_DRIVERS
22 #include <zephyr/device.h>
23 #include <zephyr/drivers/dai.h>
24 #endif
25 LOG_MODULE_REGISTER(dai, CONFIG_SOF_LOG_LEVEL);
26
27 /* 06711c94-d37d-4a76-b302-bbf6944fdd2b */
28 DECLARE_SOF_UUID("dai", dai_uuid, 0x06711c94, 0xd37d, 0x4a76,
29 0xb3, 0x02, 0xbb, 0xf6, 0x94, 0x4f, 0xdd, 0x2b);
30
31 DECLARE_TR_CTX(dai_tr, SOF_UUID(dai_uuid), LOG_LEVEL_INFO);
32
33 struct dai_group_list {
34 struct list_item list;
35 } __aligned(PLATFORM_DCACHE_ALIGN);
36
37 static struct dai_group_list *groups[CONFIG_CORE_COUNT];
38
dai_group_list_get(int core_id)39 static struct dai_group_list *dai_group_list_get(int core_id)
40 {
41 struct dai_group_list *group_list = groups[core_id];
42
43 if (!group_list) {
44 group_list = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM,
45 sizeof(*group_list));
46
47 groups[core_id] = group_list;
48 list_init(&group_list->list);
49 }
50
51 return group_list;
52 }
53
dai_group_find(uint32_t group_id)54 static struct dai_group *dai_group_find(uint32_t group_id)
55 {
56 struct list_item *dai_groups;
57 struct list_item *group_item;
58 struct dai_group *group = NULL;
59
60 dai_groups = &dai_group_list_get(cpu_get_id())->list;
61
62 list_for_item(group_item, dai_groups) {
63 group = container_of(group_item, struct dai_group, list);
64
65 if (group->group_id == group_id)
66 break;
67
68 group = NULL;
69 }
70
71 return group;
72 }
73
dai_group_alloc()74 static struct dai_group *dai_group_alloc()
75 {
76 struct list_item *dai_groups = &dai_group_list_get(cpu_get_id())->list;
77 struct dai_group *group;
78
79 group = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM,
80 sizeof(*group));
81
82 list_item_prepend(&group->list, dai_groups);
83
84 return group;
85 }
86
dai_group_get(uint32_t group_id,uint32_t flags)87 struct dai_group *dai_group_get(uint32_t group_id, uint32_t flags)
88 {
89 struct dai_group *group;
90
91 if (!group_id) {
92 tr_err(&dai_tr, "dai_group_get(): invalid group_id %u",
93 group_id);
94 return NULL;
95 }
96
97 /* Check if this group already exists */
98 group = dai_group_find(group_id);
99
100 /* Check if there's a released and now unused group */
101 if (!group)
102 group = dai_group_find(0);
103
104 /* Group doesn't exist, let's allocate and initialize it */
105 if (!group && flags & DAI_CREAT)
106 group = dai_group_alloc();
107
108 if (group) {
109 /* Group might've been previously unused */
110 if (!group->group_id)
111 group->group_id = group_id;
112
113 group->num_dais++;
114 } else {
115 tr_err(&dai_tr, "dai_group_get(): failed to get group_id %u",
116 group_id);
117 }
118
119 return group;
120 }
121
dai_group_put(struct dai_group * group)122 void dai_group_put(struct dai_group *group)
123 {
124 group->num_dais--;
125
126 /* Mark as unused if there are no more DAIs in this group */
127 if (!group->num_dais)
128 group->group_id = 0;
129 }
130
131 #if CONFIG_ZEPHYR_NATIVE_DRIVERS
132
133 #define GET_DEVICE_LIST(node) DEVICE_DT_GET(node),
134
135 const struct device *zephyr_dev[] = {
136 #if CONFIG_DAI_INTEL_SSP
137 DT_FOREACH_STATUS_OKAY(intel_ssp_dai, GET_DEVICE_LIST)
138 #endif
139 #if CONFIG_DAI_INTEL_DMIC
140 DT_FOREACH_STATUS_OKAY(intel_dai_dmic, GET_DEVICE_LIST)
141 #endif
142 #if CONFIG_DAI_INTEL_ALH
143 DT_FOREACH_STATUS_OKAY(intel_alh_dai, GET_DEVICE_LIST)
144 #endif
145 #if CONFIG_DAI_INTEL_HDA
146 DT_FOREACH_STATUS_OKAY(intel_hda_dai, GET_DEVICE_LIST)
147 #endif
148 };
149
dai_get_zephyr_device(uint32_t type,uint32_t index)150 static const struct device *dai_get_zephyr_device(uint32_t type, uint32_t index)
151 {
152 struct dai_config cfg;
153 int dir;
154 int i;
155
156 dir = (type == SOF_DAI_INTEL_DMIC) ? DAI_DIR_RX : DAI_DIR_BOTH;
157
158 for (i = 0; i < ARRAY_SIZE(zephyr_dev); i++) {
159 if (dai_config_get(zephyr_dev[i], &cfg, dir))
160 continue;
161 if (cfg.type == type && cfg.dai_index == index)
162 return zephyr_dev[i];
163 }
164
165 return NULL;
166 }
167
dai_set_device_params(struct dai * d)168 static void dai_set_device_params(struct dai *d)
169 {
170 switch (d->type) {
171 case SOF_DAI_INTEL_SSP:
172 d->dma_dev = DMA_DEV_SSP;
173 d->dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP;
174 break;
175 case SOF_DAI_INTEL_DMIC:
176 d->dma_dev = DMA_DEV_DMIC;
177 d->dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP;
178 break;
179 case SOF_DAI_INTEL_ALH:
180 d->dma_dev = DMA_DEV_ALH;
181 d->dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP;
182 break;
183 case SOF_DAI_INTEL_HDA:
184 d->dma_dev = DMA_DEV_HDA;
185 d->dma_caps = DMA_CAP_HDA;
186 break;
187 default:
188 break;
189 }
190 }
191
192 /* called from ipc/ipc3/handler.c and some platform.c files */
dai_get(uint32_t type,uint32_t index,uint32_t flags)193 struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags)
194 {
195 const struct device *dev;
196 struct dai *d;
197
198 dev = dai_get_zephyr_device(type, index);
199 if (!dev)
200 return NULL;
201
202 d = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(struct dai));
203 if (!d)
204 return NULL;
205
206 d->index = index;
207 d->type = type;
208 d->dev = dev;
209
210 dai_set_device_params(d);
211
212 if (dai_probe(d->dev)) {
213 rfree(d);
214 return NULL;
215 }
216
217 return d;
218 }
219
220 /* called from src/ipc/ipc3/handler.c */
dai_put(struct dai * dai)221 void dai_put(struct dai *dai)
222 {
223 int ret;
224
225 ret = dai_remove(dai->dev);
226 if (ret < 0) {
227 tr_err(&dai_tr, "dai_put_zephyr: index %d failed ret = %d",
228 dai->index, ret);
229 }
230
231 rfree(dai);
232 }
233 #else
dai_find_type(uint32_t type)234 static inline const struct dai_type_info *dai_find_type(uint32_t type)
235 {
236 const struct dai_info *info = dai_info_get();
237 const struct dai_type_info *dti;
238
239 for (dti = info->dai_type_array;
240 dti < info->dai_type_array + info->num_dai_types; dti++) {
241 if (dti->type == type)
242 return dti;
243 }
244 return NULL;
245 }
246
dai_get(uint32_t type,uint32_t index,uint32_t flags)247 struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags)
248 {
249 int ret = 0;
250 const struct dai_type_info *dti;
251 struct dai *d;
252 k_spinlock_key_t key;
253
254 dti = dai_find_type(type);
255 if (!dti)
256 return NULL; /* type not found */
257
258 for (d = dti->dai_array; d < dti->dai_array + dti->num_dais; d++) {
259 if (d->index != index) {
260 continue;
261 }
262 /* device created? */
263 key = k_spin_lock(&d->lock);
264 if (d->sref == 0) {
265 if (flags & DAI_CREAT)
266 ret = dai_probe(d);
267 else
268 ret = -ENODEV;
269 }
270 if (!ret)
271 d->sref++;
272
273 tr_info(&dai_tr, "dai_get type %d index %d new sref %d",
274 type, index, d->sref);
275
276 k_spin_unlock(&d->lock, key);
277
278 return !ret ? d : NULL;
279 }
280 tr_err(&dai_tr, "dai_get: type %d index %d not found", type, index);
281 return NULL;
282 }
283
dai_put(struct dai * dai)284 void dai_put(struct dai *dai)
285 {
286 int ret;
287 k_spinlock_key_t key;
288
289 key = k_spin_lock(&dai->lock);
290 if (--dai->sref == 0) {
291 ret = dai_remove(dai);
292 if (ret < 0) {
293 tr_err(&dai_tr, "dai_put: type %d index %d dai_remove() failed ret = %d",
294 dai->drv->type, dai->index, ret);
295 }
296 }
297 tr_info(&dai_tr, "dai_put type %d index %d new sref %d",
298 dai->drv->type, dai->index, dai->sref);
299 k_spin_unlock(&dai->lock, key);
300 }
301 #endif
302