1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2021, Linaro Limited 4 * Copyright (c) 2021, Bootlin 5 */ 6 7 #include <initcall.h> 8 #include <kernel/dt.h> 9 #include <kernel/dt_driver.h> 10 #include <libfdt.h> 11 #include <malloc.h> 12 #include <sys/queue.h> 13 #include <tee_api_types.h> 14 15 struct dt_driver_prov_list dt_driver_provider_list = 16 SLIST_HEAD_INITIALIZER(dt_driver_provider_list); 17 18 /* 19 * Driver provider registering API functions 20 */ 21 22 TEE_Result dt_driver_register_provider(const void *fdt, int nodeoffset, 23 get_of_device_func get_of_device, 24 void *priv, enum dt_driver_type type) 25 { 26 struct dt_driver_provider *prv = NULL; 27 int provider_cells = 0; 28 uint32_t phandle = 0; 29 30 provider_cells = fdt_get_dt_driver_cells(fdt, nodeoffset, type); 31 if (provider_cells < 0) { 32 DMSG("Failed to find provider cells: %d", provider_cells); 33 return TEE_ERROR_GENERIC; 34 } 35 36 phandle = fdt_get_phandle(fdt, nodeoffset); 37 if (!phandle || phandle == (uint32_t)-1) { 38 DMSG("Failed to find provide phandle"); 39 return TEE_ERROR_GENERIC; 40 } 41 42 prv = calloc(1, sizeof(*prv)); 43 if (!prv) 44 return TEE_ERROR_OUT_OF_MEMORY; 45 46 prv->nodeoffset = nodeoffset; 47 prv->type = type; 48 prv->provider_cells = provider_cells; 49 prv->phandle = phandle; 50 prv->get_of_device = get_of_device; 51 prv->priv_data = priv; 52 53 SLIST_INSERT_HEAD(&dt_driver_provider_list, prv, link); 54 55 return TEE_SUCCESS; 56 } 57 58 /* Release driver provider references once all dt_drivers are initialized */ 59 static TEE_Result dt_driver_release_provider(void) 60 { 61 struct dt_driver_provider *prv = NULL; 62 63 while (!SLIST_EMPTY(&dt_driver_provider_list)) { 64 prv = SLIST_FIRST(&dt_driver_provider_list); 65 SLIST_REMOVE_HEAD(&dt_driver_provider_list, link); 66 free(prv); 67 } 68 69 return TEE_SUCCESS; 70 } 71 72 driver_init_late(dt_driver_release_provider); 73 74 /* 75 * Helper functions for dt_drivers querying driver provider information 76 */ 77 78 int fdt_get_dt_driver_cells(const void *fdt, int nodeoffset, 79 enum dt_driver_type type) 80 { 81 const char *cells_name = NULL; 82 const fdt32_t *c = NULL; 83 int len = 0; 84 85 switch (type) { 86 case DT_DRIVER_CLK: 87 cells_name = "#clock-cells"; 88 break; 89 default: 90 panic(); 91 } 92 93 c = fdt_getprop(fdt, nodeoffset, cells_name, &len); 94 if (!c) 95 return len; 96 97 if (len != sizeof(*c)) 98 return -FDT_ERR_BADNCELLS; 99 100 return fdt32_to_cpu(*c); 101 } 102 103 unsigned int dt_driver_provider_cells(struct dt_driver_provider *prv) 104 { 105 return prv->provider_cells; 106 } 107