1 /*
2  * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * @file	device.h
9  * @brief	Bus abstraction for libmetal.
10  */
11 
12 #ifndef __METAL_BUS__H__
13 #define __METAL_BUS__H__
14 
15 #include <stdint.h>
16 #include <metal/io.h>
17 #include <metal/list.h>
18 #include <metal/dma.h>
19 #include <metal/sys.h>
20 
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24 
25 /** \defgroup device Bus Abstraction
26  *  @{ */
27 
28 #ifndef METAL_MAX_DEVICE_REGIONS
29 #define METAL_MAX_DEVICE_REGIONS	32
30 #endif
31 
32 struct metal_bus;
33 struct metal_device;
34 
35 /** Bus operations. */
36 struct metal_bus_ops {
37 	void		(*bus_close)(struct metal_bus *bus);
38 	int		(*dev_open)(struct metal_bus *bus,
39 				    const char *dev_name,
40 				    struct metal_device **device);
41 	void		(*dev_close)(struct metal_bus *bus,
42 				     struct metal_device *device);
43 	void		(*dev_irq_ack)(struct metal_bus *bus,
44 				     struct metal_device *device,
45 				     int irq);
46 	int		(*dev_dma_map)(struct metal_bus *bus,
47 				       struct metal_device *device,
48 				       uint32_t dir,
49 				       struct metal_sg *sg_in,
50 				       int nents_in,
51 				       struct metal_sg *sg_out);
52 	void		(*dev_dma_unmap)(struct metal_bus *bus,
53 				       struct metal_device *device,
54 				       uint32_t dir,
55 				       struct metal_sg *sg,
56 				       int nents);
57 };
58 
59 /** Libmetal bus structure. */
60 struct metal_bus {
61 	const char		*name;
62 	struct metal_bus_ops	ops;
63 	struct metal_list	devices;
64 	struct metal_list	node;
65 };
66 
67 /** Libmetal generic bus. */
68 extern struct metal_bus metal_generic_bus;
69 
70 /** Libmetal device structure. */
71 struct metal_device {
72 	const char             *name;       /**< Device name */
73 	struct metal_bus       *bus;        /**< Bus that contains device */
74 	unsigned               num_regions; /**< Number of I/O regions in
75 					      device */
76 	struct metal_io_region regions[METAL_MAX_DEVICE_REGIONS]; /**< Array of
77                                                         I/O regions in device*/
78 	struct metal_list      node;       /**< Node on bus' list of devices */
79 	int                    irq_num;    /**< Number of IRQs per device */
80 	void                   *irq_info;  /**< IRQ ID */
81 };
82 
83 /**
84  * @brief	Register a libmetal bus.
85  * @param[in]	bus	Pre-initialized bus structure.
86  * @return 0 on success, or -errno on failure.
87  */
88 extern int metal_bus_register(struct metal_bus *bus);
89 
90 /**
91  * @brief	Unregister a libmetal bus.
92  * @param[in]	bus	Pre-registered bus structure.
93  * @return 0 on success, or -errno on failure.
94  */
95 extern int metal_bus_unregister(struct metal_bus *bus);
96 
97 /**
98  * @brief	Find a libmetal bus by name.
99  * @param[in]	name	Bus name.
100  * @param[out]	bus	Returned bus handle.
101  * @return 0 on success, or -errno on failure.
102  */
103 extern int metal_bus_find(const char *name, struct metal_bus **bus);
104 
105 /**
106  * @brief	Statically register a generic libmetal device.
107  *
108  * In non-Linux systems, devices are always required to be statically
109  * registered at application initialization.
110  * In Linux system, devices can be dynamically opened via sysfs or libfdt based
111  * enumeration at runtime.
112  * This interface is used for static registration of devices. Subsequent calls
113  * to metal_device_open() look up in this list of pre-registered devices on the
114  * "generic" bus.
115  * "generic" bus is used on non-Linux system to group the memory mapped devices.
116  *
117  * @param[in]	device	Generic device.
118  * @return 0 on success, or -errno on failure.
119  */
120 extern int metal_register_generic_device(struct metal_device *device);
121 
122 /**
123  * @brief	Open a libmetal device by name.
124  * @param[in]	bus_name	Bus name.
125  * @param[in]	dev_name	Device name.
126  * @param[out]	device		Returned device handle.
127  * @return 0 on success, or -errno on failure.
128  */
129 extern int metal_device_open(const char *bus_name, const char *dev_name,
130 			     struct metal_device **device);
131 
132 /**
133  * @brief	Close a libmetal device.
134  * @param[in]	device		Device handle.
135  */
136 extern void metal_device_close(struct metal_device *device);
137 
138 /**
139  * @brief	Get an I/O region accessor for a device region.
140  *
141  * @param[in]	device		Device handle.
142  * @param[in]	index		Region index.
143  * @return I/O accessor handle, or NULL on failure.
144  */
145 static inline struct metal_io_region *
metal_device_io_region(struct metal_device * device,unsigned index)146 metal_device_io_region(struct metal_device *device, unsigned index)
147 {
148 	return (index < device->num_regions
149 		? &device->regions[index]
150 		: NULL);
151 }
152 
153 /** @} */
154 
155 #ifdef METAL_INTERNAL
156 extern int metal_generic_dev_sys_open(struct metal_device *dev);
157 extern int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name,
158 				  struct metal_device **device);
159 extern int metal_generic_dev_dma_map(struct metal_bus *bus,
160 				     struct metal_device *device,
161 				     uint32_t dir,
162 				     struct metal_sg *sg_in,
163 				     int nents_in,
164 				     struct metal_sg *sg_out);
165 extern void metal_generic_dev_dma_unmap(struct metal_bus *bus,
166 					struct metal_device *device,
167 					uint32_t dir,
168 					struct metal_sg *sg,
169 					int nents);
170 #endif /* METAL_INTERNAL */
171 
172 #ifdef __cplusplus
173 }
174 #endif
175 
176 #endif /* __METAL_BUS__H__ */
177