xref: /rk3399_ARM-atf/include/plat/marvell/odyssey/csr/ody-csr.h (revision f7a23c66fa4640deba0b11ddb59dd8bdf1667b40)
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));
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));
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