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