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