1 /**
2  * @file
3  *
4  * @brief Public APIs for the PCIe EP drivers.
5  */
6 
7 /*
8  * SPDX-License-Identifier: Apache-2.0
9  *
10  * Copyright 2020 Broadcom
11  *
12  */
13 #ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_
14 #define ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_
15 
16 #include <device.h>
17 #include <init.h>
18 #include <kernel.h>
19 #include <stdint.h>
20 
21 enum pcie_ob_mem_type {
22 	PCIE_OB_ANYMEM,  /**< PCIe OB window within any address range */
23 	PCIE_OB_LOWMEM,  /**< PCIe OB window within 32-bit address range */
24 	PCIE_OB_HIGHMEM, /**< PCIe OB window above 32-bit address range */
25 };
26 
27 enum pci_ep_irq_type {
28 	PCIE_EP_IRQ_LEGACY,	/**< Raise Legacy interrupt */
29 	PCIE_EP_IRQ_MSI,	/**< Raise MSI interrupt */
30 	PCIE_EP_IRQ_MSIX,	/**< Raise MSIX interrupt */
31 };
32 
33 enum xfer_direction {
34 	HOST_TO_DEVICE,		/**< Read from Host */
35 	DEVICE_TO_HOST,		/**< Write to Host */
36 };
37 
38 enum pcie_reset {
39 	PCIE_PERST,	/**< Cold reset */
40 	PCIE_PERST_INB,	/**< Inband hot reset */
41 	PCIE_FLR,	/**< Functional Level Reset */
42 	PCIE_RESET_MAX
43 };
44 
45 /**
46  * @typedef pcie_ep_reset_callback_t
47  * @brief Callback API for PCIe reset interrupts
48  *
49  * These callbacks execute in interrupt context. Therefore, use only
50  * interrupt-safe APIS. Registration of callbacks is done via
51  * @a pcie_ep_register_reset_cb
52  *
53  * @param arg Pointer provided at registration time, later to be
54  *	  passed back as argument to callback function
55  */
56 
57 typedef void (*pcie_ep_reset_callback_t)(void *arg);
58 
59 struct pcie_ep_driver_api {
60 	int (*conf_read)(const struct device *dev, uint32_t offset,
61 			 uint32_t *data);
62 	void (*conf_write)(const struct device *dev, uint32_t offset,
63 			   uint32_t data);
64 	int (*map_addr)(const struct device *dev, uint64_t pcie_addr,
65 			uint64_t *mapped_addr, uint32_t size,
66 			enum pcie_ob_mem_type ob_mem_type);
67 	void (*unmap_addr)(const struct device *dev, uint64_t mapped_addr);
68 	int (*raise_irq)(const struct device *dev,
69 			 enum pci_ep_irq_type irq_type,
70 			 uint32_t irq_num);
71 	int (*register_reset_cb)(const struct device *dev,
72 				 enum pcie_reset reset,
73 				 pcie_ep_reset_callback_t cb, void *arg);
74 	int (*dma_xfer)(const struct device *dev, uint64_t mapped_addr,
75 			uintptr_t local_addr, uint32_t size,
76 			enum xfer_direction dir);
77 };
78 
79 /**
80  * @brief Read PCIe EP configuration space
81  *
82  * @details This API reads EP's own configuration space
83  *
84  * @param dev    Pointer to the device structure for the driver instance
85  * @param offset Offset within configuration space
86  * @param data   Pointer to data read from the offset
87  *
88  * @return 0 if successful, negative errno code if failure.
89  */
90 
pcie_ep_conf_read(const struct device * dev,uint32_t offset,uint32_t * data)91 static inline int pcie_ep_conf_read(const struct device *dev,
92 				    uint32_t offset, uint32_t *data)
93 {
94 	const struct pcie_ep_driver_api *api =
95 			(const struct pcie_ep_driver_api *)dev->api;
96 
97 	return api->conf_read(dev, offset, data);
98 }
99 
100 /**
101  * @brief Write PCIe EP configuration space
102  *
103  * @details This API writes EP's own configuration space
104  *
105  * @param dev    Pointer to the device structure for the driver instance
106  * @param offset Offset within configuration space
107  * @param data   Data to be written at the offset
108  *
109  * @return N/A
110  */
111 
pcie_ep_conf_write(const struct device * dev,uint32_t offset,uint32_t data)112 static inline void pcie_ep_conf_write(const struct device *dev,
113 				      uint32_t offset, uint32_t data)
114 {
115 	const struct pcie_ep_driver_api *api =
116 			(const struct pcie_ep_driver_api *)dev->api;
117 
118 	api->conf_write(dev, offset, data);
119 }
120 
121 /**
122  * @brief Map a host memory buffer to PCIe outbound region
123  *
124  * @details This API maps a host memory buffer to PCIe outbound region,
125  *	    It is left to EP driver to manage multiple mappings through
126  *	    multiple PCIe outbound regions if supported by SoC
127  *
128  * @param dev         Pointer to the device structure for the driver instance
129  * @param pcie_addr   Host memory buffer address to be mapped
130  * @param mapped_addr Mapped PCIe outbound region address
131  * @param size        Host memory buffer size (bytes)
132  * @param ob_mem_type Hint if lowmem/highmem outbound region has to be used,
133  *		      this is useful in cases where bus master cannot generate
134  *		      more than 32-bit address; it becomes essential to use
135  *		      lowmem outbound region
136  *
137  * @return Mapped size : If mapped size is less than requested size,
138  *	   then requestor has to call the same API again to map
139  *	   the unmapped host buffer after data transfer is done with
140  *	   mapped size. This situation may arise because of the
141  *	   mapping alignment requirements.
142  *
143  * @return Negative errno code if failure.
144  */
145 
pcie_ep_map_addr(const struct device * dev,uint64_t pcie_addr,uint64_t * mapped_addr,uint32_t size,enum pcie_ob_mem_type ob_mem_type)146 static inline int pcie_ep_map_addr(const struct device *dev,
147 				   uint64_t pcie_addr,
148 				   uint64_t *mapped_addr, uint32_t size,
149 				   enum pcie_ob_mem_type ob_mem_type)
150 {
151 	const struct pcie_ep_driver_api *api =
152 			(const struct pcie_ep_driver_api *)dev->api;
153 
154 	return api->map_addr(dev, pcie_addr, mapped_addr, size, ob_mem_type);
155 }
156 
157 /**
158  * @brief Remove mapping to PCIe outbound region
159  *
160  * @details This API removes mapping to PCIe outbound region.
161  *	    Mapped PCIe outbound region address is given as argument
162  *	    to figure out the outbound region to be unmapped
163  *
164  * @param dev         Pointer to the device structure for the driver instance
165  * @param mapped_addr PCIe outbound region address
166  *
167  * @return      N/A
168  */
169 
pcie_ep_unmap_addr(const struct device * dev,uint64_t mapped_addr)170 static inline void pcie_ep_unmap_addr(const struct device *dev,
171 				      uint64_t mapped_addr)
172 {
173 	const struct pcie_ep_driver_api *api =
174 			(const struct pcie_ep_driver_api *)dev->api;
175 
176 	api->unmap_addr(dev, mapped_addr);
177 }
178 
179 /**
180  * @brief Raise interrupt to Host
181  *
182  * @details This API raises interrupt to Host
183  *
184  * @param   dev      Pointer to the device structure for the driver instance
185  * @param   irq_type Type of Interrupt be raised (legacy, MSI or MSI-X)
186  * @param   irq_num  MSI or MSI-X interrupt number
187  *
188  * @return 0 if successful, negative errno code if failure.
189  */
190 
pcie_ep_raise_irq(const struct device * dev,enum pci_ep_irq_type irq_type,uint32_t irq_num)191 static inline int pcie_ep_raise_irq(const struct device *dev,
192 				    enum pci_ep_irq_type irq_type,
193 				    uint32_t irq_num)
194 {
195 	const struct pcie_ep_driver_api *api =
196 			(const struct pcie_ep_driver_api *)dev->api;
197 	return api->raise_irq(dev, irq_type, irq_num);
198 }
199 
200 /**
201  * @brief Register callback function for reset interrupts
202  *
203  * @details If reset interrupts are handled by device, this API can be
204  *	    used to register callback function, which will be
205  *	    executed part of corresponding PCIe reset handler
206  *
207  * @param   dev   Pointer to the device structure for the driver instance
208  * @param   reset Reset interrupt type
209  * @param   cb    Callback function being registered
210  * @param   arg   Argument to be passed back to callback function
211  *
212  * @return 0 if successful, negative errno code if failure.
213  */
214 
pcie_ep_register_reset_cb(const struct device * dev,enum pcie_reset reset,pcie_ep_reset_callback_t cb,void * arg)215 static inline int pcie_ep_register_reset_cb(const struct device *dev,
216 					    enum pcie_reset reset,
217 					    pcie_ep_reset_callback_t cb,
218 					    void *arg)
219 {
220 	const struct pcie_ep_driver_api *api =
221 			(const struct pcie_ep_driver_api *)dev->api;
222 
223 	if (api->register_reset_cb) {
224 		return api->register_reset_cb(dev, reset, cb, arg);
225 	}
226 
227 	return -ENOTSUP;
228 }
229 
230 /**
231  * @brief Data transfer between mapped Host memory and device memory with
232  *	  "System DMA". The term "System DMA" is used to clarify that we
233  *	  are not talking about dedicated "PCIe DMA"; rather the one
234  *	  which does not understand PCIe address directly, and
235  *	  uses the mapped Host memory.
236  *
237  * @details If DMA controller is available in the EP device, this API can be
238  *	    used to achieve data transfer between mapped Host memory,
239  *	    i.e. outbound memory and EP device's local memory with DMA
240  *
241  * @param   dev         Pointer to the device structure for the driver instance
242  * @param   mapped_addr Mapped Host memory address
243  * @param   local_addr  Device memory address
244  * @param   size        DMA transfer length (bytes)
245  * @param   dir         Direction of DMA transfer
246  *
247  * @return 0 if successful, negative errno code if failure.
248  */
249 
pcie_ep_dma_xfer(const struct device * dev,uint64_t mapped_addr,uintptr_t local_addr,uint32_t size,const enum xfer_direction dir)250 static inline int pcie_ep_dma_xfer(const struct device *dev,
251 				   uint64_t mapped_addr,
252 				   uintptr_t local_addr, uint32_t size,
253 				   const enum xfer_direction dir)
254 {
255 	const struct pcie_ep_driver_api *api =
256 			(const struct pcie_ep_driver_api *)dev->api;
257 
258 	if (api->dma_xfer) {
259 		return api->dma_xfer(dev, mapped_addr, local_addr, size, dir);
260 	}
261 
262 	return -ENOTSUP;
263 }
264 
265 /**
266  * @brief Data transfer using memcpy
267  *
268  * @details Helper API to achieve data transfer with memcpy
269  *          through PCIe outbound memory
270  *
271  * @param dev         Pointer to the device structure for the driver instance
272  * @param pcie_addr   Host memory buffer address
273  * @param local_addr  Local memory buffer address
274  * @param size        Data transfer size (bytes)
275  * @param ob_mem_type Hint if lowmem/highmem outbound region has to be used
276  *                    (PCIE_OB_LOWMEM / PCIE_OB_HIGHMEM / PCIE_OB_ANYMEM),
277  *                    should be PCIE_OB_LOWMEM if bus master cannot generate
278  *                    more than 32-bit address
279  * @param dir         Data transfer direction (HOST_TO_DEVICE / DEVICE_TO_HOST)
280  *
281  * @return 0 if successful, negative errno code if failure.
282  */
283 int pcie_ep_xfer_data_memcpy(const struct device *dev, uint64_t pcie_addr,
284 			     uintptr_t *local_addr, uint32_t size,
285 			     enum pcie_ob_mem_type ob_mem_type,
286 			     enum xfer_direction dir);
287 
288 /**
289  * @brief Data transfer using system DMA
290  *
291  * @details Helper API to achieve data transfer with system DMA through PCIe
292  *          outbound memory, this API is based off pcie_ep_xfer_data_memcpy,
293  *          here we use "system dma" instead of memcpy
294  *
295  * @param dev         Pointer to the device structure for the driver instance
296  * @param pcie_addr   Host memory buffer address
297  * @param local_addr  Local memory buffer address
298  * @param size        Data transfer size (bytes)
299  * @param ob_mem_type Hint if lowmem/highmem outbound region has to be used
300  *                    (PCIE_OB_LOWMEM / PCIE_OB_HIGHMEM / PCIE_OB_ANYMEM)
301  * @param dir         Data transfer direction (HOST_TO_DEVICE / DEVICE_TO_HOST)
302  *
303  * @return 0 if successful, negative errno code if failure.
304  */
305 int pcie_ep_xfer_data_dma(const struct device *dev, uint64_t pcie_addr,
306 			  uintptr_t *local_addr, uint32_t size,
307 			  enum pcie_ob_mem_type ob_mem_type,
308 			  enum xfer_direction dir);
309 
310 #endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_ */
311