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