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