xref: /optee_os/core/include/kernel/dt_driver.h (revision 6f9a437380a59f0e4f4f41aeb2cb846077eec54e)
18c0c44c9SEtienne Carriere /* SPDX-License-Identifier: BSD-2-Clause */
28c0c44c9SEtienne Carriere /*
38c0c44c9SEtienne Carriere  * Copyright (c) 2021, Linaro Limited
48c0c44c9SEtienne Carriere  * Copyright (c) 2021, Bootlin
5b3a88b52SEtienne Carriere  * Copyright (c) 2021, STMicroelectronics
68c0c44c9SEtienne Carriere  */
78c0c44c9SEtienne Carriere 
8fbe66cf8SEtienne Carriere #ifndef __KERNEL_DT_DRIVER_H
9fbe66cf8SEtienne Carriere #define __KERNEL_DT_DRIVER_H
108c0c44c9SEtienne Carriere 
118c0c44c9SEtienne Carriere #include <kernel/dt.h>
128c0c44c9SEtienne Carriere #include <stdint.h>
138c0c44c9SEtienne Carriere #include <sys/queue.h>
143fd340e5SEtienne Carriere #include <tee_api_types.h>
158c0c44c9SEtienne Carriere 
169e3c57c8SEtienne Carriere /*
179e3c57c8SEtienne Carriere  * Type indentifiers for registered device drivers consumer can query
189e3c57c8SEtienne Carriere  *
199e3c57c8SEtienne Carriere  * DT_DRIVER_NOTYPE Generic type for when no generic FDT parsing is supported
209e3c57c8SEtienne Carriere  * DT_DRIVER_UART   UART driver currently designed for console means
219e3c57c8SEtienne Carriere  * DT_DRIVER_CLK    Clock controller using generic clock DT bindings
229e3c57c8SEtienne Carriere  * DT_DRIVER_RSTCTRL Reset controller using generic reset DT bindings
23d679f4ddSThomas Perrot  * DT_DRIVER_I2C    I2C bus controller using generic I2C bus DT bindings
244fc179b6SThomas Perrot  * DT_DRIVER_GPIO   GPIO controller using generic GPIO DT bindings
25*6f9a4373SAntonio Borneo  * DT_DRIVER_PINCTRL Pin controller using generic DT bindings
26ed33eb2eSEtienne Carriere  * DT_DRIVER_INTERRUPT Interrupt controller using generic DT bindings
27193944aaSEtienne Carriere  * DT_DRIVER_REGULATOR Voltage regulator controller using generic DT bindings
284fd40c39SClément Léger  * DT_DRIVER_NVMEM NVMEM controller using generic NVMEM DT bindings
2948a1cce4SGatien Chevallier  * DT_DRIVER_FIREWALL Firewall controller using generic DT bindings
309e3c57c8SEtienne Carriere  */
319e3c57c8SEtienne Carriere enum dt_driver_type {
329e3c57c8SEtienne Carriere 	DT_DRIVER_NOTYPE,
339e3c57c8SEtienne Carriere 	DT_DRIVER_UART,
349e3c57c8SEtienne Carriere 	DT_DRIVER_CLK,
359e3c57c8SEtienne Carriere 	DT_DRIVER_RSTCTRL,
369e3c57c8SEtienne Carriere 	DT_DRIVER_I2C,
37b5aff6deSClément Léger 	DT_DRIVER_GPIO,
38ed33eb2eSEtienne Carriere 	DT_DRIVER_PINCTRL,
39ed33eb2eSEtienne Carriere 	DT_DRIVER_INTERRUPT,
40193944aaSEtienne Carriere 	DT_DRIVER_REGULATOR,
414fd40c39SClément Léger 	DT_DRIVER_NVMEM,
4248a1cce4SGatien Chevallier 	DT_DRIVER_FIREWALL,
439e3c57c8SEtienne Carriere };
449e3c57c8SEtienne Carriere 
459e3c57c8SEtienne Carriere /*
469e3c57c8SEtienne Carriere  * dt_driver_probe_func - Callback probe function for a driver.
479e3c57c8SEtienne Carriere  *
489e3c57c8SEtienne Carriere  * @fdt: FDT base address
499e3c57c8SEtienne Carriere  * @nodeoffset: Offset of the node in the FDT
509e3c57c8SEtienne Carriere  * @compat_data: Data registered for the compatible that probed the device
519e3c57c8SEtienne Carriere  *
529e3c57c8SEtienne Carriere  * Return TEE_SUCCESS on successful probe,
539e3c57c8SEtienne Carriere  *	TEE_ERROR_DEFER_DRIVER_INIT if probe must be deferred
549e3c57c8SEtienne Carriere  *	TEE_ERROR_ITEM_NOT_FOUND when no driver matched node's compatible string
559e3c57c8SEtienne Carriere  *	Any other TEE_ERROR_* compliant code.
569e3c57c8SEtienne Carriere  */
579e3c57c8SEtienne Carriere typedef TEE_Result (*dt_driver_probe_func)(const void *fdt, int nodeoffset,
589e3c57c8SEtienne Carriere 					   const void *compat_data);
599e3c57c8SEtienne Carriere 
609e3c57c8SEtienne Carriere /*
619e3c57c8SEtienne Carriere  * Driver instance registered to be probed on compatible node found in the DT.
629e3c57c8SEtienne Carriere  *
639e3c57c8SEtienne Carriere  * @name: Driver name
649e3c57c8SEtienne Carriere  * @type: Drive type
659e3c57c8SEtienne Carriere  * @match_table: Compatible matching identifiers, null terminated
669e3c57c8SEtienne Carriere  * @driver: Driver private reference or NULL
679e3c57c8SEtienne Carriere  * @probe: Probe callback (see dt_driver_probe_func) or NULL
689e3c57c8SEtienne Carriere  */
699e3c57c8SEtienne Carriere struct dt_driver {
709e3c57c8SEtienne Carriere 	const char *name;
719e3c57c8SEtienne Carriere 	enum dt_driver_type type;
729e3c57c8SEtienne Carriere 	const struct dt_device_match *match_table; /* null-terminated */
739e3c57c8SEtienne Carriere 	const void *driver;
749e3c57c8SEtienne Carriere 	TEE_Result (*probe)(const void *fdt, int node, const void *compat_data);
759e3c57c8SEtienne Carriere };
769e3c57c8SEtienne Carriere 
779e3c57c8SEtienne Carriere #define DEFINE_DT_DRIVER(name) \
789e3c57c8SEtienne Carriere 		SCATTERED_ARRAY_DEFINE_PG_ITEM(dt_drivers, struct dt_driver)
799e3c57c8SEtienne Carriere 
809e3c57c8SEtienne Carriere #define for_each_dt_driver(drv) \
819e3c57c8SEtienne Carriere 	for (drv = SCATTERED_ARRAY_BEGIN(dt_drivers, struct dt_driver); \
829e3c57c8SEtienne Carriere 	     drv < SCATTERED_ARRAY_END(dt_drivers, struct dt_driver); \
839e3c57c8SEtienne Carriere 	     drv++)
849e3c57c8SEtienne Carriere 
85704f6eddSEtienne Carriere /* Opaque reference to DT driver device provider instance */
86704f6eddSEtienne Carriere struct dt_driver_provider;
87704f6eddSEtienne Carriere 
888c0c44c9SEtienne Carriere /**
898fd620f7SEtienne Carriere  * struct dt_pargs - Devicetree phandle arguments
9033cc94dfSClément Léger  * @fdt: Device-tree to work on
9133cc94dfSClément Léger  * @phandle_node: Node pointed by the specifier phandle
92f4cc581bSEtienne Carriere  * @consumer_node: Node of the consumer requesting this device
938c0c44c9SEtienne Carriere  * @args_count: Count of cells for the device
948c0c44c9SEtienne Carriere  * @args: Device consumer specifiers
958c0c44c9SEtienne Carriere  */
968fd620f7SEtienne Carriere struct dt_pargs {
9733cc94dfSClément Léger 	const void *fdt;
9833cc94dfSClément Léger 	int phandle_node;
99f4cc581bSEtienne Carriere 	int consumer_node;
1008c0c44c9SEtienne Carriere 	int args_count;
1018c0c44c9SEtienne Carriere 	uint32_t args[];
1028c0c44c9SEtienne Carriere };
1038c0c44c9SEtienne Carriere 
1048c0c44c9SEtienne Carriere /*
1058c0c44c9SEtienne Carriere  * get_of_device_func - Callback function for returning a driver private
1068c0c44c9SEtienne Carriere  *	instance based on a FDT phandle with possible arguments and the
1078c0c44c9SEtienne Carriere  *	registered dt_driver private data reference.
1088c0c44c9SEtienne Carriere  *
1098c0c44c9SEtienne Carriere  * @parg: phandle argument(s) referencing the device in the FDT.
1108c0c44c9SEtienne Carriere  * @data: driver private data registered in struct dt_driver.
111b548a657SEtienne Carriere  * @device_ref: output device reference upon success, e.g. a struct clk
1121238110cSEtienne Carriere  *	pointer for a clock driver.
1131238110cSEtienne Carriere  *
1141238110cSEtienne Carriere  * Return code:
1158ae7e418SEtienne Carriere  * TEE_SUCCESS in case of success
116b6095989SEtienne Carriere  * TEE_ERROR_DEFER_DRIVER_INIT if device driver is not yet initialized
1178ae7e418SEtienne Carriere  * Any TEE_Result compliant code in case of error.
1188c0c44c9SEtienne Carriere  */
119b357d34fSEtienne Carriere typedef TEE_Result (*get_of_device_func)(struct dt_pargs *parg, void *data,
120b548a657SEtienne Carriere 					 void *device_ref);
1218c0c44c9SEtienne Carriere 
1223fd340e5SEtienne Carriere /**
1233fd340e5SEtienne Carriere  * dt_driver_register_provider - Register a driver provider
1243fd340e5SEtienne Carriere  *
1253fd340e5SEtienne Carriere  * @fdt: Device tree to work on
1263fd340e5SEtienne Carriere  * @nodeoffset: Node offset in the FDT
1273fd340e5SEtienne Carriere  * @get_of_device: Function to match the devicetree with a device instance
1283fd340e5SEtienne Carriere  * @data: Data which will be passed to the @get_of_device callback
1293fd340e5SEtienne Carriere  * @type: Driver type
1303fd340e5SEtienne Carriere  *
1313fd340e5SEtienne Carriere  * @get_of_device returns a void *. Driver provider is expected to
1323fd340e5SEtienne Carriere  * include a shim helper to cast to device reference into provider driver
1333fd340e5SEtienne Carriere  * target structure reference (e.g (struct clk *) for clock devices).
1343fd340e5SEtienne Carriere  */
1353fd340e5SEtienne Carriere TEE_Result dt_driver_register_provider(const void *fdt, int nodeoffset,
1363fd340e5SEtienne Carriere 				       get_of_device_func get_of_device,
1373fd340e5SEtienne Carriere 				       void *data, enum dt_driver_type type);
1383fd340e5SEtienne Carriere 
1393fd340e5SEtienne Carriere /*
140a22e85b2SEtienne Carriere  * dt_driver_device_from_node_idx_prop - Return a device instance based on a
141a22e85b2SEtienne Carriere  *	property name and FDT information
142a22e85b2SEtienne Carriere  *
143a22e85b2SEtienne Carriere  * @prop_name: DT property name, e.g. "clocks" for clock resources
144a22e85b2SEtienne Carriere  * @fdt: FDT base address
145a22e85b2SEtienne Carriere  * @nodeoffset: node offset in the FDT
146a22e85b2SEtienne Carriere  * @prop_idx: index of the phandle data in the property
1478dca59b4SEtienne Carriere  * @type: Driver type
148b548a657SEtienne Carriere  * @device_ref: output device opaque reference upon support, for example
149b357d34fSEtienne Carriere  *	a struct clk pointer for a clock driver.
150b357d34fSEtienne Carriere 
151b357d34fSEtienne Carriere  * Return code:
152b357d34fSEtienne Carriere  * TEE_SUCCESS in case of success,
153b6095989SEtienne Carriere  * TEE_ERROR_DEFER_DRIVER_INIT if device driver is not yet initialized
154b357d34fSEtienne Carriere  * TEE_ERROR_ITEM_NOT_FOUND if @prop_name does not match a property's name
155b357d34fSEtienne Carriere  *	or @prop_idx does not match any index in @prop_name phandle list
1568ae7e418SEtienne Carriere  * Any TEE_Result compliant code in case of error.
157a22e85b2SEtienne Carriere  */
158b357d34fSEtienne Carriere TEE_Result dt_driver_device_from_node_idx_prop(const char *prop_name,
159a22e85b2SEtienne Carriere 					       const void *fdt, int nodeoffset,
160d8b14b46SEtienne Carriere 					       unsigned int prop_idx,
1618dca59b4SEtienne Carriere 					       enum dt_driver_type type,
162b548a657SEtienne Carriere 					       void *device_ref);
163a22e85b2SEtienne Carriere 
164a22e85b2SEtienne Carriere /*
165e7a2db34SClément Léger  * dt_driver_device_from_parent - Return a device instance based on the parent.
166e7a2db34SClément Léger  *	This is mainly used for the devices that are children of a controller
167e7a2db34SClément Léger  *	such as I2C, SPI and so on.
168e7a2db34SClément Léger  *
169e7a2db34SClément Léger  * @fdt: FDT base address
170e7a2db34SClément Léger  * @nodeoffset: node offset in the FDT
171e7a2db34SClément Léger  * @type: Driver type
172b548a657SEtienne Carriere  * @device_ref: output device opaque reference upon success, for example
173b357d34fSEtienne Carriere  *	a struct i2c_dev pointer for a I2C bus driver
174b357d34fSEtienne Carriere  *
175b357d34fSEtienne Carriere  * Return code:
176b357d34fSEtienne Carriere  * TEE_SUCCESS in case of success,
177e7a2db34SClément Léger  * TEE_ERROR_DEFER_DRIVER_INIT if device driver is not yet initialized
178e7a2db34SClément Léger  * Any TEE_Result compliant code in case of error.
179e7a2db34SClément Léger  */
180b357d34fSEtienne Carriere TEE_Result dt_driver_device_from_parent(const void *fdt, int nodeoffset,
181b357d34fSEtienne Carriere 					enum dt_driver_type type,
182b548a657SEtienne Carriere 					void *device_ref);
183e7a2db34SClément Léger 
184e7a2db34SClément Léger /*
18550dd2af0SEtienne Carriere  * dt_driver_device_from_node_idx_prop_phandle() - Same as
18650dd2af0SEtienne Carriere  *	dt_driver_device_from_node_idx_prop() but phandle is not the first
18750dd2af0SEtienne Carriere  *	cells in property @prop_name but is passed as an argument.
18850dd2af0SEtienne Carriere  *
18950dd2af0SEtienne Carriere  * This function is used for DT bindings as "interrupts" property where the
19050dd2af0SEtienne Carriere  * property carries the interrupt information but not the interrupt controller
19150dd2af0SEtienne Carriere  * phandle which is found in a specific property (here "interrupt-parent").
19250dd2af0SEtienne Carriere  */
193b357d34fSEtienne Carriere TEE_Result dt_driver_device_from_node_idx_prop_phandle(const char *prop_name,
194b357d34fSEtienne Carriere 						       const void *fdt,
195b357d34fSEtienne Carriere 						       int nodeoffs,
19650dd2af0SEtienne Carriere 						       unsigned int prop_index,
19750dd2af0SEtienne Carriere 						       enum dt_driver_type type,
19850dd2af0SEtienne Carriere 						       uint32_t phandle,
199b548a657SEtienne Carriere 						       void *device_ref);
20050dd2af0SEtienne Carriere 
20150dd2af0SEtienne Carriere /*
2023de8f0deSEtienne Carriere  * dt_driver_get_crypto() - Request crypto support for driver initialization
2033de8f0deSEtienne Carriere  *
2043de8f0deSEtienne Carriere  * Return TEE_SUCCESS if cryptography services are initialized, otherwise return
2053de8f0deSEtienne Carriere  * TEE_ERROR_DEFER_DRIVER_INIT.
2063de8f0deSEtienne Carriere  */
2073de8f0deSEtienne Carriere TEE_Result dt_driver_get_crypto(void);
2083de8f0deSEtienne Carriere 
2093de8f0deSEtienne Carriere #ifdef CFG_DT
2103de8f0deSEtienne Carriere /* Inform DT driver probe sequence that core crypto support is initialized */
2113de8f0deSEtienne Carriere void dt_driver_crypt_init_complete(void);
2123de8f0deSEtienne Carriere #else
dt_driver_crypt_init_complete(void)2133de8f0deSEtienne Carriere static inline void dt_driver_crypt_init_complete(void) {}
2143de8f0deSEtienne Carriere #endif
2153de8f0deSEtienne Carriere 
2163de8f0deSEtienne Carriere /*
217f498c404SEtienne Carriere  * Return driver provider reference from its node offset value in the FDT
218f498c404SEtienne Carriere  */
2198dca59b4SEtienne Carriere struct dt_driver_provider *
2208dca59b4SEtienne Carriere dt_driver_get_provider_by_node(int nodeoffset, enum dt_driver_type type);
221f498c404SEtienne Carriere 
222f498c404SEtienne Carriere /*
223f498c404SEtienne Carriere  * Return driver provider reference from its phandle value in the FDT
224f498c404SEtienne Carriere  */
2258dca59b4SEtienne Carriere struct dt_driver_provider *
2268dca59b4SEtienne Carriere dt_driver_get_provider_by_phandle(uint32_t phandle, enum dt_driver_type type);
227f498c404SEtienne Carriere 
228f498c404SEtienne Carriere /*
2293fd340e5SEtienne Carriere  * Return number cells used for phandle arguments by a driver provider
2303fd340e5SEtienne Carriere  */
2313fd340e5SEtienne Carriere unsigned int dt_driver_provider_cells(struct dt_driver_provider *prv);
2323fd340e5SEtienne Carriere 
2333fd340e5SEtienne Carriere /*
234c9c53de1SEtienne Carriere  * Return provider private data registered by dt_driver_register_provider()
235c9c53de1SEtienne Carriere  */
236c9c53de1SEtienne Carriere void *dt_driver_provider_priv_data(struct dt_driver_provider *prv);
237c9c53de1SEtienne Carriere 
238c9c53de1SEtienne Carriere /*
239ef20efc4SEtienne Carriere  * dt_driver_probe_device_by_node - Probe matching driver to create a device
240ef20efc4SEtienne Carriere  *	from a FDT node
241ef20efc4SEtienne Carriere  *
242ef20efc4SEtienne Carriere  * @fdt: FDT base address
243ef20efc4SEtienne Carriere  * @nodeoffset: Node byte offset from FDT base
244ef20efc4SEtienne Carriere  * @type: Target driver to match or DT_DRIVER_ANY
245ef20efc4SEtienne Carriere  *
246ef20efc4SEtienne Carriere  * Read the dt_driver database. Compatible list is looked up in the order
247ef20efc4SEtienne Carriere  * of the FDT "compatible" property list. @type can be used to probe only
248ef20efc4SEtienne Carriere  * specific drivers.
249ef20efc4SEtienne Carriere  *
250ef20efc4SEtienne Carriere  */
251ef20efc4SEtienne Carriere TEE_Result dt_driver_probe_device_by_node(const void *fdt, int nodeoffset,
252ef20efc4SEtienne Carriere 					  enum dt_driver_type type);
253ef20efc4SEtienne Carriere 
254ef20efc4SEtienne Carriere /*
2553fd340e5SEtienne Carriere  * Get cells count of a device node given its dt_driver type
2563fd340e5SEtienne Carriere  *
2573fd340e5SEtienne Carriere  * @fdt: FDT base address
2583fd340e5SEtienne Carriere  * @nodeoffset: Node offset on the FDT for the device
2593fd340e5SEtienne Carriere  * @type: One of the supported DT_DRIVER_* value.
2603fd340e5SEtienne Carriere  *
2613fd340e5SEtienne Carriere  * Return a positive cell count value (>= 0) or a negative FDT_ error code
2623fd340e5SEtienne Carriere  */
2633fd340e5SEtienne Carriere int fdt_get_dt_driver_cells(const void *fdt, int nodeoffset,
2643fd340e5SEtienne Carriere 			    enum dt_driver_type type);
265b3a88b52SEtienne Carriere 
266b3a88b52SEtienne Carriere /*
267b3a88b52SEtienne Carriere  * Called by bus like nodes to propose a node for dt_driver probing
268b3a88b52SEtienne Carriere  *
269b3a88b52SEtienne Carriere  * @fdt: FDT base address
270b3a88b52SEtienne Carriere  * @nodeoffset: Node offset on the FDT for the device
271b3a88b52SEtienne Carriere  */
272b3a88b52SEtienne Carriere TEE_Result dt_driver_maybe_add_probe_node(const void *fdt, int nodeoffset);
273d783b681SEtienne Carriere 
274d783b681SEtienne Carriere #ifdef CFG_DT_DRIVER_EMBEDDED_TEST
275d783b681SEtienne Carriere /*
276d783b681SEtienne Carriere  * Return TEE_ERROR_NOT_IMPLEMENTED if test are not implemented
277d783b681SEtienne Carriere  * otherwise return TEE_ERROR_GENERIC if some test has failed
278d783b681SEtienne Carriere  * otherwise return TEE_SUCCESS (tests succeed or skipped)
279d783b681SEtienne Carriere  */
280d783b681SEtienne Carriere TEE_Result dt_driver_test_status(void);
281d783b681SEtienne Carriere #else
dt_driver_test_status(void)282d783b681SEtienne Carriere static inline TEE_Result dt_driver_test_status(void)
283d783b681SEtienne Carriere {
284d783b681SEtienne Carriere 	return TEE_ERROR_NOT_IMPLEMENTED;
285d783b681SEtienne Carriere }
286d783b681SEtienne Carriere #endif
287fbe66cf8SEtienne Carriere #endif /* __KERNEL_DT_DRIVER_H */
288