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 <zephyr/device.h>
17 #include <zephyr/init.h>
18 #include <zephyr/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
pcie_ep_conf_write(const struct device * dev,uint32_t offset,uint32_t data)110 static inline void pcie_ep_conf_write(const struct device *dev,
111 uint32_t offset, uint32_t data)
112 {
113 const struct pcie_ep_driver_api *api =
114 (const struct pcie_ep_driver_api *)dev->api;
115
116 api->conf_write(dev, offset, data);
117 }
118
119 /**
120 * @brief Map a host memory buffer to PCIe outbound region
121 *
122 * @details This API maps a host memory buffer to PCIe outbound region,
123 * It is left to EP driver to manage multiple mappings through
124 * multiple PCIe outbound regions if supported by SoC
125 *
126 * @param dev Pointer to the device structure for the driver instance
127 * @param pcie_addr Host memory buffer address to be mapped
128 * @param mapped_addr Mapped PCIe outbound region address
129 * @param size Host memory buffer size (bytes)
130 * @param ob_mem_type Hint if lowmem/highmem outbound region has to be used,
131 * this is useful in cases where bus master cannot generate
132 * more than 32-bit address; it becomes essential to use
133 * lowmem outbound region
134 *
135 * @return Mapped size : If mapped size is less than requested size,
136 * then requestor has to call the same API again to map
137 * the unmapped host buffer after data transfer is done with
138 * mapped size. This situation may arise because of the
139 * mapping alignment requirements.
140 *
141 * @return Negative errno code if failure.
142 */
143
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)144 static inline int pcie_ep_map_addr(const struct device *dev,
145 uint64_t pcie_addr,
146 uint64_t *mapped_addr, uint32_t size,
147 enum pcie_ob_mem_type ob_mem_type)
148 {
149 const struct pcie_ep_driver_api *api =
150 (const struct pcie_ep_driver_api *)dev->api;
151
152 return api->map_addr(dev, pcie_addr, mapped_addr, size, ob_mem_type);
153 }
154
155 /**
156 * @brief Remove mapping to PCIe outbound region
157 *
158 * @details This API removes mapping to PCIe outbound region.
159 * Mapped PCIe outbound region address is given as argument
160 * to figure out the outbound region to be unmapped
161 *
162 * @param dev Pointer to the device structure for the driver instance
163 * @param mapped_addr PCIe outbound region address
164 */
165
pcie_ep_unmap_addr(const struct device * dev,uint64_t mapped_addr)166 static inline void pcie_ep_unmap_addr(const struct device *dev,
167 uint64_t mapped_addr)
168 {
169 const struct pcie_ep_driver_api *api =
170 (const struct pcie_ep_driver_api *)dev->api;
171
172 api->unmap_addr(dev, mapped_addr);
173 }
174
175 /**
176 * @brief Raise interrupt to Host
177 *
178 * @details This API raises interrupt to Host
179 *
180 * @param dev Pointer to the device structure for the driver instance
181 * @param irq_type Type of Interrupt be raised (legacy, MSI or MSI-X)
182 * @param irq_num MSI or MSI-X interrupt number
183 *
184 * @return 0 if successful, negative errno code if failure.
185 */
186
pcie_ep_raise_irq(const struct device * dev,enum pci_ep_irq_type irq_type,uint32_t irq_num)187 static inline int pcie_ep_raise_irq(const struct device *dev,
188 enum pci_ep_irq_type irq_type,
189 uint32_t irq_num)
190 {
191 const struct pcie_ep_driver_api *api =
192 (const struct pcie_ep_driver_api *)dev->api;
193 return api->raise_irq(dev, irq_type, irq_num);
194 }
195
196 /**
197 * @brief Register callback function for reset interrupts
198 *
199 * @details If reset interrupts are handled by device, this API can be
200 * used to register callback function, which will be
201 * executed part of corresponding PCIe reset handler
202 *
203 * @param dev Pointer to the device structure for the driver instance
204 * @param reset Reset interrupt type
205 * @param cb Callback function being registered
206 * @param arg Argument to be passed back to callback function
207 *
208 * @return 0 if successful, negative errno code if failure.
209 */
210
pcie_ep_register_reset_cb(const struct device * dev,enum pcie_reset reset,pcie_ep_reset_callback_t cb,void * arg)211 static inline int pcie_ep_register_reset_cb(const struct device *dev,
212 enum pcie_reset reset,
213 pcie_ep_reset_callback_t cb,
214 void *arg)
215 {
216 const struct pcie_ep_driver_api *api =
217 (const struct pcie_ep_driver_api *)dev->api;
218
219 if (api->register_reset_cb) {
220 return api->register_reset_cb(dev, reset, cb, arg);
221 }
222
223 return -ENOTSUP;
224 }
225
226 /**
227 * @brief Data transfer between mapped Host memory and device memory with
228 * "System DMA". The term "System DMA" is used to clarify that we
229 * are not talking about dedicated "PCIe DMA"; rather the one
230 * which does not understand PCIe address directly, and
231 * uses the mapped Host memory.
232 *
233 * @details If DMA controller is available in the EP device, this API can be
234 * used to achieve data transfer between mapped Host memory,
235 * i.e. outbound memory and EP device's local memory with DMA
236 *
237 * @param dev Pointer to the device structure for the driver instance
238 * @param mapped_addr Mapped Host memory address
239 * @param local_addr Device memory address
240 * @param size DMA transfer length (bytes)
241 * @param dir Direction of DMA transfer
242 *
243 * @return 0 if successful, negative errno code if failure.
244 */
245
pcie_ep_dma_xfer(const struct device * dev,uint64_t mapped_addr,uintptr_t local_addr,uint32_t size,const enum xfer_direction dir)246 static inline int pcie_ep_dma_xfer(const struct device *dev,
247 uint64_t mapped_addr,
248 uintptr_t local_addr, uint32_t size,
249 const enum xfer_direction dir)
250 {
251 const struct pcie_ep_driver_api *api =
252 (const struct pcie_ep_driver_api *)dev->api;
253
254 if (api->dma_xfer) {
255 return api->dma_xfer(dev, mapped_addr, local_addr, size, dir);
256 }
257
258 return -ENOTSUP;
259 }
260
261 /**
262 * @brief Data transfer using memcpy
263 *
264 * @details Helper API to achieve data transfer with memcpy
265 * through PCIe outbound memory
266 *
267 * @param dev Pointer to the device structure for the driver instance
268 * @param pcie_addr Host memory buffer address
269 * @param local_addr Local memory buffer address
270 * @param size Data transfer size (bytes)
271 * @param ob_mem_type Hint if lowmem/highmem outbound region has to be used
272 * (PCIE_OB_LOWMEM / PCIE_OB_HIGHMEM / PCIE_OB_ANYMEM),
273 * should be PCIE_OB_LOWMEM if bus master cannot generate
274 * more than 32-bit address
275 * @param dir Data transfer direction (HOST_TO_DEVICE / DEVICE_TO_HOST)
276 *
277 * @return 0 if successful, negative errno code if failure.
278 */
279 int pcie_ep_xfer_data_memcpy(const struct device *dev, uint64_t pcie_addr,
280 uintptr_t *local_addr, uint32_t size,
281 enum pcie_ob_mem_type ob_mem_type,
282 enum xfer_direction dir);
283
284 /**
285 * @brief Data transfer using system DMA
286 *
287 * @details Helper API to achieve data transfer with system DMA through PCIe
288 * outbound memory, this API is based off pcie_ep_xfer_data_memcpy,
289 * here we use "system dma" instead of memcpy
290 *
291 * @param dev Pointer to the device structure for the driver instance
292 * @param pcie_addr Host memory buffer address
293 * @param local_addr Local memory buffer address
294 * @param size Data transfer size (bytes)
295 * @param ob_mem_type Hint if lowmem/highmem outbound region has to be used
296 * (PCIE_OB_LOWMEM / PCIE_OB_HIGHMEM / PCIE_OB_ANYMEM)
297 * @param dir Data transfer direction (HOST_TO_DEVICE / DEVICE_TO_HOST)
298 *
299 * @return 0 if successful, negative errno code if failure.
300 */
301 int pcie_ep_xfer_data_dma(const struct device *dev, uint64_t pcie_addr,
302 uintptr_t *local_addr, uint32_t size,
303 enum pcie_ob_mem_type ob_mem_type,
304 enum xfer_direction dir);
305
306 #endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_ */
307