1 /* Copyright (c) 2022 Intel Corporation
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 
5 #ifndef ZEPHYR_INCLUDE_INTEL_ADSP_HDA_H
6 #define ZEPHYR_INCLUDE_INTEL_ADSP_HDA_H
7 
8 #include <zephyr/cache.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/sys/util.h>
12 #include <adsp_shim.h>
13 #include <adsp_memory.h>
14 #include <adsp_shim.h>
15 
16 /**
17  * @brief HDA stream functionality for Intel ADSP
18  *
19  * Provides low level calls to support Intel ADSP HDA streams with
20  * minimal abstraction that allows testing the hardware
21  * and its demands separately from the intended DMA API
22  * usage. The only requirement is that you define the base
23  * addresses, the stream count, and the size of the ip blocks.
24  */
25 
26 /* The read/write positions are masked to 24 bits */
27 #define HDA_RWP_MASK 0x00FFFFFF
28 
29 /* Buffers must be 128 byte aligned, this mask enforces that */
30 #define HDA_ALIGN_MASK 0xFFFFFF80
31 
32 /* Buffer size must match the mask of BS field in DGBS register */
33 #define HDA_BUFFER_SIZE_MASK 0x00FFFFF0
34 
35 /* Calculate base address of the stream registers */
36 #define HDA_ADDR(base, regblock_size, stream) ((base) + (stream)*(regblock_size))
37 
38 /* Gateway Control and Status Register */
39 #define DGCS(base, regblock_size, stream) \
40 	((volatile uint32_t *)HDA_ADDR(base, regblock_size, stream))
41 #define DGCS_SCS BIT(31) /* Sample container size */
42 #define DGCS_GEN BIT(26) /* Gateway Enable */
43 #define DGCS_L1ETP BIT(25) /* L1 Enter Prevent */
44 #define DGCS_L1EXP BIT(24) /* L1 Exit Prevent */
45 #define DGCS_FWCB BIT(23) /* Firmware Control Buffer */
46 #define DGCS_GBUSY BIT(15) /* Gateway Busy */
47 #define DGCS_TE BIT(14) /* Transfer Error */
48 #define DGCS_BSC BIT(11) /* Buffer Segment Completion */
49 #define DGCS_BOR BIT(10) /* Buffer Overrun */
50 #define DGCS_BUR BIT(10) /* Buffer Underrun */
51 #define DGCS_BF BIT(9) /* Buffer Full */
52 #define DGCS_BNE BIT(8) /* Buffer Not Empty */
53 #define DGCS_FIFORDY BIT(5) /* Enable FIFO */
54 #define DGCS_BSCIE BIT(3) /* Buffer Segment Completion Interrupt Enable */
55 
56 /* Gateway Buffer Base Address */
57 #define DGBBA(base, regblock_size, stream) \
58 	((volatile uint32_t *)(HDA_ADDR(base, regblock_size, stream) + 0x04))
59 
60 /* Gateway Buffer Size */
61 #define DGBS(base, regblock_size, stream) \
62 	((volatile uint32_t *)(HDA_ADDR(base, regblock_size, stream) + 0x08))
63 
64 /* Gateway Buffer Position Increment */
65 #define DGBFPI(base, regblock_size, stream) \
66 	((volatile uint32_t *)(HDA_ADDR(base, regblock_size, stream) + 0x0c))
67 
68 /* Gateway Buffer Read Position */
69 #define DGBRP(base, regblock_size, stream) \
70 	((volatile uint32_t *)(HDA_ADDR(base, regblock_size, stream) + 0x10))
71 
72 /* Gateway Buffer Write Position */
73 #define DGBWP(base, regblock_size, stream) \
74 	((volatile uint32_t *)(HDA_ADDR(base, regblock_size, stream) + 0x14))
75 
76 /* Gateway Buffer Segment Position */
77 #define DGBSP(base, regblock_size, stream) \
78 	((volatile uint32_t *)(HDA_ADDR(base, regblock_size, stream) + 0x18))
79 
80 /* Gateway Minimum Buffer Size */
81 #define DGMBS(base, regblock_size, stream) \
82 	((volatile uint32_t *)(HDA_ADDR(base, regblock_size, stream) + 0x1c))
83 
84 /* Gateway Linear Link Position Increment */
85 #define DGLLPI(base, regblock_size, stream) \
86 	((volatile uint32_t *)(HDA_ADDR(base, regblock_size, stream) + 0x24))
87 
88 /* Gateway Linear Position In Buffer Increment */
89 #define DGLPIBI(base, regblock_size, stream) \
90 	((volatile uint32_t *)(HDA_ADDR(base, regblock_size, stream) + 0x28))
91 
92 /**
93  * @brief Dump all the useful registers of an HDA stream to printk
94  *
95  * This can be invaluable when finding out why HDA isn't doing (or maybe is)
96  * doing what you want it to do. Macro so you get the file and line
97  * of the call site included.
98  *
99  * @param name String that contains a name of the hda stream (or anything really)
100  * @param base Base address of the IP register block
101  * @param regblock_size Register block size
102  * @param sid Stream ID
103  */
104 #define intel_adsp_hda_dbg(name, base, regblock_size, sid)			\
105 		printk("%s:%u %s(%u:0x%p), dgcs: 0x%x, dgbba 0x%x, "		\
106 		       "dgbs %u, dgbrp %u, dgbwp %u, dgbsp %u, "		\
107 		       "dgmbs %u, dgbllpi 0x%x, dglpibi 0x%x\n",		\
108 		       __FILE__, __LINE__, name,				\
109 		       sid, DGCS(base, regblock_size, sid),			\
110 		       *DGCS(base, regblock_size, sid),				\
111 		       *DGBBA(base, regblock_size, sid),			\
112 		       *DGBS(base, regblock_size, sid),				\
113 		       *DGBRP(base, regblock_size, sid),			\
114 		       *DGBWP(base, regblock_size, sid),			\
115 		       *DGBSP(base, regblock_size, sid),			\
116 		       *DGMBS(base, regblock_size, sid),			\
117 		       *DGLLPI(base, regblock_size, sid),			\
118 		       *DGLPIBI(base, regblock_size, sid))
119 
120 
121 
122 /**
123  * @brief Initialize an HDA stream for use with the firmware
124  *
125  * @param base Base address of the IP register block
126  * @param sid Stream ID
127  */
intel_adsp_hda_init(uint32_t base,uint32_t regblock_size,uint32_t sid)128 static inline void intel_adsp_hda_init(uint32_t base, uint32_t regblock_size, uint32_t sid)
129 {
130 	*DGCS(base, regblock_size, sid) |= DGCS_FWCB;
131 }
132 
133 /**
134  * @brief Set the buffer, size, and element size for an HDA stream
135  *
136  * Sanity checks that the buffer address and size are valid and that the
137  * stream isn't enabled or busy.
138  *
139  * Prior to enabling an HDA stream to/from the host this is the minimum configuration
140  * that is required. It must be set *after* the host has configured its own buffers.
141  *
142  *
143  * @param base Base address of the IP register block
144  * @param regblock_size Register block size
145  * @param sid Stream ID
146  * @param buf Buffer address to use for the shared FIFO. Must be in L2 and 128 byte aligned.
147  * @param buf_size Buffer size in bytes Must be 128 byte aligned
148  *
149  * @retval -EBUSY if the HDA stream is already enabled
150  * @retval -EINVAL if the buf is not in L2, buf isn't aligned on 128 byte boundaries
151  * @retval 0 on Success
152  */
intel_adsp_hda_set_buffer(uint32_t base,uint32_t regblock_size,uint32_t sid,uint8_t * buf,uint32_t buf_size)153 static inline int intel_adsp_hda_set_buffer(uint32_t base,
154 					    uint32_t regblock_size,
155 					    uint32_t sid,
156 					    uint8_t *buf,
157 					    uint32_t buf_size)
158 {
159 	/* While we don't actually care if the pointer is in the cached
160 	 * region or not, we do need a consistent address space to check
161 	 * against for our assertion. This is cheap.
162 	 */
163 	uint32_t addr = (uint32_t)sys_cache_cached_ptr_get(buf);
164 	uint32_t aligned_addr = addr & HDA_ALIGN_MASK;
165 	uint32_t aligned_size = buf_size & HDA_BUFFER_SIZE_MASK;
166 
167 	__ASSERT(aligned_addr == addr, "Buffer must be 128 byte aligned");
168 	__ASSERT(aligned_size == buf_size,
169 		 "Buffer must be 16 byte aligned in size");
170 
171 #if defined(CONFIG_KERNEL_VM_SUPPORT)
172 #  define _INTEL_ADSP_BASE  CONFIG_KERNEL_VM_BASE
173 #  define _INTEL_ADSP_SIZE  CONFIG_KERNEL_VM_SIZE
174 #else
175 #  define _INTEL_ADSP_BASE  CONFIG_SRAM_BASE_ADDRESS
176 #  define _INTEL_ADSP_SIZE  KB(CONFIG_SRAM_SIZE)
177 #endif
178 
179 	__ASSERT(aligned_addr >= _INTEL_ADSP_BASE
180 		 && aligned_addr < _INTEL_ADSP_BASE + _INTEL_ADSP_SIZE,
181 		 "Buffer must be in kernel address space");
182 	__ASSERT(aligned_addr + aligned_size < _INTEL_ADSP_BASE + _INTEL_ADSP_SIZE,
183 		 "Buffer must end in kernel address space");
184 
185 	if (*DGCS(base, regblock_size, sid) & DGCS_GEN) {
186 		return -EBUSY;
187 	}
188 
189 	if (*DGCS(base, regblock_size, sid) & DGCS_GBUSY) {
190 		return -EBUSY;
191 	}
192 
193 	*DGBBA(base, regblock_size, sid) = aligned_addr;
194 	*DGBS(base, regblock_size, sid) = aligned_size;
195 
196 	return 0;
197 }
198 
199 /**
200  * @brief Get the buffer size
201  *
202  * @param base Base address of the IP register block
203  * @param regblock_size Register block size
204  * @param sid Stream ID
205  *
206  * @retval buf_size Buffer size in bytes
207  */
intel_adsp_hda_get_buffer_size(uint32_t base,uint32_t regblock_size,uint32_t sid)208 static inline uint32_t intel_adsp_hda_get_buffer_size(uint32_t base,
209 					    uint32_t regblock_size,
210 					    uint32_t sid)
211 {
212 	return *DGBS(base, regblock_size, sid);
213 }
214 
215 /**
216  * @brief Enable the stream
217  *
218  * @param base Base address of the IP register block
219  * @param regblock_size Register block size
220  * @param sid Stream ID
221  */
intel_adsp_hda_enable(uint32_t base,uint32_t regblock_size,uint32_t sid,bool set_fifordy)222 static inline void intel_adsp_hda_enable(uint32_t base, uint32_t regblock_size,
223 					 uint32_t sid, bool set_fifordy)
224 {
225 	*DGCS(base, regblock_size, sid) |= DGCS_GEN;
226 
227 	if (set_fifordy) {
228 		*DGCS(base, regblock_size, sid) |= DGCS_FIFORDY;
229 	}
230 }
231 
232 /**
233  * @brief Disable stream
234  *
235  * @param base Base address of the IP register block
236  * @param regblock_size Register block size
237  * @param sid Stream ID
238  */
intel_adsp_hda_disable(uint32_t base,uint32_t regblock_size,uint32_t sid)239 static inline void intel_adsp_hda_disable(uint32_t base, uint32_t regblock_size, uint32_t sid)
240 {
241 	*DGCS(base, regblock_size, sid) &= ~(DGCS_GEN | DGCS_FIFORDY);
242 }
243 
244 /**
245  * @brief Check if stream is enabled
246  *
247  * @param base Base address of the IP register block
248  * @param regblock_size Register block size
249  * @param sid Stream ID
250  */
intel_adsp_hda_is_enabled(uint32_t base,uint32_t regblock_size,uint32_t sid)251 static inline bool intel_adsp_hda_is_enabled(uint32_t base, uint32_t regblock_size, uint32_t sid)
252 {
253 	return *DGCS(base, regblock_size, sid) & (DGCS_GEN | DGCS_FIFORDY);
254 }
255 
256 /**
257  * @brief Determine the number of unused bytes in the buffer
258  *
259  * This is useful primarily for a  host in (dsp -> host) stream.
260  *
261  * @param base Base address of the IP register block
262  * @param regblock_size Register block size
263  * @param sid Stream ID within the register block
264  *
265  * @retval n Number of unused bytes
266  */
intel_adsp_hda_unused(uint32_t base,uint32_t regblock_size,uint32_t sid)267 static inline uint32_t intel_adsp_hda_unused(uint32_t base, uint32_t regblock_size, uint32_t sid)
268 {
269 	uint32_t dgcs = *DGCS(base, regblock_size, sid);
270 	uint32_t dgbs = *DGBS(base, regblock_size, sid);
271 
272 	/* Check if buffer is empty */
273 	if ((dgcs & DGCS_BNE) == 0) {
274 		return dgbs;
275 	}
276 
277 	/* Check if the buffer is full */
278 	if (dgcs & DGCS_BF) {
279 		return 0;
280 	}
281 
282 	int32_t rp = *DGBRP(base, regblock_size, sid);
283 	int32_t wp = *DGBWP(base, regblock_size, sid);
284 	int32_t size = rp - wp;
285 
286 	if (size <= 0) {
287 		size += dgbs;
288 	}
289 
290 	return size;
291 }
292 
293 /**
294  * @brief Commit a number of bytes that have been transferred to/from host
295  *
296  * Writes the length to BFPI. For host transfers LLPI and LPIB are
297  * also written to with the given length.
298  *
299  * This then updates the read or write position depending on the direction.
300  *
301  * LPIBI writes here can be seen on the host side of the transfer in the
302  * matching LPIB register.
303  *
304  * LLPI seems to, from behavior, inform the hardware to actually read/write
305  * from the buffer. Without updating BFPI AND LLPI, the transfer doesn't
306  * happen in testing for host transfers.
307  *
308  * @param base Base address of the IP register block
309  * @param regblock_size Register block size
310  * @param sid Stream ID within the register block
311  * @param len Len to increment postion by
312  */
intel_adsp_hda_host_commit(uint32_t base,uint32_t regblock_size,uint32_t sid,uint32_t len)313 static inline void intel_adsp_hda_host_commit(uint32_t base,
314 					      uint32_t regblock_size,
315 					      uint32_t sid,
316 					      uint32_t len)
317 {
318 	*DGBFPI(base, regblock_size, sid) = len;
319 	*DGLLPI(base, regblock_size, sid) = len;
320 	*DGLPIBI(base, regblock_size, sid) = len;
321 }
322 
323 /**
324  * @brief Commit a number of bytes that have been transferred to/from link
325  *
326  * Writes the length to BFPI.
327  *
328  * @seealso intel_adsp_hda_host_commit
329  *
330  * @param base Base address of the IP register block
331  * @param regblock_size Register block size
332  * @param sid Stream ID within the register block
333  * @param len Len to increment postion by
334  */
intel_adsp_hda_link_commit(uint32_t base,uint32_t regblock_size,uint32_t sid,uint32_t len)335 static inline void intel_adsp_hda_link_commit(uint32_t base,
336 					      uint32_t regblock_size,
337 					      uint32_t sid,
338 					      uint32_t len)
339 {
340 	*DGBFPI(base, regblock_size, sid) = len;
341 }
342 
343 /**
344  * @brief Read the buffer full bit of the given stream.
345  *
346  * @param base Base address of the IP register block
347  * @param regblock_size Register block size
348  * @param sid Stream ID within the register block
349  *
350  * @retval true If the buffer full flag is set
351  */
intel_adsp_hda_buf_full(uint32_t base,uint32_t regblock_size,uint32_t sid)352 static inline bool intel_adsp_hda_buf_full(uint32_t base, uint32_t regblock_size, uint32_t sid)
353 {
354 	return *DGCS(base, regblock_size, sid) & DGCS_BF;
355 }
356 
357 /**
358  * @brief Check if the write and read position are equal
359  *
360  * For HDA this does not mean that the buffer is full or empty
361  * there are bit flags for those cases.
362  *
363  * Useful for waiting on the hardware to catch up to
364  * reads or writes (e.g. after a intel_adsp_hda_commit)
365  *
366  * @param base Base address of the IP register block
367  * @param regblock_size Register block size
368  * @param sid Stream D
369  *
370  * @retval true If the read and write positions are equal
371  */
intel_adsp_hda_wp_rp_eq(uint32_t base,uint32_t regblock_size,uint32_t sid)372 static inline bool intel_adsp_hda_wp_rp_eq(uint32_t base, uint32_t regblock_size, uint32_t sid)
373 {
374 	return *DGBWP(base, regblock_size, sid) == *DGBRP(base, regblock_size, sid);
375 }
376 
intel_adsp_hda_is_buffer_overrun(uint32_t base,uint32_t regblock_size,uint32_t sid)377 static inline bool intel_adsp_hda_is_buffer_overrun(uint32_t base, uint32_t regblock_size,
378 						    uint32_t sid)
379 {
380 	return (*DGCS(base, regblock_size, sid) & DGCS_BOR) == DGCS_BOR ? 1 : 0;
381 }
382 
intel_adsp_hda_is_buffer_underrun(uint32_t base,uint32_t regblock_size,uint32_t sid)383 static inline bool intel_adsp_hda_is_buffer_underrun(uint32_t base, uint32_t regblock_size,
384 						     uint32_t sid)
385 {
386 	return (*DGCS(base, regblock_size, sid) & DGCS_BUR) == DGCS_BUR ? 1 : 0;
387 }
388 
intel_adsp_hda_overrun_clear(uint32_t base,uint32_t regblock_size,uint32_t sid)389 static inline void intel_adsp_hda_overrun_clear(uint32_t base, uint32_t regblock_size,
390 						uint32_t sid)
391 {
392 	*DGCS(base, regblock_size, sid) |= DGCS_BOR;
393 }
394 
intel_adsp_hda_underrun_clear(uint32_t base,uint32_t regblock_size,uint32_t sid)395 static inline void intel_adsp_hda_underrun_clear(uint32_t base, uint32_t regblock_size,
396 						 uint32_t sid)
397 {
398 	*DGCS(base, regblock_size, sid) |= DGCS_BUR;
399 }
400 
401 /**
402  * @brief Set the buffer segment ptr
403  *
404  * @param base Base address of the IP register block
405  * @param regblock_size Register block size
406  * @param sid Stream ID
407  * @param size
408  */
intel_adsp_hda_set_buffer_segment_ptr(uint32_t base,uint32_t regblock_size,uint32_t sid,uint32_t size)409 static inline void intel_adsp_hda_set_buffer_segment_ptr(uint32_t base, uint32_t regblock_size,
410 							 uint32_t sid, uint32_t size)
411 {
412 	*DGBSP(base, regblock_size, sid) = size;
413 }
414 
415 /**
416  * @brief Get the buffer segment ptr
417  *
418  * @param base Base address of the IP register block
419  * @param regblock_size Register block size
420  * @param sid Stream ID
421  *
422  * @retval buffer segment ptr
423  */
intel_adsp_hda_get_buffer_segment_ptr(uint32_t base,uint32_t regblock_size,uint32_t sid)424 static inline uint32_t intel_adsp_hda_get_buffer_segment_ptr(uint32_t base, uint32_t regblock_size,
425 							     uint32_t sid)
426 {
427 	return *DGBSP(base, regblock_size, sid);
428 }
429 
430 /**
431  * @brief Enable BSC interrupt
432  *
433  * @param base Base address of the IP register block
434  * @param regblock_size Register block size
435  * @param sid Stream ID
436  */
intel_adsp_hda_enable_buffer_interrupt(uint32_t base,uint32_t regblock_size,uint32_t sid)437 static inline void intel_adsp_hda_enable_buffer_interrupt(uint32_t base, uint32_t regblock_size,
438 							  uint32_t sid)
439 {
440 	*DGCS(base, regblock_size, sid) |= DGCS_BSCIE;
441 }
442 
443 /**
444  * @brief Disable BSC interrupt
445  *
446  * @param base Base address of the IP register block
447  * @param regblock_size Register block size
448  * @param sid Stream ID
449  */
intel_adsp_hda_disable_buffer_interrupt(uint32_t base,uint32_t regblock_size,uint32_t sid)450 static inline void intel_adsp_hda_disable_buffer_interrupt(uint32_t base, uint32_t regblock_size,
451 							   uint32_t sid)
452 {
453 	*DGCS(base, regblock_size, sid) &= ~DGCS_BSCIE;
454 }
455 
456 /**
457  * @brief Check if BSC interrupt enabled
458  *
459  * @param base Base address of the IP register block
460  * @param regblock_size Register block size
461  * @param sid Stream ID
462  */
intel_adsp_hda_is_buffer_interrupt_enabled(uint32_t base,uint32_t regblock_size,uint32_t sid)463 static inline bool intel_adsp_hda_is_buffer_interrupt_enabled(uint32_t base,
464 							      uint32_t regblock_size, uint32_t sid)
465 {
466 	return (*DGCS(base, regblock_size, sid) & DGCS_BSCIE) == DGCS_BSCIE;
467 }
468 
intel_adsp_force_dmi_l0_state(void)469 static inline void intel_adsp_force_dmi_l0_state(void)
470 {
471 #ifdef CONFIG_SOC_SERIES_INTEL_ADSP_ACE
472 	ACE_DfPMCCH.svcfg |= ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT;
473 #endif
474 }
475 
intel_adsp_allow_dmi_l1_state(void)476 static inline void intel_adsp_allow_dmi_l1_state(void)
477 {
478 #ifdef CONFIG_SOC_SERIES_INTEL_ADSP_ACE
479 	ACE_DfPMCCH.svcfg &= ~(ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT);
480 #endif
481 }
482 
483 /**
484  * @brief Clear BSC interrupt
485  *
486  * @param base Base address of the IP register block
487  * @param regblock_size Register block size
488  * @param sid Stream ID
489  */
intel_adsp_hda_clear_buffer_interrupt(uint32_t base,uint32_t regblock_size,uint32_t sid)490 static inline void intel_adsp_hda_clear_buffer_interrupt(uint32_t base, uint32_t regblock_size,
491 							 uint32_t sid)
492 {
493 	*DGCS(base, regblock_size, sid) |= DGCS_BSC;
494 }
495 
496 /**
497  * @brief Get status of BSC interrupt
498  *
499  * @param base Base address of the IP register block
500  * @param regblock_size Register block size
501  * @param sid Stream ID
502  *
503  * @retval interrupt status
504  */
intel_adsp_hda_check_buffer_interrupt(uint32_t base,uint32_t regblock_size,uint32_t sid)505 static inline uint32_t intel_adsp_hda_check_buffer_interrupt(uint32_t base, uint32_t regblock_size,
506 							     uint32_t sid)
507 {
508 	return (*DGCS(base, regblock_size, sid) & DGCS_BSC) == DGCS_BSC;
509 }
510 
511 /**
512  * @brief Set the Sample Container Size (SCS)
513  *
514  * Sample Container Size indicates the container size of the audio samples in local memory
515  * SCS bit must cleared to 0 for 32bit sample size (HD Audio container size)
516  * SCS bit must be set to 1 for non 32bit sample sizes
517  *
518  * @param base Base address of the IP register block
519  * @param regblock_size Register block size
520  * @param sid Stream ID
521  * @param sample_size
522  */
intel_adsp_hda_set_sample_container_size(uint32_t base,uint32_t regblock_size,uint32_t sid,uint32_t sample_size)523 static inline void intel_adsp_hda_set_sample_container_size(uint32_t base, uint32_t regblock_size,
524 							    uint32_t sid, uint32_t sample_size)
525 {
526 	if (sample_size <= 3) {
527 		*DGCS(base, regblock_size, sid) |= DGCS_SCS;
528 	} else {
529 		*DGCS(base, regblock_size, sid) &= ~DGCS_SCS;
530 	}
531 }
532 
533 #endif /* ZEPHYR_INCLUDE_INTEL_ADSP_HDA_H */
534