1 /*
2  * Copyright (c) 2023 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <stdbool.h>
9 #include <zephyr/spinlock.h>
10 #include <zephyr/devicetree.h>
11 #include <adsp_shim.h>
12 #include <adsp_timestamp.h>
13 
14 #define TTS_BASE_ADDR   DT_REG_ADDR(DT_NODELABEL(tts))
15 
16 #define TSCTRL_ADDR     (TTS_BASE_ADDR + ADSP_TSCTRL_OFFSET)
17 #define ISCS_ADDR       (TTS_BASE_ADDR + ADSP_ISCS_OFFSET)
18 #define LSCS_ADDR       (TTS_BASE_ADDR + ADSP_LSCS_OFFSET)
19 #define DWCCS_ADDR      (TTS_BASE_ADDR + ADSP_DWCCS_OFFSET)
20 #define ARTCS_ADDR      (TTS_BASE_ADDR + ADSP_ARTCS_OFFSET)
21 #define LWCCS_ADDR      (TTS_BASE_ADDR + ADSP_LWCCS_OFFSET)
22 
23 /* Copies the bit-field specified by mask from src to dest */
24 #define BITS_COPY(dest, src, mask)  ((dest) = ((dest) & ~(mask)) | ((src) & (mask)))
25 
26 static struct k_spinlock lock;
27 
intel_adsp_get_timestamp(uint32_t tsctrl,struct intel_adsp_timestamp * timestamp)28 int intel_adsp_get_timestamp(uint32_t tsctrl, struct intel_adsp_timestamp *timestamp)
29 {
30 	uint32_t trigger_mask = ADSP_SHIM_TSCTRL_HHTSE | ADSP_SHIM_TSCTRL_ODTS;
31 	uint32_t trigger_bits = tsctrl & trigger_mask;
32 	uint32_t tsctrl_temp;
33 	k_spinlock_key_t key;
34 	int ret = 0;
35 
36 	/* Exactly one trigger bit must be set in a valid request */
37 	if (POPCOUNT(trigger_bits) != 1) {
38 		return -EINVAL;
39 	}
40 
41 	key = k_spin_lock(&lock);
42 
43 	tsctrl_temp = sys_read32(TSCTRL_ADDR);
44 
45 	/* Abort if any timestamp capture in progress */
46 	if (tsctrl_temp & trigger_mask) {
47 		ret = -EBUSY;
48 		goto out;
49 	}
50 
51 	/* Clear NTK (RW/1C) bit if needed */
52 	if (tsctrl_temp & ADSP_SHIM_TSCTRL_NTK) {
53 		sys_write32(tsctrl_temp, TSCTRL_ADDR);
54 		tsctrl_temp &= ~ADSP_SHIM_TSCTRL_NTK;
55 	}
56 
57 	/* Setup the timestamping logic according to request */
58 	BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_IONTE);
59 	BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_DMATS);
60 	BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_CLNKS);
61 	BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_LWCS);
62 	BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_CDMAS);
63 	sys_write32(tsctrl_temp, TSCTRL_ADDR);
64 
65 	/* Start new timestamp capture by setting one of mutually exclusive
66 	 * trigger bits.
67 	 */
68 	tsctrl_temp |= trigger_bits;
69 	sys_write32(tsctrl_temp, TSCTRL_ADDR);
70 
71 	/* Wait for timestamp capture to complete */
72 	while (true) {
73 		tsctrl_temp = sys_read32(TSCTRL_ADDR);
74 		if (tsctrl_temp & ADSP_SHIM_TSCTRL_NTK) {
75 			break;
76 		}
77 	}
78 
79 	/* Copy the timestamp data from HW registers to the snapshot buffer
80 	 * provided by caller. As NTK bit is high at this stage, the timestamp
81 	 * data in HW is guaranteed to be valid and static.
82 	 */
83 	timestamp->iscs = sys_read32(ISCS_ADDR);
84 	timestamp->lscs = sys_read64(LSCS_ADDR);
85 	timestamp->dwccs = sys_read64(DWCCS_ADDR);
86 	timestamp->artcs = sys_read64(ARTCS_ADDR);
87 	timestamp->lwccs = sys_read32(LWCCS_ADDR);
88 
89 	/* Clear NTK (RW/1C) bit */
90 	tsctrl_temp |= ADSP_SHIM_TSCTRL_NTK;
91 	sys_write32(tsctrl_temp, TSCTRL_ADDR);
92 
93 out:
94 	k_spin_unlock(&lock, key);
95 
96 	return ret;
97 }
98