1 /**
2 * @file
3 *
4 * @brief Public APIs for the PCIe Controllers drivers.
5 */
6
7 /*
8 * Copyright (c) 2021 BayLibre, SAS
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12 #ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_CONTROLLERS_H_
13 #define ZEPHYR_INCLUDE_DRIVERS_PCIE_CONTROLLERS_H_
14
15 #include <zephyr/types.h>
16 #include <zephyr/device.h>
17
18 #ifdef CONFIG_PCIE_MSI
19 #include <zephyr/drivers/pcie/msi.h>
20 #endif
21
22 /**
23 * @brief PCI Express Controller Interface
24 * @defgroup pcie_controller_interface PCI Express Controller Interface
25 * @ingroup io_interfaces
26 * @{
27 */
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 /**
34 * @brief Function called to read a 32-bit word from an endpoint's configuration space.
35 *
36 * Read a 32-bit word from an endpoint's configuration space with the PCI Express Controller
37 * configuration space access method (I/O port, memory mapped or custom method)
38 *
39 * @param dev PCI Express Controller device pointer
40 * @param bdf PCI(e) endpoint
41 * @param reg the configuration word index (not address)
42 * @return the word read (0xFFFFFFFFU if nonexistent endpoint or word)
43 */
44 typedef uint32_t (*pcie_ctrl_conf_read_t)(const struct device *dev, pcie_bdf_t bdf,
45 unsigned int reg);
46
47 /**
48 * @brief Function called to write a 32-bit word to an endpoint's configuration space.
49 *
50 * Write a 32-bit word to an endpoint's configuration space with the PCI Express Controller
51 * configuration space access method (I/O port, memory mapped or custom method)
52 *
53 * @param dev PCI Express Controller device pointer
54 * @param bdf PCI(e) endpoint
55 * @param reg the configuration word index (not address)
56 * @param data the value to write
57 */
58 typedef void (*pcie_ctrl_conf_write_t)(const struct device *dev, pcie_bdf_t bdf,
59 unsigned int reg, uint32_t data);
60
61 /**
62 * @brief Function called to allocate a memory region subset for an endpoint Base Address Register.
63 *
64 * When enumerating PCIe Endpoints, Type0 endpoints can require up to 6 memory zones
65 * via the Base Address Registers from I/O or Memory types.
66 *
67 * This call allocates such zone in the PCI Express Controller memory regions if
68 * such region is available and space is still available.
69 *
70 * @param dev PCI Express Controller device pointer
71 * @param bdf PCI(e) endpoint
72 * @param mem True if the BAR is of memory type
73 * @param mem64 True if the BAR is of 64bit memory type
74 * @param bar_size Size in bytes of the Base Address Register as returned by HW
75 * @param bar_bus_addr bus-centric address allocated to be written in the BAR register
76 * @return True if allocation was possible, False if allocation failed
77 */
78 typedef bool (*pcie_ctrl_region_allocate_t)(const struct device *dev, pcie_bdf_t bdf,
79 bool mem, bool mem64, size_t bar_size,
80 uintptr_t *bar_bus_addr);
81
82 /**
83 * @brief Function called to get the current allocation base of a memory region subset
84 * for an endpoint Base Address Register.
85 *
86 * When enumerating PCIe Endpoints, Type1 bridge endpoints requires a range of memory
87 * allocated by all endpoints in the bridged bus.
88 *
89 * @param dev PCI Express Controller device pointer
90 * @param bdf PCI(e) endpoint
91 * @param mem True if the BAR is of memory type
92 * @param mem64 True if the BAR is of 64bit memory type
93 * @param align size to take in account for alignment
94 * @param bar_base_addr bus-centric address allocation base
95 * @return True if allocation was possible, False if allocation failed
96 */
97 typedef bool (*pcie_ctrl_region_get_allocate_base_t)(const struct device *dev, pcie_bdf_t bdf,
98 bool mem, bool mem64, size_t align,
99 uintptr_t *bar_base_addr);
100
101 /**
102 * @brief Function called to translate an endpoint Base Address Register bus-centric address
103 * into Physical address.
104 *
105 * When enumerating PCIe Endpoints, Type0 endpoints can require up to 6 memory zones
106 * via the Base Address Registers from I/O or Memory types.
107 *
108 * The bus-centric address set in this BAR register is not necessarily accessible from the CPU,
109 * thus must be translated by using the PCI Express Controller memory regions translation
110 * ranges to permit mapping from the CPU.
111 *
112 * @param dev PCI Express Controller device pointer
113 * @param bdf PCI(e) endpoint
114 * @param mem True if the BAR is of memory type
115 * @param mem64 True if the BAR is of 64bit memory type
116 * @param bar_bus_addr bus-centric address written in the BAR register
117 * @param bar_addr CPU-centric address translated from the bus-centric address
118 * @return True if translation was possible, False if translation failed
119 */
120 typedef bool (*pcie_ctrl_region_translate_t)(const struct device *dev, pcie_bdf_t bdf,
121 bool mem, bool mem64, uintptr_t bar_bus_addr,
122 uintptr_t *bar_addr);
123
124 #ifdef CONFIG_PCIE_MSI
125 typedef uint8_t (*pcie_ctrl_msi_device_setup_t)(const struct device *dev, unsigned int priority,
126 msi_vector_t *vectors, uint8_t n_vector);
127 #endif
128
129 /**
130 * @brief Read a 32-bit word from a Memory-Mapped endpoint's configuration space.
131 *
132 * Read a 32-bit word from an endpoint's configuration space from a Memory-Mapped
133 * configuration space access method, known as PCI Control Access Method (CAM) or
134 * PCIe Extended Control Access Method (ECAM).
135 *
136 * @param cfg_addr Logical address of Memory-Mapped configuration space
137 * @param bdf PCI(e) endpoint
138 * @param reg the configuration word index (not address)
139 * @return the word read (0xFFFFFFFFU if nonexistent endpoint or word)
140 */
141 uint32_t pcie_generic_ctrl_conf_read(mm_reg_t cfg_addr, pcie_bdf_t bdf, unsigned int reg);
142
143
144 /**
145 * @brief Write a 32-bit word to a Memory-Mapped endpoint's configuration space.
146 *
147 * Write a 32-bit word to an endpoint's configuration space from a Memory-Mapped
148 * configuration space access method, known as PCI Control Access Method (CAM) or
149 * PCIe Extended Control Access Method (ECAM).
150 *
151 * @param cfg_addr Logical address of Memory-Mapped configuration space
152 * @param bdf PCI(e) endpoint
153 * @param reg the configuration word index (not address)
154 * @param data the value to write
155 */
156 void pcie_generic_ctrl_conf_write(mm_reg_t cfg_addr, pcie_bdf_t bdf,
157 unsigned int reg, uint32_t data);
158
159 /**
160 * @brief Start PCIe Endpoints enumeration.
161 *
162 * Start a PCIe Endpoints enumeration from a Bus number.
163 * When on non-x86 architecture or when firmware didn't setup the PCIe Bus hierarchy,
164 * the PCIe bus complex must be enumerated to setup the Endpoints Base Address Registers.
165 *
166 * @param dev PCI Express Controller device pointer
167 * @param bdf_start PCI(e) start endpoint (only bus & dev are used to start enumeration)
168 */
169 void pcie_generic_ctrl_enumerate(const struct device *dev, pcie_bdf_t bdf_start);
170
171 /** @brief Structure providing callbacks to be implemented for devices
172 * that supports the PCI Express Controller API
173 */
174 __subsystem struct pcie_ctrl_driver_api {
175 pcie_ctrl_conf_read_t conf_read;
176 pcie_ctrl_conf_write_t conf_write;
177 pcie_ctrl_region_allocate_t region_allocate;
178 pcie_ctrl_region_get_allocate_base_t region_get_allocate_base;
179 pcie_ctrl_region_translate_t region_translate;
180 #ifdef CONFIG_PCIE_MSI
181 pcie_ctrl_msi_device_setup_t msi_device_setup;
182 #endif
183 };
184
185 /**
186 * @brief Read a 32-bit word from an endpoint's configuration space.
187 *
188 * Read a 32-bit word from an endpoint's configuration space with the PCI Express Controller
189 * configuration space access method (I/O port, memory mapped or custom method)
190 *
191 * @param dev PCI Express Controller device pointer
192 * @param bdf PCI(e) endpoint
193 * @param reg the configuration word index (not address)
194 * @return the word read (0xFFFFFFFFU if nonexistent endpoint or word)
195 */
pcie_ctrl_conf_read(const struct device * dev,pcie_bdf_t bdf,unsigned int reg)196 static inline uint32_t pcie_ctrl_conf_read(const struct device *dev, pcie_bdf_t bdf,
197 unsigned int reg)
198 {
199 const struct pcie_ctrl_driver_api *api =
200 (const struct pcie_ctrl_driver_api *)dev->api;
201
202 return api->conf_read(dev, bdf, reg);
203 }
204
205 /**
206 * @brief Write a 32-bit word to an endpoint's configuration space.
207 *
208 * Write a 32-bit word to an endpoint's configuration space with the PCI Express Controller
209 * configuration space access method (I/O port, memory mapped or custom method)
210 *
211 * @param dev PCI Express Controller device pointer
212 * @param bdf PCI(e) endpoint
213 * @param reg the configuration word index (not address)
214 * @param data the value to write
215 */
pcie_ctrl_conf_write(const struct device * dev,pcie_bdf_t bdf,unsigned int reg,uint32_t data)216 static inline void pcie_ctrl_conf_write(const struct device *dev, pcie_bdf_t bdf,
217 unsigned int reg, uint32_t data)
218 {
219 const struct pcie_ctrl_driver_api *api =
220 (const struct pcie_ctrl_driver_api *)dev->api;
221
222 api->conf_write(dev, bdf, reg, data);
223 }
224
225 /**
226 * @brief Allocate a memory region subset for an endpoint Base Address Register.
227 *
228 * When enumerating PCIe Endpoints, Type0 endpoints can require up to 6 memory zones
229 * via the Base Address Registers from I/O or Memory types.
230 *
231 * This call allocates such zone in the PCI Express Controller memory regions if
232 * such region is available and space is still available.
233 *
234 * @param dev PCI Express Controller device pointer
235 * @param bdf PCI(e) endpoint
236 * @param mem True if the BAR is of memory type
237 * @param mem64 True if the BAR is of 64bit memory type
238 * @param bar_size Size in bytes of the Base Address Register as returned by HW
239 * @param bar_bus_addr bus-centric address allocated to be written in the BAR register
240 * @return True if allocation was possible, False if allocation failed
241 */
pcie_ctrl_region_allocate(const struct device * dev,pcie_bdf_t bdf,bool mem,bool mem64,size_t bar_size,uintptr_t * bar_bus_addr)242 static inline bool pcie_ctrl_region_allocate(const struct device *dev, pcie_bdf_t bdf,
243 bool mem, bool mem64, size_t bar_size,
244 uintptr_t *bar_bus_addr)
245 {
246 const struct pcie_ctrl_driver_api *api =
247 (const struct pcie_ctrl_driver_api *)dev->api;
248
249 return api->region_allocate(dev, bdf, mem, mem64, bar_size, bar_bus_addr);
250 }
251
252 /**
253 * @brief Function called to get the current allocation base of a memory region subset
254 * for an endpoint Base Address Register.
255 *
256 * When enumerating PCIe Endpoints, Type1 bridge endpoints requires a range of memory
257 * allocated by all endpoints in the bridged bus.
258 *
259 * @param dev PCI Express Controller device pointer
260 * @param bdf PCI(e) endpoint
261 * @param mem True if the BAR is of memory type
262 * @param mem64 True if the BAR is of 64bit memory type
263 * @param align size to take in account for alignment
264 * @param bar_base_addr bus-centric address allocation base
265 * @return True if allocation was possible, False if allocation failed
266 */
pcie_ctrl_region_get_allocate_base(const struct device * dev,pcie_bdf_t bdf,bool mem,bool mem64,size_t align,uintptr_t * bar_base_addr)267 static inline bool pcie_ctrl_region_get_allocate_base(const struct device *dev, pcie_bdf_t bdf,
268 bool mem, bool mem64, size_t align,
269 uintptr_t *bar_base_addr)
270 {
271 const struct pcie_ctrl_driver_api *api =
272 (const struct pcie_ctrl_driver_api *)dev->api;
273
274 return api->region_get_allocate_base(dev, bdf, mem, mem64, align, bar_base_addr);
275 }
276
277 /**
278 * @brief Translate an endpoint Base Address Register bus-centric address into Physical address.
279 *
280 * When enumerating PCIe Endpoints, Type0 endpoints can require up to 6 memory zones
281 * via the Base Address Registers from I/O or Memory types.
282 *
283 * The bus-centric address set in this BAR register is not necessarily accessible from the CPU,
284 * thus must be translated by using the PCI Express Controller memory regions translation
285 * ranges to permit mapping from the CPU.
286 *
287 * @param dev PCI Express Controller device pointer
288 * @param bdf PCI(e) endpoint
289 * @param mem True if the BAR is of memory type
290 * @param mem64 True if the BAR is of 64bit memory type
291 * @param bar_bus_addr bus-centric address written in the BAR register
292 * @param bar_addr CPU-centric address translated from the bus-centric address
293 * @return True if translation was possible, False if translation failed
294 */
pcie_ctrl_region_translate(const struct device * dev,pcie_bdf_t bdf,bool mem,bool mem64,uintptr_t bar_bus_addr,uintptr_t * bar_addr)295 static inline bool pcie_ctrl_region_translate(const struct device *dev, pcie_bdf_t bdf,
296 bool mem, bool mem64, uintptr_t bar_bus_addr,
297 uintptr_t *bar_addr)
298 {
299 const struct pcie_ctrl_driver_api *api =
300 (const struct pcie_ctrl_driver_api *)dev->api;
301
302 if (!api->region_translate) {
303 *bar_addr = bar_bus_addr;
304 return true;
305 } else {
306 return api->region_translate(dev, bdf, mem, mem64, bar_bus_addr, bar_addr);
307 }
308 }
309
310 #ifdef CONFIG_PCIE_MSI
pcie_ctrl_msi_device_setup(const struct device * dev,unsigned int priority,msi_vector_t * vectors,uint8_t n_vector)311 static inline uint8_t pcie_ctrl_msi_device_setup(const struct device *dev, unsigned int priority,
312 msi_vector_t *vectors, uint8_t n_vector)
313 {
314 const struct pcie_ctrl_driver_api *api =
315 (const struct pcie_ctrl_driver_api *)dev->api;
316
317 return api->msi_device_setup(dev, priority, vectors, n_vector);
318 }
319 #endif
320
321 /** @brief Structure describing a device that supports the PCI Express Controller API
322 */
323 struct pcie_ctrl_config {
324 #ifdef CONFIG_PCIE_MSI
325 const struct device *msi_parent;
326 #endif
327 /* Configuration space physical address */
328 uintptr_t cfg_addr;
329 /* Configuration space physical size */
330 size_t cfg_size;
331 /* BAR regions translation ranges count */
332 size_t ranges_count;
333 /* BAR regions translation ranges table */
334 struct {
335 /* Flags as defined in the PCI Bus Binding to IEEE Std 1275-1994 */
336 uint32_t flags;
337 /* bus-centric offset from the start of the region */
338 uintptr_t pcie_bus_addr;
339 /* CPU-centric offset from the start of the region */
340 uintptr_t host_map_addr;
341 /* region size */
342 size_t map_length;
343 } ranges[];
344 };
345
346 /*
347 * Fills the pcie_ctrl_config.ranges table from DT
348 */
349 #define PCIE_RANGE_FORMAT(node_id, idx) \
350 { \
351 .flags = DT_RANGES_CHILD_BUS_FLAGS_BY_IDX(node_id, idx), \
352 .pcie_bus_addr = DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(node_id, idx), \
353 .host_map_addr = DT_RANGES_PARENT_BUS_ADDRESS_BY_IDX(node_id, idx), \
354 .map_length = DT_RANGES_LENGTH_BY_IDX(node_id, idx), \
355 },
356
357 #ifdef __cplusplus
358 }
359 #endif
360
361 /**
362 * @}
363 */
364
365 #endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_CONTROLLERS_H_ */
366