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