1 /***********************license start***********************************
2 * Copyright (C) 2021-2026 Marvell.
3 * SPDX-License-Identifier: BSD-3-Clause
4 * https://spdx.org/licenses
5 ***********************license end**************************************/
6 #ifndef __ODY_CSR_H__
7 #define __ODY_CSR_H__
8
9 /**
10 * @file
11 *
12 * Functions and macros for accessing Cavium CSRs.
13 *
14 * <hr>$Revision: 49448 $<hr>
15 *
16 * @defgroup csr CSR support
17 * @{
18 */
19
20 /**
21 * Possible CSR bus types
22 */
23 typedef enum {
24 CSR_TYPE_DAB, /**< External debug 64bit CSR */
25 CSR_TYPE_DAB32b, /**< External debug 32bit CSR */
26 CSR_TYPE_MDSB, /**< CN96XX: Memory Diagnostic Serial Bus?, not memory mapped */
27 CSR_TYPE_NCB, /**< Fast 64bit CSR */
28 CSR_TYPE_NCB32b, /**< Fast 32bit CSR */
29 CSR_TYPE_PCCBR,
30 CSR_TYPE_PCCPF,
31 CSR_TYPE_PCCVF,
32 CSR_TYPE_PCICONFIGRC, /**< PCIe config address (RC mode) */
33 CSR_TYPE_PCICONFIGEP, /**< PCIe config address (EP mode) */
34 CSR_TYPE_PCICONFIGEP_SHADOW, /**< CN96XX: PCIEP register invisible to host, not memory mapped */
35 CSR_TYPE_PCICONFIGEPVF, /**< CN96XX: PCIEP registers only on vertain PEMs, not memory mapped */
36 CSR_TYPE_PEXP, /**< PCIe BAR 0 address only */
37 CSR_TYPE_PEXP_NCB, /**< NCB-direct and PCIe BAR0 address */
38 CSR_TYPE_RSL, /**< Slow 64bit CSR */
39 CSR_TYPE_RSL32b, /**< Slow 32bit CSR */
40 CSR_TYPE_RVU_PF_BAR0, /**< Index into RVU PF BAR0 */
41 CSR_TYPE_RVU_PF_BAR2, /**< Index into RVU PF BAR2 */
42 CSR_TYPE_RVU_PFVF_BAR2, /**< Index into RVU PF or VF BAR2 */
43 CSR_TYPE_RVU_VF_BAR2, /**< Index into RVU VF BAR2 */
44 CSR_TYPE_SYSREG, /**< Core system register */
45 } ody_csr_type_t;
46
47 #define CSR_DB_MAX_PARAM 6
48 typedef struct __attribute__ ((packed)) {
49 uint32_t name_index : 20;/**< Index into __ody_csr_db_string where the name is */
50 uint32_t width : 4; /**< CSR width in bytes */
51 ody_csr_type_t type : 8; /**< Enum type from above */
52 uint16_t base_index; /**< Index into __ody_csr_db_number where the base address is */
53 uint16_t field_index; /**< Index into __ody_csr_db_fieldList where the fields start */
54 uint16_t range_index; /**< Index into __ody_csr_db_range where the range is */
55 uint16_t param_inc_index; /**< Index into __ody_csr_db_number where the param multiplier is */
56 } __ody_csr_db_type_t;
57
58 typedef struct __attribute__ ((packed)) {
59 uint32_t name_index : 20;/**< Index into __ody_csr_db_string where the name is */
60 uint32_t start_bit : 6; /**< LSB of the field */
61 uint32_t stop_bit : 6; /**< MSB of the field */
62 } __ody_csr_db_field_t;
63
64 typedef struct {
65 uint32_t model;
66 uint32_t offset;
67 } __ody_csr_db_map_t;
68
69 struct ody_readline_tab;
70 extern uint64_t ody_sysreg_read(int core, uint64_t regnum);
71 extern void ody_sysreg_write(int core, uint64_t regnum, uint64_t value);
72
73 #ifndef ODY_BUILD_HOST
74
75 /**
76 * Read a value from a CSR. Normally this function should not be
77 * used directly. Instead use the macro CSR_READ that fills
78 * in the parameters to this function for you.
79 *
80 * @param type Bus type the CSR is on
81 * @param busnum Bus number the CSR is on
82 * @param size Width of the CSR in bytes
83 * @param address The address of the CSR
84 *
85 * @return The value of the CSR
86 */
87 static inline uint64_t ody_csr_read(ody_csr_type_t type, int busnum, int size, uint64_t address) __attribute__ ((always_inline));
ody_csr_read(ody_csr_type_t type,int busnum,int size,uint64_t address)88 static inline uint64_t ody_csr_read(ody_csr_type_t type, int busnum, int size, uint64_t address)
89 {
90 extern uint64_t __ody_csr_read_slow(ody_csr_type_t type, int busnum, int size, uint64_t address);
91
92 switch (type) {
93 case CSR_TYPE_DAB:
94 case CSR_TYPE_DAB32b:
95 case CSR_TYPE_NCB:
96 case CSR_TYPE_NCB32b:
97 case CSR_TYPE_PEXP_NCB:
98 case CSR_TYPE_RSL:
99 case CSR_TYPE_RSL32b:
100 case CSR_TYPE_RVU_PF_BAR0:
101 case CSR_TYPE_RVU_PF_BAR2:
102 case CSR_TYPE_RVU_PFVF_BAR2:
103 case CSR_TYPE_RVU_VF_BAR2:
104 /* Note: This code assume a 1:1 mapping of all of address space
105 * It is designed to run with the MMU disabled
106 */
107 switch (size) {
108 case 1:
109 return *(volatile uint8_t *)address;
110 case 2:
111 return ody_le16_to_cpu(*(volatile uint16_t *)address);
112 case 4:
113 return ody_le32_to_cpu(*(volatile uint32_t *)address);
114 default:
115 return ody_le64_to_cpu(*(volatile uint64_t *)address);
116 }
117 default:
118 return __ody_csr_read_slow(type, busnum, size, address);
119 }
120 }
121
122
123 /**
124 * Wrate a value to a CSR. Normally this function should not be
125 * used directly. Instead use the macro CSR_WRITE that fills
126 * in the parameters to this function for you.
127 *
128 * @param type Bus type the CSR is on
129 * @param busnum Bus number the CSR is on
130 * @param size Width of the CSR in bytes
131 * @param address The address of the CSR
132 * @param value Value to write to the CSR
133 */
134 static inline void ody_csr_write(ody_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value) __attribute__ ((always_inline));
ody_csr_write(ody_csr_type_t type,int busnum,int size,uint64_t address,uint64_t value)135 static inline void ody_csr_write(ody_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value)
136 {
137 extern void __ody_csr_write_slow(ody_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value);
138
139 switch (type) {
140 case CSR_TYPE_DAB:
141 case CSR_TYPE_DAB32b:
142 case CSR_TYPE_NCB:
143 case CSR_TYPE_NCB32b:
144 case CSR_TYPE_PEXP_NCB:
145 case CSR_TYPE_RSL:
146 case CSR_TYPE_RSL32b:
147 case CSR_TYPE_RVU_PF_BAR0:
148 case CSR_TYPE_RVU_PF_BAR2:
149 case CSR_TYPE_RVU_PFVF_BAR2:
150 case CSR_TYPE_RVU_VF_BAR2:
151 /* Note: This code assume a 1:1 mapping of all of address space.
152 * It is designed to run with the MMU disabled
153 */
154 switch (size) {
155 case 1:
156 *(volatile uint8_t *)address = value;
157 break;
158 case 2:
159 *(volatile uint16_t *)address = ody_cpu_to_le16(value);
160 break;
161 case 4:
162 *(volatile uint32_t *)address = ody_cpu_to_le32(value);
163 break;
164 default:
165 *(volatile uint64_t *)address = ody_cpu_to_le64(value);
166 break;
167 }
168 break;
169 default:
170 __ody_csr_write_slow(type, busnum, size, address, value);
171 }
172 }
173
174 #else
175 #define ody_csr_read thunder_remote_read_csr
176 #define ody_csr_write thunder_remote_write_csr
177 #endif
178
179 /**
180 * This macro makes it easy to define a variable of the correct
181 * type for a CSR.
182 */
183 #define CSR_DEFINE(name, csr) typedef_##csr name
184
185 /**
186 * This macro makes it easy to define a variable and initialize it
187 * with a CSR.
188 */
189 #define CSR_INIT(name, csr) typedef_##csr name = {.u = ody_csr_read(bustype_##csr, busnum_##csr, sizeof(typedef_##csr), csr)}
190
191 /**
192 * Macro to read a CSR
193 */
194 #define CSR_READ(csr) ody_csr_read(bustype_##csr, busnum_##csr, sizeof(typedef_##csr), csr)
195
196 /**
197 * Macro to write a CSR
198 */
199 #define CSR_WRITE(csr, value) ody_csr_write(bustype_##csr, busnum_##csr, sizeof(typedef_##csr), csr, value)
200
201 /**
202 * Macro to make a read, modify, and write sequence easy. The "code_block"
203 * should be replaced with a C code block or a comma separated list of
204 * "name.s.field = value", without the quotes.
205 */
206 #define CSR_MODIFY(name, csr, code_block) do { \
207 uint64_t _tmp_address = csr; \
208 typedef_##csr name = {.u = ody_csr_read(bustype_##csr, busnum_##csr, sizeof(typedef_##csr), _tmp_address)}; \
209 code_block; \
210 ody_csr_write(bustype_##csr, busnum_##csr, sizeof(typedef_##csr), _tmp_address, name.u); \
211 } while (0)
212
213 /**
214 * This macro spins on a field waiting for it to reach a value. It
215 * is common in code to need to wait for a specific field in a CSR
216 * to match a specific value. Conceptually this macro expands to:
217 *
218 * 1) read csr at "address" with a csr typedef of "type"
219 * 2) Check if ("type".s."field" "op" "value")
220 * 3) If #2 isn't true loop to #1 unless too much time has passed.
221 */
222 #define CSR_WAIT_FOR_FIELD(csr, field, op, value, timeout_usec) \
223 ({int result; \
224 do { \
225 uint64_t done = ody_clock_get_count(CLOCK_TIME) + (uint64_t)timeout_usec * \
226 ody_clock_get_rate(CLOCK_TIME) / 1000000; \
227 typedef_##csr c; \
228 uint64_t _tmp_address = csr; \
229 while (1) { \
230 c.u = ody_csr_read(bustype_##csr, busnum_##csr, sizeof(typedef_##csr), _tmp_address); \
231 if ((c.s.field) op(value)) { \
232 result = 0; \
233 break; \
234 } else if (ody_clock_get_count(CLOCK_TIME) > done) { \
235 result = -1; \
236 break; \
237 } else \
238 ody_wait_usec(1); \
239 } \
240 } while (0); \
241 result; })
242
243 /**
244 * This macro spins on a field waiting for it to reach a value. It
245 * is common in code to need to wait for a specific field in a CSR
246 * to match a specific value. Conceptually this macro expands to:
247 *
248 * 1) read csr at "address" with a csr typedef of "type"
249 * 2) Check if ("type".s."field" "op" "value")
250 * 3) If #2 isn't true loop to #1 unless too much time has passed.
251 */
252 #define CSR_WAIT_FOR_FIELD_ACTUAL(csr, field, op, value, timeout_usec) \
253 ({int result; \
254 do { \
255 uint64_t _start_time = ody_clock_get_count(CLOCK_TIME); \
256 uint64_t done = _start_time + (uint64_t)timeout_usec * \
257 ody_clock_get_rate(CLOCK_TIME) / 1000000; \
258 typedef_##csr c; \
259 uint64_t _tmp_address = csr; \
260 uint64_t _current_time; \
261 while (1) { \
262 c.u = ody_csr_read(bustype_##csr, busnum_##csr, sizeof(typedef_##csr), _tmp_address); \
263 _current_time = ody_clock_get_count(CLOCK_TIME); \
264 if ((c.s.field) op(value)) { \
265 result = _current_time - _start_time; \
266 break; \
267 } else if (_current_time > done) { \
268 result = -1; \
269 break; \
270 } else \
271 ody_thread_yield(); \
272 } \
273 } while (0); \
274 result; })
275
276 /**
277 * This macro spins on a field waiting for it to reach a value. It
278 * is common in code to need to wait for a specific field in a CSR
279 * to match a specific value. Conceptually this macro expands to:
280 *
281 * 1) read csr at "address" with a csr typedef of "type"
282 * 2) Check if ("type"."chip"."field" "op" "value")
283 * 3) If #2 isn't true loop to #1 unless too much time has passed.
284 *
285 * Note that usage of this macro should be avoided. When future chips
286 * change bit locations, the compiler will not catch those changes
287 * with this macro. Changes silently do the wrong thing at runtime.
288 */
289 #define CSR_WAIT_FOR_CHIP_FIELD(csr, chip, field, op, value, timeout_usec) \
290 ({int result; \
291 do { \
292 uint64_t done = ody_clock_get_count(CLOCK_TIME) + (uint64_t)timeout_usec * \
293 ody_clock_get_rate(CLOCK_TIME) / 1000000; \
294 typedef_##csr c; \
295 uint64_t _tmp_address = csr; \
296 while (1) { \
297 c.u = ody_csr_read(bustype_##csr, busnum_##csr, sizeof(typedef_##csr), _tmp_address); \
298 if ((c.chip.field) op(value)) { \
299 result = 0; \
300 break; \
301 } else if (ody_clock_get_count(CLOCK_TIME) > done) { \
302 result = -1; \
303 break; \
304 } else \
305 ody_wait_usec(1); \
306 } \
307 } while (0); \
308 result; })
309
310 /** @} */
311 #endif
312