1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2016 Intel Corporation. All rights reserved.
4 *
5 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6 * Keyon Jie <yang.jie@linux.intel.com>
7 */
8
9 /**
10 * \file include/sof/lib/dai.h
11 * \brief DAI Drivers definition
12 * \author Liam Girdwood <liam.r.girdwood@linux.intel.com>
13 * \author Keyon Jie <yang.jie@linux.intel.com>
14 */
15
16 #ifndef __SOF_LIB_DAI_H__
17 #define __SOF_LIB_DAI_H__
18
19 #include <platform/lib/dai.h>
20 #include <sof/bit.h>
21 #include <sof/list.h>
22 #include <sof/lib/io.h>
23 #include <sof/lib/memory.h>
24 #include <sof/lib/dma.h>
25 #include <sof/list.h>
26 #include <sof/sof.h>
27 #include <sof/spinlock.h>
28 #include <sof/trace/trace.h>
29 #include <sof/ipc/topology.h>
30 #include <sof/audio/pcm_converter.h>
31 #include <sof/audio/ipc-config.h>
32 #include <errno.h>
33 #include <stddef.h>
34 #include <stdint.h>
35
36 struct dai;
37 struct sof_ipc_stream_params;
38
39 /** \addtogroup sof_dai_drivers DAI Drivers
40 * DAI Drivers API specification.
41 * @{
42 */
43
44 #define DAI_CLOCK_IN 0
45 #define DAI_CLOCK_OUT 1
46
47 #define DAI_DIR_PLAYBACK 0
48 #define DAI_DIR_CAPTURE 1
49
50 #define DAI_NUM_SLOT_MAPS 8
51
52 #define DAI_INFO_TYPE 0
53 #define DAI_INFO_DMA_CAPS 1
54 #define DAI_INFO_DMA_DEV 2
55
56 /* DAI flags */
57
58 /** \brief IRQ used for copy() timer */
59 #define DAI_FLAGS_IRQ_CB BIT(0)
60
61 /* DAI get() flags */
62
63 /** \brief If the device does not exist it will be created */
64 #define DAI_CREAT BIT(0)
65
66 /**
67 * \brief DAI operations - all optional
68 *
69 * DAI drivers may allocate private data,
70 * which can be set with 'dai_set_drvdata' and retrieved with 'dai_get_drvdata'.
71 * If a single DAI instance can have multiple DMA links and/or there is
72 * some other possibility of the same instance being used in multiple
73 * contexts at the same time, the private data should be allocated in the
74 * SOF_MEM_ZONE_SHARED.
75 */
76 struct dai_ops {
77 int (*set_config)(struct dai *dai, struct ipc_config_dai *config,
78 void *spec_config);
79 int (*trigger)(struct dai *dai, int cmd, int direction);
80 int (*pm_context_restore)(struct dai *dai);
81 int (*pm_context_store)(struct dai *dai);
82 int (*get_hw_params)(struct dai *dai,
83 struct sof_ipc_stream_params *params, int dir);
84 int (*hw_params)(struct dai *dai, struct sof_ipc_stream_params *params);
85 int (*get_handshake)(struct dai *dai, int direction, int stream_id);
86 int (*get_fifo)(struct dai *dai, int direction, int stream_id);
87 int (*probe)(struct dai *dai);
88 int (*remove)(struct dai *dai);
89 };
90
91 struct timestamp_cfg {
92 uint32_t walclk_rate; /* Rate in Hz, e.g. 19200000 */
93 int type; /* SSP, DMIC, HDA, etc. */
94 int direction; /* Playback, capture */
95 int index; /* For SSPx to select correct timestamp register */
96 int dma_id; /* GPDMA id*/
97 int dma_chan_index; /* Used GPDMA channel */
98 int dma_chan_count; /* Channels in single GPDMA */
99 };
100
101 struct timestamp_data {
102 uint64_t walclk; /* Wall clock */
103 uint64_t sample; /* Sample count */
104 uint32_t walclk_rate; /* Rate in Hz, e.g. 19200000 */
105 };
106
107 struct timestamp_ops {
108 int (*ts_config)(struct dai *dai, struct timestamp_cfg *cfg);
109 int (*ts_start)(struct dai *dai, struct timestamp_cfg *cfg);
110 int (*ts_stop)(struct dai *dai, struct timestamp_cfg *cfg);
111 int (*ts_get)(struct dai *dai, struct timestamp_cfg *cfg,
112 struct timestamp_data *tsd);
113 };
114
115 struct dai_driver {
116 uint32_t type; /**< type, one of SOF_DAI_... */
117 const struct sof_uuid_entry *uid;
118 struct tr_ctx *tctx;
119 uint32_t dma_caps;
120 uint32_t dma_dev;
121 struct dai_ops ops;
122 struct timestamp_ops ts_ops;
123 };
124
125 /**
126 * \brief DAI slot map to audio channel
127 */
128 struct dai_slot_map {
129 uint32_t channel; /**< channel ID - CHAN_ID_ */
130 uint32_t slot; /**< physical slot index */
131 };
132
133 struct dai_plat_fifo_data {
134 uint32_t offset;
135 uint32_t width;
136 uint32_t depth;
137 uint32_t watermark;
138 uint32_t handshake;
139 };
140
141 /**
142 * \brief DAI platform data
143 */
144 struct dai_plat_data {
145 uint32_t base;
146 int irq;
147 const char *irq_name;
148 uint32_t flags;
149 struct dai_plat_fifo_data fifo[2];
150 };
151
152 /**
153 * \brief DAI runtime data
154 */
155 struct dai_data {
156 /* local DMA config */
157 struct dma_chan_data *chan;
158 uint32_t stream_id;
159 struct dma_sg_config config;
160 struct comp_buffer *dma_buffer;
161 struct comp_buffer *local_buffer;
162 struct timestamp_cfg ts_config;
163 struct dai *dai;
164 struct dma *dma;
165 struct dai_group *group; /**< NULL if no group assigned */
166 int xrun; /* true if we are doing xrun recovery */
167
168 pcm_converter_func process; /* processing function */
169
170 uint32_t dai_pos_blks; /* position in bytes (nearest block) */
171 uint64_t start_position; /* position on start */
172 uint32_t period_bytes; /**< number of bytes per one period */
173
174 /* host can read back this value without IPC */
175 uint64_t *dai_pos;
176
177 struct ipc_config_dai ipc_config; /* generic common config */
178 void *dai_spec_config; /* dai specific config from the host */
179
180 uint64_t wallclock; /* wall clock at stream start */
181 };
182
183 struct dai {
184 uint32_t index; /**< index */
185 spinlock_t lock; /**< locking mechanism */
186 int sref; /**< simple ref counter, guarded by lock */
187 struct dai_plat_data plat_data;
188 const struct dai_driver *drv;
189 void *priv_data;
190 };
191
192 /**
193 * \brief Array of DAIs grouped by type.
194 */
195 struct dai_type_info {
196 uint32_t type; /**< Type */
197 struct dai *dai_array; /**< Array of DAIs */
198 size_t num_dais; /**< Number of elements in dai_array */
199 };
200
201 /* dai tracing */
202 #define trace_dai_drv_get_tr_ctx(drv_p) ((drv_p)->tctx)
203 #define trace_dai_drv_get_id(drv_p) (-1)
204 #define trace_dai_drv_get_subid(drv_p) (-1)
205
206 #define trace_dai_get_tr_ctx(dai_p) ((dai_p)->drv->tctx)
207 #define trace_dai_get_id(dai_p) ((dai_p)->drv->type)
208 #define trace_dai_get_subid(dai_p) ((dai_p)->index)
209
210 /* class (driver) level (no device object) tracing */
211
212 #define dai_cl_err(drv_p, __e, ...) \
213 trace_dev_err(trace_dai_dvr_get_tr_ctx, \
214 trace_dai_drv_get_id, \
215 trace_dai_drv_get_subid, \
216 drv_p, __e, ##__VA_ARGS__)
217
218 #define dai_cl_warn(drv_p, __e, ...) \
219 trace_dev_warn(trace_dai_drv_get_tr_ctx,\
220 trace_dai_drv_get_id, \
221 trace_dai_drv_get_subid, \
222 drv_p, __e, ##__VA_ARGS__)
223
224 #define dai_cl_info(drv_p, __e, ...) \
225 trace_dev_info(trace_dai_drv_get_tr_ctx,\
226 trace_dai_drv_get_id, \
227 trace_dai_drv_get_subid, \
228 drv_p, __e, ##__VA_ARGS__)
229
230 #define dai_cl_dbg(drv_p, __e, ...) \
231 trace_dev_dbg(trace_dai_drv_get_tr_ctx, \
232 trace_dai_drv_get_id, \
233 trace_dai_drv_get_subid, \
234 drv_p, __e, ##__VA_ARGS__)
235
236 /* device tracing */
237
238 #define dai_err(dai_p, __e, ...) \
239 trace_dev_err(trace_dai_get_tr_ctx, \
240 trace_dai_get_id, \
241 trace_dai_get_subid, dai_p, __e, ##__VA_ARGS__)
242
243 #define dai_warn(dai_p, __e, ...) \
244 trace_dev_warn(trace_dai_get_tr_ctx, \
245 trace_dai_get_id, \
246 trace_dai_get_subid, dai_p, __e, ##__VA_ARGS__)
247
248 #define dai_info(dai_p, __e, ...) \
249 trace_dev_info(trace_dai_get_tr_ctx, \
250 trace_dai_get_id, \
251 trace_dai_get_subid, dai_p, __e, ##__VA_ARGS__)
252
253 #define dai_dbg(dai_p, __e, ...) \
254 trace_dev_dbg(trace_dai_get_tr_ctx, \
255 trace_dai_get_id, \
256 trace_dai_get_subid, dai_p, __e, ##__VA_ARGS__)
257
258 /**
259 * \brief API to request DAI group
260 *
261 * Returns a DAI group for the given ID and
262 * increments the counter of DAIs in the group.
263 *
264 * If a group for the given ID doesn't exist,
265 * it will either return NULL or allocate a new group structure
266 * if the CREATE flag is supplied.
267 *
268 * \param[in] group_id Group ID
269 * \param[in] flags Flags (CREATE)
270 */
271 struct dai_group *dai_group_get(uint32_t group_id, uint32_t flags);
272
273 /**
274 * \brief API to release DAI group
275 *
276 * Decrements the DAI counter inside the group.
277 *
278 * \param[in] group Group
279 */
280 void dai_group_put(struct dai_group *group);
281
282 /**
283 * \brief DAI group information
284 */
285 struct dai_group {
286 /**
287 * Group ID
288 */
289 uint32_t group_id;
290
291 /**
292 * Number of DAIs in this group
293 */
294 uint32_t num_dais;
295
296 /**
297 * Number of DAIs to receive a trigger before processing begins
298 */
299 uint32_t trigger_counter;
300
301 /**
302 * Trigger command to propagate
303 */
304 int trigger_cmd;
305
306 /**
307 * Last trigger error
308 */
309 int trigger_ret;
310
311 /**
312 * Group list
313 */
314 struct list_item list;
315 };
316
317 /**
318 * \brief Holds information about array of DAIs grouped by type.
319 */
320 struct dai_info {
321 const struct dai_type_info *dai_type_array;
322 size_t num_dai_types;
323 };
324
325 /**
326 * \brief API to initialize a platform DAI.
327 *
328 * \param[in] sof Pointer to firmware main context.
329 */
330 int dai_init(struct sof *sof);
331
332 /**
333 * \brief API to request a platform DAI.
334 *
335 * \param[in] type Type of requested DAI.
336 * \param[in] index Index of requested DAI.
337 * \param[in] flags Flags (CREATE)
338 */
339 struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags);
340
341 /**
342 * \brief API to release a platform DAI.
343 *
344 * @param[in] dai DAI to relese.
345 */
346 void dai_put(struct dai *dai);
347
348 #define dai_set_drvdata(dai, data) \
349 (dai->priv_data = data)
350 #define dai_get_drvdata(dai) \
351 dai->priv_data
352 #define dai_base(dai) \
353 dai->plat_data.base
354 #define dai_irq(dai) \
355 dai->plat_data.irq
356 #define dai_fifo(dai, direction) \
357 dai->plat_data.fifo[direction].offset
358
359 /**
360 * \brief Digital Audio interface formatting
361 */
dai_set_config(struct dai * dai,struct ipc_config_dai * config,void * spec_config)362 static inline int dai_set_config(struct dai *dai, struct ipc_config_dai *config,
363 void *spec_config)
364 {
365 int ret = dai->drv->ops.set_config(dai, config, spec_config);
366
367 return ret;
368 }
369
370 /**
371 * \brief Digital Audio interface trigger
372 */
dai_trigger(struct dai * dai,int cmd,int direction)373 static inline int dai_trigger(struct dai *dai, int cmd, int direction)
374 {
375 int ret = dai->drv->ops.trigger(dai, cmd, direction);
376
377 return ret;
378 }
379
380 /**
381 * \brief Digital Audio interface PM context store
382 */
dai_pm_context_store(struct dai * dai)383 static inline int dai_pm_context_store(struct dai *dai)
384 {
385 int ret = dai->drv->ops.pm_context_store(dai);
386
387 return ret;
388 }
389
390 /**
391 * \brief Digital Audio interface PM context restore
392 */
dai_pm_context_restore(struct dai * dai)393 static inline int dai_pm_context_restore(struct dai *dai)
394 {
395 int ret = dai->drv->ops.pm_context_restore(dai);
396
397 return ret;
398 }
399
400 /**
401 * \brief Get Digital Audio interface stream parameters
402 */
dai_get_hw_params(struct dai * dai,struct sof_ipc_stream_params * params,int dir)403 static inline int dai_get_hw_params(struct dai *dai,
404 struct sof_ipc_stream_params *params,
405 int dir)
406 {
407 int ret = dai->drv->ops.get_hw_params(dai, params, dir);
408
409 return ret;
410 }
411
412 /**
413 * \brief Configure Digital Audio interface stream parameters
414 */
dai_hw_params(struct dai * dai,struct sof_ipc_stream_params * params)415 static inline int dai_hw_params(struct dai *dai,
416 struct sof_ipc_stream_params *params)
417 {
418 int ret = 0;
419
420 if (dai->drv->ops.hw_params)
421 ret = dai->drv->ops.hw_params(dai, params);
422
423 return ret;
424 }
425
426 /**
427 * \brief Get Digital Audio interface DMA Handshake
428 */
dai_get_handshake(struct dai * dai,int direction,int stream_id)429 static inline int dai_get_handshake(struct dai *dai, int direction,
430 int stream_id)
431 {
432 int ret = dai->drv->ops.get_handshake(dai, direction, stream_id);
433
434 return ret;
435 }
436
437 /**
438 * \brief Get Digital Audio interface FIFO address
439 */
dai_get_fifo(struct dai * dai,int direction,int stream_id)440 static inline int dai_get_fifo(struct dai *dai, int direction,
441 int stream_id)
442 {
443 int ret = dai->drv->ops.get_fifo(dai, direction, stream_id);
444
445 return ret;
446 }
447
448 /**
449 * \brief Digital Audio interface Probe
450 */
dai_probe(struct dai * dai)451 static inline int dai_probe(struct dai *dai)
452 {
453 int ret = dai->drv->ops.probe(dai);
454
455 return ret;
456 }
457
458 /**
459 * \brief Digital Audio interface Remove
460 */
dai_remove(struct dai * dai)461 static inline int dai_remove(struct dai *dai)
462 {
463 int ret = dai->drv->ops.remove(dai);
464
465 return ret;
466 }
467
468 /**
469 * \brief Get driver specific DAI information
470 */
dai_get_info(struct dai * dai,int info)471 static inline int dai_get_info(struct dai *dai, int info)
472 {
473 int ret;
474
475 switch (info) {
476 case DAI_INFO_TYPE:
477 ret = dai->drv->type;
478 break;
479 case DAI_INFO_DMA_CAPS:
480 ret = dai->drv->dma_caps;
481 break;
482 case DAI_INFO_DMA_DEV:
483 ret = dai->drv->dma_dev;
484 break;
485 default:
486 ret = -EINVAL;
487 break;
488 }
489
490 return ret;
491 }
492
dai_write(struct dai * dai,uint32_t reg,uint32_t value)493 static inline void dai_write(struct dai *dai, uint32_t reg, uint32_t value)
494 {
495 io_reg_write(dai_base(dai) + reg, value);
496 }
497
dai_read(struct dai * dai,uint32_t reg)498 static inline uint32_t dai_read(struct dai *dai, uint32_t reg)
499 {
500 uint32_t val = io_reg_read(dai_base(dai) + reg);
501
502 return val;
503 }
504
dai_update_bits(struct dai * dai,uint32_t reg,uint32_t mask,uint32_t value)505 static inline void dai_update_bits(struct dai *dai, uint32_t reg,
506 uint32_t mask, uint32_t value)
507 {
508 io_reg_update_bits(dai_base(dai) + reg, mask, value);
509 }
510
dai_info_get(void)511 static inline const struct dai_info *dai_info_get(void)
512 {
513 return sof_get()->dai_info;
514 }
515
516 /**
517 * \brief Configure DMA channel for DAI
518 */
519 int dai_config_dma_channel(struct comp_dev *dev, void *config);
520
521 /**
522 * \brief Configure DAI physical interface.
523 */
524 int dai_config(struct comp_dev *dev, struct ipc_config_dai *common_config,
525 void *spec_config);
526
527 /**
528 * \brief Assign DAI to a group for simultaneous triggering.
529 */
530 int dai_assign_group(struct comp_dev *dev, uint32_t group_id);
531
532 /** @}*/
533
534 #endif /* __SOF_LIB_DAI_H__ */
535