11bb92983SJerome Forissier /* SPDX-License-Identifier: BSD-2-Clause */ 2a4f139d7SJerome Forissier /* 301254f1dSEtienne Carriere * Copyright (c) 2016-2021, Linaro Limited 4a4f139d7SJerome Forissier */ 5a4f139d7SJerome Forissier 6a4f139d7SJerome Forissier #ifndef KERNEL_DT_H 7a4f139d7SJerome Forissier #define KERNEL_DT_H 8a4f139d7SJerome Forissier 9a4f139d7SJerome Forissier #include <compiler.h> 10702fe5a7SClément Léger #include <kernel/interrupt.h> 11c0cfb36cSEtienne Carriere #include <kernel/panic.h> 1261bdedeaSJerome Forissier #include <scattered_array.h> 13a4f139d7SJerome Forissier #include <stdint.h> 1401254f1dSEtienne Carriere #include <tee_api_types.h> 15a4f139d7SJerome Forissier #include <types_ext.h> 169fe4c797SJerome Forissier #include <util.h> 179fe4c797SJerome Forissier 189fe4c797SJerome Forissier /* 1923b1daf4SPeng Fan * Bitfield to reflect status and secure-status values ("okay", "disabled" 2023b1daf4SPeng Fan * or not present) 219fe4c797SJerome Forissier */ 22b4bfc9a9SJens Wiklander #define DT_STATUS_DISABLED U(0) 239fe4c797SJerome Forissier #define DT_STATUS_OK_NSEC BIT(0) 249fe4c797SJerome Forissier #define DT_STATUS_OK_SEC BIT(1) 25a4f139d7SJerome Forissier 26c0cfb36cSEtienne Carriere #define DT_INFO_INVALID_REG ((paddr_t)-1) 27df7cecc0SLionel Debieve #define DT_INFO_INVALID_REG_SIZE ((size_t)-1) 28c0cfb36cSEtienne Carriere #define DT_INFO_INVALID_CLOCK -1 29c0cfb36cSEtienne Carriere #define DT_INFO_INVALID_RESET -1 3095cdc5e0SCedric Neveux #define DT_INFO_INVALID_INTERRUPT -1 3195cdc5e0SCedric Neveux 32c0cfb36cSEtienne Carriere /* 33c0cfb36cSEtienne Carriere * @status: Bit mask for DT_STATUS_* 34c0cfb36cSEtienne Carriere * @reg: Device register physical base address or DT_INFO_INVALID_REG 3506fd21ddSLionel Debieve * @reg_size: Device register size or DT_INFO_INVALID_REG_SIZE 36c0cfb36cSEtienne Carriere * @clock: Device identifier (positive value) or DT_INFO_INVALID_CLOCK 37c0cfb36cSEtienne Carriere * @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK 387acb3a47SLudovic Barre * @interrupt: Device interrupt identifier (positive value) or 397acb3a47SLudovic Barre * DT_INFO_INVALID_INTERRUPT 40702fe5a7SClément Léger * @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if 41702fe5a7SClément Léger * not present 42702fe5a7SClément Léger * @prio: interrupt priority parsed from interrupts properties or 0 if not 43702fe5a7SClément Léger * present 44c0cfb36cSEtienne Carriere */ 45c0cfb36cSEtienne Carriere struct dt_node_info { 46c0cfb36cSEtienne Carriere unsigned int status; 47c0cfb36cSEtienne Carriere paddr_t reg; 4806fd21ddSLionel Debieve size_t reg_size; 49c0cfb36cSEtienne Carriere int clock; 50c0cfb36cSEtienne Carriere int reset; 517acb3a47SLudovic Barre int interrupt; 52702fe5a7SClément Léger uint32_t type; 53702fe5a7SClément Léger uint32_t prio; 54c0cfb36cSEtienne Carriere }; 55c0cfb36cSEtienne Carriere 56a4f139d7SJerome Forissier /* 57a4f139d7SJerome Forissier * DT-aware drivers 58a4f139d7SJerome Forissier */ 59a4f139d7SJerome Forissier 60a4f139d7SJerome Forissier struct dt_device_match { 61a4f139d7SJerome Forissier const char *compatible; 627e6a39feSEtienne Carriere const void *compat_data; 63a4f139d7SJerome Forissier }; 64a4f139d7SJerome Forissier 655e588771SClément Léger enum dt_driver_type { 665e588771SClément Léger DT_DRIVER_NOTYPE, 675e588771SClément Léger DT_DRIVER_UART, 682305544bSClément Léger DT_DRIVER_CLK, 69c78b2c66SEtienne Carriere DT_DRIVER_RSTCTRL, 70e7a2db34SClément Léger DT_DRIVER_I2C, 715e588771SClément Léger }; 725e588771SClément Léger 7301254f1dSEtienne Carriere /* 74a5d5bbc8SVesa Jääskeläinen * DT_MAP_AUTO: Uses status properties from device tree to determine mapping. 75a5d5bbc8SVesa Jääskeläinen * DT_MAP_SECURE: Force mapping for device to be secure. 76a5d5bbc8SVesa Jääskeläinen * DT_MAP_NON_SECURE: Force mapping for device to be non-secure. 77a5d5bbc8SVesa Jääskeläinen */ 78a5d5bbc8SVesa Jääskeläinen enum dt_map_dev_directive { 79a5d5bbc8SVesa Jääskeläinen DT_MAP_AUTO, 80a5d5bbc8SVesa Jääskeläinen DT_MAP_SECURE, 81a5d5bbc8SVesa Jääskeläinen DT_MAP_NON_SECURE 82a5d5bbc8SVesa Jääskeläinen }; 83a5d5bbc8SVesa Jääskeläinen 84a5d5bbc8SVesa Jääskeläinen /* 8501254f1dSEtienne Carriere * dt_driver_probe_func - Callback probe function for a driver. 8601254f1dSEtienne Carriere * 8701254f1dSEtienne Carriere * @fdt: FDT base address 8801254f1dSEtienne Carriere * @nodeoffset: Offset of the node in the FDT 8901254f1dSEtienne Carriere * @compat_data: Data registered for the compatible that probed the device 9001254f1dSEtienne Carriere * 9101254f1dSEtienne Carriere * Return TEE_SUCCESS on successful probe, 92b3a88b52SEtienne Carriere * TEE_ERROR_DEFER_DRIVER_INIT if probe must be deferred 9301254f1dSEtienne Carriere * TEE_ERROR_ITEM_NOT_FOUND when no driver matched node's compatible string 9401254f1dSEtienne Carriere * Any other TEE_ERROR_* compliant code. 9501254f1dSEtienne Carriere */ 9601254f1dSEtienne Carriere typedef TEE_Result (*dt_driver_probe_func)(const void *fdt, int nodeoffset, 9701254f1dSEtienne Carriere const void *compat_data); 9801254f1dSEtienne Carriere 99670fa4aaSEtienne Carriere #if defined(CFG_DT) 10001254f1dSEtienne Carriere /* 10101254f1dSEtienne Carriere * Driver instance registered to be probed on compatible node found in the DT. 10201254f1dSEtienne Carriere * 10301254f1dSEtienne Carriere * @name: Driver name 10401254f1dSEtienne Carriere * @type: Drive type 10501254f1dSEtienne Carriere * @match_table: Compatible matching identifiers, null terminated 10601254f1dSEtienne Carriere * @driver: Driver private reference or NULL 10701254f1dSEtienne Carriere * @probe: Probe callback (see dt_driver_probe_func) or NULL 10801254f1dSEtienne Carriere */ 109a4f139d7SJerome Forissier struct dt_driver { 110a4f139d7SJerome Forissier const char *name; 1115e588771SClément Léger enum dt_driver_type type; 112a4f139d7SJerome Forissier const struct dt_device_match *match_table; /* null-terminated */ 113a4f139d7SJerome Forissier const void *driver; 11401254f1dSEtienne Carriere TEE_Result (*probe)(const void *fdt, int node, const void *compat_data); 115a4f139d7SJerome Forissier }; 116a4f139d7SJerome Forissier 11761bdedeaSJerome Forissier #define DEFINE_DT_DRIVER(name) \ 118ace4d69dSEtienne Carriere SCATTERED_ARRAY_DEFINE_PG_ITEM(dt_drivers, struct dt_driver) 119a4f139d7SJerome Forissier 120a4f139d7SJerome Forissier /* 121a4f139d7SJerome Forissier * Find a driver that is suitable for the given DT node, that is, with 122a4f139d7SJerome Forissier * a matching "compatible" property. 123a4f139d7SJerome Forissier * 124a4f139d7SJerome Forissier * @fdt: pointer to the device tree 125a4f139d7SJerome Forissier * @offs: node offset 126a4f139d7SJerome Forissier */ 127a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 128a4f139d7SJerome Forissier 1299fe4c797SJerome Forissier /* 1307ba16abbSJerome Forissier * Map a device into secure or non-secure memory and return the base VA and 1317ba16abbSJerome Forissier * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 1327ba16abbSJerome Forissier * MEM_AREA_IO_NSEC, depending on the device status. 1337ba16abbSJerome Forissier * If the mapping already exists, the function simply returns the @vbase and 1347ba16abbSJerome Forissier * @size information. 1357ba16abbSJerome Forissier * 1367ba16abbSJerome Forissier * @offs is the offset of the node that describes the device in @fdt. 1377ba16abbSJerome Forissier * @base receives the base virtual address corresponding to the base physical 1387ba16abbSJerome Forissier * address of the "reg" property 1397ba16abbSJerome Forissier * @size receives the size of the mapping 140a5d5bbc8SVesa Jääskeläinen * @mapping what kind of mapping is done for memory. 1417ba16abbSJerome Forissier * 1427ba16abbSJerome Forissier * Returns 0 on success or -1 in case of error. 1437ba16abbSJerome Forissier */ 144a5d5bbc8SVesa Jääskeläinen int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size, 145a5d5bbc8SVesa Jääskeläinen enum dt_map_dev_directive mapping); 1467ba16abbSJerome Forissier 1477ba16abbSJerome Forissier /* 14850f3b323SPeng Fan * Check whether the node at @offs contains the property with propname or not. 14950f3b323SPeng Fan * 15050f3b323SPeng Fan * @offs is the offset of the node that describes the device in @fdt. 15150f3b323SPeng Fan * @propname is the property that need to check 15250f3b323SPeng Fan * 15350f3b323SPeng Fan * Returns true on success or false if no propname. 15450f3b323SPeng Fan */ 15550f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname); 15650f3b323SPeng Fan 15750f3b323SPeng Fan /* 15895cdc5e0SCedric Neveux * Modify or add "status" property to "disabled" 15995cdc5e0SCedric Neveux * 16095cdc5e0SCedric Neveux * @fdt reference to the Device Tree 16195cdc5e0SCedric Neveux * @node is the node offset to modify 16295cdc5e0SCedric Neveux * 16395cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 16495cdc5e0SCedric Neveux */ 16595cdc5e0SCedric Neveux int dt_disable_status(void *fdt, int node); 16695cdc5e0SCedric Neveux 16795cdc5e0SCedric Neveux /* 16895cdc5e0SCedric Neveux * Force secure-status = "okay" and status="disabled" for the target node. 16995cdc5e0SCedric Neveux * 17095cdc5e0SCedric Neveux * @fdt reference to the Device Tree 17195cdc5e0SCedric Neveux * @node is the node offset to modify 17295cdc5e0SCedric Neveux * 17395cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 17495cdc5e0SCedric Neveux */ 17595cdc5e0SCedric Neveux int dt_enable_secure_status(void *fdt, int node); 17695cdc5e0SCedric Neveux 17795cdc5e0SCedric Neveux /* 1789fe4c797SJerome Forissier * FDT manipulation functions, not provided by <libfdt.h> 1799fe4c797SJerome Forissier */ 1809fe4c797SJerome Forissier 1819fe4c797SJerome Forissier /* 1829fe4c797SJerome Forissier * Return the base address for the "reg" property of the specified node or 1839fe4c797SJerome Forissier * (paddr_t)-1 in case of error 1849fe4c797SJerome Forissier */ 185*f354a5d8SGatien Chevallier paddr_t fdt_reg_base_address(const void *fdt, int offs); 1869fe4c797SJerome Forissier 1879fe4c797SJerome Forissier /* 1889fe4c797SJerome Forissier * Return the reg size for the reg property of the specified node or -1 in case 1899fe4c797SJerome Forissier * of error 1909fe4c797SJerome Forissier */ 191*f354a5d8SGatien Chevallier size_t fdt_reg_size(const void *fdt, int offs); 1929fe4c797SJerome Forissier 1939fe4c797SJerome Forissier /* 1949fe4c797SJerome Forissier * Read the status and secure-status properties into a bitfield. 195c020046dSEtienne Carriere * Return -1 on failure, DT_STATUS_DISABLED if the node is disabled, 196c020046dSEtienne Carriere * otherwise return a combination of DT_STATUS_OK_NSEC and DT_STATUS_OK_SEC. 1979fe4c797SJerome Forissier */ 198*f354a5d8SGatien Chevallier int fdt_get_status(const void *fdt, int offs); 1999fe4c797SJerome Forissier 200c0cfb36cSEtienne Carriere /* 201c0cfb36cSEtienne Carriere * fdt_fill_device_info - Get generic device info from a node 202c0cfb36cSEtienne Carriere * 203c0cfb36cSEtienne Carriere * This function fills the generic information from a given node. 204c0cfb36cSEtienne Carriere * Currently supports a single base register, a single clock, 205c0cfb36cSEtienne Carriere * a single reset ID line and a single interrupt ID. 206c0cfb36cSEtienne Carriere * Default DT_INFO_* macros are used when the relate property is not found. 207c0cfb36cSEtienne Carriere */ 208*f354a5d8SGatien Chevallier void fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 209df45c114SEtienne Carriere int node); 210876826f3SGabriel Fernandez /* 211876826f3SGabriel Fernandez * Read cells from a given property of the given node. Any number of 32-bit 212876826f3SGabriel Fernandez * cells of the property can be read. Returns 0 on success, or a negative 213876826f3SGabriel Fernandez * FDT error value otherwise. 214876826f3SGabriel Fernandez */ 215*f354a5d8SGatien Chevallier int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name, 216876826f3SGabriel Fernandez uint32_t *array, size_t count); 217876826f3SGabriel Fernandez 218876826f3SGabriel Fernandez /* 219876826f3SGabriel Fernandez * Read one cell from a given property of the given node. 220876826f3SGabriel Fernandez * Returns 0 on success, or a negative FDT error value otherwise. 221876826f3SGabriel Fernandez */ 222*f354a5d8SGatien Chevallier int fdt_read_uint32(const void *fdt, int node, const char *prop_name, 223876826f3SGabriel Fernandez uint32_t *value); 224876826f3SGabriel Fernandez 225876826f3SGabriel Fernandez /* 226876826f3SGabriel Fernandez * Read one cell from a property of a cell or default to a given value 227876826f3SGabriel Fernandez * Returns the 32bit cell value or @dflt_value on failure. 228876826f3SGabriel Fernandez */ 229*f354a5d8SGatien Chevallier uint32_t fdt_read_uint32_default(const void *fdt, int node, 230876826f3SGabriel Fernandez const char *prop_name, uint32_t dflt_value); 231876826f3SGabriel Fernandez 232876826f3SGabriel Fernandez /* 233876826f3SGabriel Fernandez * Check whether the node at @node has a reference name. 234876826f3SGabriel Fernandez * 235876826f3SGabriel Fernandez * @node is the offset of the node that describes the device in @fdt. 236876826f3SGabriel Fernandez * 237876826f3SGabriel Fernandez * Returns true on success or false if no property 238876826f3SGabriel Fernandez */ 239*f354a5d8SGatien Chevallier bool fdt_check_node(const void *fdt, int node); 240c0cfb36cSEtienne Carriere 2419fe4c797SJerome Forissier #else /* !CFG_DT */ 242a4f139d7SJerome Forissier 243a4f139d7SJerome Forissier static inline const struct dt_driver *dt_find_compatible_driver( 244a4f139d7SJerome Forissier const void *fdt __unused, 245a4f139d7SJerome Forissier int offs __unused) 246a4f139d7SJerome Forissier { 247a4f139d7SJerome Forissier return NULL; 248a4f139d7SJerome Forissier } 249a4f139d7SJerome Forissier 2507ba16abbSJerome Forissier static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 251a5d5bbc8SVesa Jääskeläinen vaddr_t *vbase __unused, size_t *size __unused, 252a5d5bbc8SVesa Jääskeläinen enum dt_map_dev_directive mapping __unused) 2537ba16abbSJerome Forissier { 2547ba16abbSJerome Forissier return -1; 2557ba16abbSJerome Forissier } 2567ba16abbSJerome Forissier 257*f354a5d8SGatien Chevallier static inline paddr_t fdt_reg_base_address(const void *fdt __unused, 2589fe4c797SJerome Forissier int offs __unused) 2599fe4c797SJerome Forissier { 2609fe4c797SJerome Forissier return (paddr_t)-1; 2619fe4c797SJerome Forissier } 2629fe4c797SJerome Forissier 263*f354a5d8SGatien Chevallier static inline size_t fdt_reg_size(const void *fdt __unused, 2649fe4c797SJerome Forissier int offs __unused) 2659fe4c797SJerome Forissier { 266df7cecc0SLionel Debieve return (size_t)-1; 2679fe4c797SJerome Forissier } 2689fe4c797SJerome Forissier 269*f354a5d8SGatien Chevallier static inline int fdt_get_status(const void *fdt __unused, int offs __unused) 2709fe4c797SJerome Forissier { 2719fe4c797SJerome Forissier return -1; 2729fe4c797SJerome Forissier } 2739fe4c797SJerome Forissier 2741e866588SJerome Forissier __noreturn 275*f354a5d8SGatien Chevallier static inline void fdt_fill_device_info(const void *fdt __unused, 276c0cfb36cSEtienne Carriere struct dt_node_info *info __unused, 277c0cfb36cSEtienne Carriere int node __unused) 278c0cfb36cSEtienne Carriere { 279c0cfb36cSEtienne Carriere panic(); 280c0cfb36cSEtienne Carriere } 281876826f3SGabriel Fernandez 282*f354a5d8SGatien Chevallier static inline int fdt_read_uint32_array(const void *fdt __unused, 283876826f3SGabriel Fernandez int node __unused, 284876826f3SGabriel Fernandez const char *prop_name __unused, 285876826f3SGabriel Fernandez uint32_t *array __unused, 286876826f3SGabriel Fernandez size_t count __unused) 287876826f3SGabriel Fernandez { 288876826f3SGabriel Fernandez return -1; 289876826f3SGabriel Fernandez } 290876826f3SGabriel Fernandez 291*f354a5d8SGatien Chevallier static inline int fdt_read_uint32(const void *fdt __unused, 292876826f3SGabriel Fernandez int node __unused, 293876826f3SGabriel Fernandez const char *prop_name __unused, 294876826f3SGabriel Fernandez uint32_t *value __unused) 295876826f3SGabriel Fernandez { 296876826f3SGabriel Fernandez return -1; 297876826f3SGabriel Fernandez } 298876826f3SGabriel Fernandez 299*f354a5d8SGatien Chevallier static inline uint32_t fdt_read_uint32_default(const void *fdt __unused, 300876826f3SGabriel Fernandez int node __unused, 301876826f3SGabriel Fernandez const char *prop_name __unused, 302876826f3SGabriel Fernandez uint32_t dflt_value __unused) 303876826f3SGabriel Fernandez { 304876826f3SGabriel Fernandez return dflt_value; 305876826f3SGabriel Fernandez } 306876826f3SGabriel Fernandez 307a4f139d7SJerome Forissier #endif /* !CFG_DT */ 308a4f139d7SJerome Forissier 309a4f139d7SJerome Forissier #define for_each_dt_driver(drv) \ 31061bdedeaSJerome Forissier for (drv = SCATTERED_ARRAY_BEGIN(dt_drivers, struct dt_driver); \ 31161bdedeaSJerome Forissier drv < SCATTERED_ARRAY_END(dt_drivers, struct dt_driver); \ 31261bdedeaSJerome Forissier drv++) 313a4f139d7SJerome Forissier 314a4f139d7SJerome Forissier #endif /* KERNEL_DT_H */ 315