18c0c44c9SEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause 28c0c44c9SEtienne Carriere /* 38c0c44c9SEtienne Carriere * Copyright (c) 2021, Linaro Limited 48c0c44c9SEtienne Carriere * Copyright (c) 2021, Bootlin 58c0c44c9SEtienne Carriere */ 68c0c44c9SEtienne Carriere 73fd340e5SEtienne Carriere #include <initcall.h> 83fd340e5SEtienne Carriere #include <kernel/dt.h> 98c0c44c9SEtienne Carriere #include <kernel/dt_driver.h> 103fd340e5SEtienne Carriere #include <libfdt.h> 113fd340e5SEtienne Carriere #include <malloc.h> 128c0c44c9SEtienne Carriere #include <sys/queue.h> 133fd340e5SEtienne Carriere #include <tee_api_types.h> 148c0c44c9SEtienne Carriere 158c0c44c9SEtienne Carriere struct dt_driver_prov_list dt_driver_provider_list = 168c0c44c9SEtienne Carriere SLIST_HEAD_INITIALIZER(dt_driver_provider_list); 173fd340e5SEtienne Carriere 183fd340e5SEtienne Carriere /* 193fd340e5SEtienne Carriere * Driver provider registering API functions 203fd340e5SEtienne Carriere */ 213fd340e5SEtienne Carriere 223fd340e5SEtienne Carriere TEE_Result dt_driver_register_provider(const void *fdt, int nodeoffset, 233fd340e5SEtienne Carriere get_of_device_func get_of_device, 243fd340e5SEtienne Carriere void *priv, enum dt_driver_type type) 253fd340e5SEtienne Carriere { 263fd340e5SEtienne Carriere struct dt_driver_provider *prv = NULL; 273fd340e5SEtienne Carriere int provider_cells = 0; 283fd340e5SEtienne Carriere uint32_t phandle = 0; 293fd340e5SEtienne Carriere 303fd340e5SEtienne Carriere provider_cells = fdt_get_dt_driver_cells(fdt, nodeoffset, type); 313fd340e5SEtienne Carriere if (provider_cells < 0) { 323fd340e5SEtienne Carriere DMSG("Failed to find provider cells: %d", provider_cells); 333fd340e5SEtienne Carriere return TEE_ERROR_GENERIC; 343fd340e5SEtienne Carriere } 353fd340e5SEtienne Carriere 363fd340e5SEtienne Carriere phandle = fdt_get_phandle(fdt, nodeoffset); 373fd340e5SEtienne Carriere if (!phandle || phandle == (uint32_t)-1) { 383fd340e5SEtienne Carriere DMSG("Failed to find provide phandle"); 393fd340e5SEtienne Carriere return TEE_ERROR_GENERIC; 403fd340e5SEtienne Carriere } 413fd340e5SEtienne Carriere 423fd340e5SEtienne Carriere prv = calloc(1, sizeof(*prv)); 433fd340e5SEtienne Carriere if (!prv) 443fd340e5SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 453fd340e5SEtienne Carriere 463fd340e5SEtienne Carriere prv->nodeoffset = nodeoffset; 473fd340e5SEtienne Carriere prv->type = type; 483fd340e5SEtienne Carriere prv->provider_cells = provider_cells; 493fd340e5SEtienne Carriere prv->phandle = phandle; 503fd340e5SEtienne Carriere prv->get_of_device = get_of_device; 513fd340e5SEtienne Carriere prv->priv_data = priv; 523fd340e5SEtienne Carriere 533fd340e5SEtienne Carriere SLIST_INSERT_HEAD(&dt_driver_provider_list, prv, link); 543fd340e5SEtienne Carriere 553fd340e5SEtienne Carriere return TEE_SUCCESS; 563fd340e5SEtienne Carriere } 573fd340e5SEtienne Carriere 583fd340e5SEtienne Carriere /* Release driver provider references once all dt_drivers are initialized */ 593fd340e5SEtienne Carriere static TEE_Result dt_driver_release_provider(void) 603fd340e5SEtienne Carriere { 613fd340e5SEtienne Carriere struct dt_driver_provider *prv = NULL; 623fd340e5SEtienne Carriere 633fd340e5SEtienne Carriere while (!SLIST_EMPTY(&dt_driver_provider_list)) { 643fd340e5SEtienne Carriere prv = SLIST_FIRST(&dt_driver_provider_list); 653fd340e5SEtienne Carriere SLIST_REMOVE_HEAD(&dt_driver_provider_list, link); 663fd340e5SEtienne Carriere free(prv); 673fd340e5SEtienne Carriere } 683fd340e5SEtienne Carriere 693fd340e5SEtienne Carriere return TEE_SUCCESS; 703fd340e5SEtienne Carriere } 713fd340e5SEtienne Carriere 723fd340e5SEtienne Carriere driver_init_late(dt_driver_release_provider); 733fd340e5SEtienne Carriere 743fd340e5SEtienne Carriere /* 753fd340e5SEtienne Carriere * Helper functions for dt_drivers querying driver provider information 763fd340e5SEtienne Carriere */ 773fd340e5SEtienne Carriere 783fd340e5SEtienne Carriere int fdt_get_dt_driver_cells(const void *fdt, int nodeoffset, 793fd340e5SEtienne Carriere enum dt_driver_type type) 803fd340e5SEtienne Carriere { 813fd340e5SEtienne Carriere const char *cells_name = NULL; 823fd340e5SEtienne Carriere const fdt32_t *c = NULL; 833fd340e5SEtienne Carriere int len = 0; 843fd340e5SEtienne Carriere 853fd340e5SEtienne Carriere switch (type) { 863fd340e5SEtienne Carriere case DT_DRIVER_CLK: 873fd340e5SEtienne Carriere cells_name = "#clock-cells"; 883fd340e5SEtienne Carriere break; 893fd340e5SEtienne Carriere default: 903fd340e5SEtienne Carriere panic(); 913fd340e5SEtienne Carriere } 923fd340e5SEtienne Carriere 933fd340e5SEtienne Carriere c = fdt_getprop(fdt, nodeoffset, cells_name, &len); 943fd340e5SEtienne Carriere if (!c) 953fd340e5SEtienne Carriere return len; 963fd340e5SEtienne Carriere 973fd340e5SEtienne Carriere if (len != sizeof(*c)) 983fd340e5SEtienne Carriere return -FDT_ERR_BADNCELLS; 993fd340e5SEtienne Carriere 1003fd340e5SEtienne Carriere return fdt32_to_cpu(*c); 1013fd340e5SEtienne Carriere } 1023fd340e5SEtienne Carriere 1033fd340e5SEtienne Carriere unsigned int dt_driver_provider_cells(struct dt_driver_provider *prv) 1043fd340e5SEtienne Carriere { 1053fd340e5SEtienne Carriere return prv->provider_cells; 1063fd340e5SEtienne Carriere } 107*f498c404SEtienne Carriere 108*f498c404SEtienne Carriere struct dt_driver_provider *dt_driver_get_provider_by_node(int nodeoffset) 109*f498c404SEtienne Carriere { 110*f498c404SEtienne Carriere struct dt_driver_provider *prv = NULL; 111*f498c404SEtienne Carriere 112*f498c404SEtienne Carriere SLIST_FOREACH(prv, &dt_driver_provider_list, link) 113*f498c404SEtienne Carriere if (prv->nodeoffset == nodeoffset) 114*f498c404SEtienne Carriere return prv; 115*f498c404SEtienne Carriere 116*f498c404SEtienne Carriere return NULL; 117*f498c404SEtienne Carriere } 118*f498c404SEtienne Carriere 119*f498c404SEtienne Carriere struct dt_driver_provider *dt_driver_get_provider_by_phandle(uint32_t phandle) 120*f498c404SEtienne Carriere { 121*f498c404SEtienne Carriere struct dt_driver_provider *prv = NULL; 122*f498c404SEtienne Carriere 123*f498c404SEtienne Carriere SLIST_FOREACH(prv, &dt_driver_provider_list, link) 124*f498c404SEtienne Carriere if (prv->phandle == phandle) 125*f498c404SEtienne Carriere return prv; 126*f498c404SEtienne Carriere 127*f498c404SEtienne Carriere return NULL; 128*f498c404SEtienne Carriere } 129