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