xref: /aosp_15_r20/external/coreboot/src/vendorcode/cavium/include/bdk/libbdk-hal/device/bdk-device.h (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 #ifndef __CB_BDK_DEVICE_H__
2 #define __CB_BDK_DEVICE_H__
3 
4 /***********************license start***********************************
5 * Copyright (c) 2003-2017  Cavium Inc. ([email protected]). All rights
6 * reserved.
7 *
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 *
13 *   * Redistributions of source code must retain the above copyright
14 *     notice, this list of conditions and the following disclaimer.
15 *
16 *   * Redistributions in binary form must reproduce the above
17 *     copyright notice, this list of conditions and the following
18 *     disclaimer in the documentation and/or other materials provided
19 *     with the distribution.
20 *
21 *   * Neither the name of Cavium Inc. nor the names of
22 *     its contributors may be used to endorse or promote products
23 *     derived from this software without specific prior written
24 *     permission.
25 *
26 * This Software, including technical data, may be subject to U.S. export
27 * control laws, including the U.S. Export Administration Act and its
28 * associated regulations, and may be subject to export or import
29 * regulations in other countries.
30 *
31 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
32 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
33 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
34 * TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
35 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
36 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
37 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
38 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
39 * QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK
40 * ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
41 ***********************license end**************************************/
42 
43 /**
44  * @file
45  *
46  * bdk_device_t represents devices connected using ECAMs. This
47  * are discover by scanning the ECAMs and instantiating devices
48  * for what is found.
49  *
50  *  The discovery process for a device is: Scan all ECAMs:
51  *      1) Device found on an ECAM that doesn't have a bdk_device_t
52  *      2) bdk_device_t created, put in
53  *          BDK_DEVICE_STATE_NOT_PROBED state
54  *  For all devices in state BDK_DEVICE_STATE_NOT_PROBED:
55  *      1) Lookup driver probe() function. If not found, skip
56  *      2) Call probe() 3) Based on probe(), transition to
57  *          either BDK_DEVICE_STATE_PROBED or
58  *          BDK_DEVICE_STATE_PROBE_FAIL
59  *  For all devices in state BDK_DEVICE_STATE_PROBED:
60  *      1) Lookup driver init() function. If not found, skip
61  *      2) Call init() 3) Based on init(), transition to either
62  *          BDK_DEVICE_STATE_READY or BDK_DEVICE_STATE_INIT_FAIL
63  *  In general all devices should transition to
64  *  BDK_DEVICE_STATE_PROBED before any init() functions are
65  *  called. This can be used for synchronization. For example,
66  *  the FPA should be functional after a probe() so PKI/PKO can
67  *  succeed when calling alloc in init().
68  *
69  * @defgroup device ECAM Attached Devices
70  * @addtogroup device
71  * @{
72  */
73 
74 /**
75  * Possible states of a device
76  */
77 typedef enum
78 {
79     BDK_DEVICE_STATE_NOT_PROBED,    /* Device is known and offline. We haven't probed it */
80     BDK_DEVICE_STATE_PROBE_FAIL,    /* Device failed probing and is offline */
81     BDK_DEVICE_STATE_PROBED,        /* Device succeeded probing, about to go online */
82     BDK_DEVICE_STATE_INIT_FAIL,     /* Device init call failed, offline */
83     BDK_DEVICE_STATE_READY,         /* Device init call success, online */
84 } bdk_device_state_t;
85 
86 /**
87  * The structure of a ECAM BAR entry inside if a device
88  */
89 typedef struct
90 {
91     uint64_t address;   /* Base physical address */
92     uint32_t size2;     /* Size in bytes as 2^size */
93     uint32_t flags;     /* Type flags for the BAR */
94 } bdk_device_bar_t;
95 
96 /**
97  * Defines the BDK's representation of a ECAM connected device
98  */
99 typedef struct
100 {
101     char name[16];                  /* Name of the device */
102     bdk_device_bar_t    bar[4];     /* Device BARs, first for better alignment */
103     bdk_device_state_t  state : 8;  /* Current state of bdk_device_t */
104     bdk_node_t          node : 3;   /* Node the device is on */
105     uint8_t             ecam : 5;   /* ECAM for the device */
106     uint8_t             bus;        /* ECAM bus number (0-255) */
107     uint8_t             dev : 5;    /* ECAM device (0-31) */
108     uint8_t             func : 3;   /* ECAM deivce function (0-7) */
109     uint32_t            id;         /* ECAM device ID */
110     uint16_t            instance;   /* Cavium internal instance number */
111 } bdk_device_t;
112 #define BDK_NO_DEVICE_INSTANCE 0xffffu
113 
114 /**
115  * Defines the main entry points for a device driver. Full
116  * definition is in bdk-device.h
117  */
118 struct bdk_driver_s;
119 
120 /**
121  * Called to register a new driver with the bdk-device system. Drivers are probed
122  * and initialized as device are found for them. If devices have already been
123  * added before the driver was registered, the driver will be probed and
124  * initialized before this function returns.
125  *
126  * @param driver Driver functions
127  *
128  * @return Zero on success, negative on failure
129  */
130 extern int bdk_device_add_driver(struct bdk_driver_s *driver);
131 
132 /**
133  * Called by the ECAM code whan a new device is detected in the system
134  *
135  * @param node   Node the ECAM is on
136  * @param ecam   ECAM the device is on
137  * @param bus    Bus number for the device
138  * @param dev    Device number
139  * @param func   Function number
140  *
141  * @return Zero on success, negative on failure
142  */
143 extern int bdk_device_add(bdk_node_t node, int ecam, int bus, int dev, int func);
144 
145 /**
146  * Rename a device. Called by driver to give devices friendly names
147  *
148  * @param device Device to rename
149  * @param format Printf style format string
150  */
151 extern void bdk_device_rename(bdk_device_t *device, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
152 
153 /**
154  * Called by the ECAM code once all devices have been added
155  *
156  * @return Zero on success, negative on failure
157  */
158 extern int bdk_device_init(void);
159 
160 /**
161  * Lookup a device by ECAM ID and internal instance number. This can be used by
162  * one device to find a handle to an associated device. For example, PKI would
163  * use this function to get a handle to the FPA.
164  *
165  * @param node     Node to lookup for
166  * @param id       ECAM ID
167  * @param instance Cavium internal instance number
168  *
169  * @return Device pointer, or NULL if the device isn't found
170  */
171 extern const bdk_device_t *bdk_device_lookup(bdk_node_t node, uint32_t id, int instance);
172 
173 /**
174  * Read from a device BAR
175  *
176  * @param device Device to read from
177  * @param bar    Which BAR to read from (0-3)
178  * @param size   Size of the read
179  * @param offset Offset into the BAR
180  *
181  * @return Value read
182  */
183 extern uint64_t bdk_bar_read(const bdk_device_t *device, int bar, int size, uint64_t offset);
184 
185 /**
186  * Write to a device BAR
187  *
188  * @param device Device to write to
189  * @param bar    Which BAR to read from (0-3)
190  * @param size   Size of the write
191  * @param offset Offset into the BAR
192  * @param value  Value to write
193  */
194 extern void bdk_bar_write(const bdk_device_t *device, int bar, int size, uint64_t offset, uint64_t value);
195 
196 /**
197  * This macro makes it easy to define a variable of the correct
198  * type for a BAR.
199  */
200 #define BDK_BAR_DEFINE(name, REG) typedef_##REG name
201 
202 /**
203  * This macro makes it easy to define a variable and initialize it
204  * with a BAR.
205  */
206 #define BDK_BAR_INIT(name, device, REG) typedef_##REG name = {.u = bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), REG)}
207 
208 /**
209  * Macro to read a BAR
210  */
211 #define BDK_BAR_READ(device, REG) bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), REG)
212 
213 /**
214  * Macro to write a BAR
215  */
216 #define BDK_BAR_WRITE(device, REG, value) bdk_bar_write(device, device_bar_##REG, sizeof(typedef_##REG), REG, value)
217 
218 /**
219  * Macro to make a read, modify, and write sequence easy. The "code_block"
220  * should be replaced with a C code block or a comma separated list of
221  * "name.s.field = value", without the quotes.
222  */
223 #define BDK_BAR_MODIFY(name, device, REG, code_block) do { \
224         uint64_t _tmp_address = REG; \
225         typedef_##REG name = {.u = bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), _tmp_address)}; \
226         code_block; \
227         bdk_bar_write(device, device_bar_##REG, sizeof(typedef_##REG), _tmp_address, name.u); \
228     } while (0)
229 
230 /**
231  * This macro spins on a field waiting for it to reach a value. It
232  * is common in code to need to wait for a specific field in a
233  * REG to match a specific value. Conceptually this macro
234  * expands to:
235  *
236  * 1) read REG
237  * 2) Check if ("type".s."field" "op" "value")
238  * 3) If #2 isn't true loop to #1 unless too much time has passed.
239  */
240 #define BDK_BAR_WAIT_FOR_FIELD(device, REG, field, op, value, timeout_usec) \
241     ({int result;                                                       \
242     do {                                                                \
243         uint64_t done = bdk_clock_get_count(BDK_CLOCK_TIME) + (uint64_t)timeout_usec * \
244                         bdk_clock_get_rate(bdk_numa_local(), BDK_CLOCK_TIME) / 1000000;   \
245         typedef_##REG c;                                                \
246         uint64_t _tmp_address = REG;                                    \
247         while (1)                                                       \
248         {                                                               \
249             c.u = bdk_bar_read(device, device_bar_##REG, sizeof(typedef_##REG), _tmp_address); \
250             if ((c.s.field) op (value)) {                               \
251                 result = 0;                                             \
252                 break;                                                  \
253             } else if (bdk_clock_get_count(BDK_CLOCK_TIME) > done) {    \
254                 result = -1;                                            \
255                 break;                                                  \
256             }                                                           \
257         }                                                               \
258     } while (0);                                                        \
259     result;})
260 
261 /** @} */
262 
263 #endif	/* !__CB_BDK_DEVICE_H__ */
264