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, 705e588771SClément Léger }; 715e588771SClément Léger 7201254f1dSEtienne Carriere /* 73*a5d5bbc8SVesa Jääskeläinen * DT_MAP_AUTO: Uses status properties from device tree to determine mapping. 74*a5d5bbc8SVesa Jääskeläinen * DT_MAP_SECURE: Force mapping for device to be secure. 75*a5d5bbc8SVesa Jääskeläinen * DT_MAP_NON_SECURE: Force mapping for device to be non-secure. 76*a5d5bbc8SVesa Jääskeläinen */ 77*a5d5bbc8SVesa Jääskeläinen enum dt_map_dev_directive { 78*a5d5bbc8SVesa Jääskeläinen DT_MAP_AUTO, 79*a5d5bbc8SVesa Jääskeläinen DT_MAP_SECURE, 80*a5d5bbc8SVesa Jääskeläinen DT_MAP_NON_SECURE 81*a5d5bbc8SVesa Jääskeläinen }; 82*a5d5bbc8SVesa Jääskeläinen 83*a5d5bbc8SVesa Jääskeläinen /* 8401254f1dSEtienne Carriere * dt_driver_probe_func - Callback probe function for a driver. 8501254f1dSEtienne Carriere * 8601254f1dSEtienne Carriere * @fdt: FDT base address 8701254f1dSEtienne Carriere * @nodeoffset: Offset of the node in the FDT 8801254f1dSEtienne Carriere * @compat_data: Data registered for the compatible that probed the device 8901254f1dSEtienne Carriere * 9001254f1dSEtienne Carriere * Return TEE_SUCCESS on successful probe, 91b3a88b52SEtienne Carriere * TEE_ERROR_DEFER_DRIVER_INIT if probe must be deferred 9201254f1dSEtienne Carriere * TEE_ERROR_ITEM_NOT_FOUND when no driver matched node's compatible string 9301254f1dSEtienne Carriere * Any other TEE_ERROR_* compliant code. 9401254f1dSEtienne Carriere */ 9501254f1dSEtienne Carriere typedef TEE_Result (*dt_driver_probe_func)(const void *fdt, int nodeoffset, 9601254f1dSEtienne Carriere const void *compat_data); 9701254f1dSEtienne Carriere 98670fa4aaSEtienne Carriere #if defined(CFG_DT) 9901254f1dSEtienne Carriere /* 10001254f1dSEtienne Carriere * Driver instance registered to be probed on compatible node found in the DT. 10101254f1dSEtienne Carriere * 10201254f1dSEtienne Carriere * @name: Driver name 10301254f1dSEtienne Carriere * @type: Drive type 10401254f1dSEtienne Carriere * @match_table: Compatible matching identifiers, null terminated 10501254f1dSEtienne Carriere * @driver: Driver private reference or NULL 10601254f1dSEtienne Carriere * @probe: Probe callback (see dt_driver_probe_func) or NULL 10701254f1dSEtienne Carriere */ 108a4f139d7SJerome Forissier struct dt_driver { 109a4f139d7SJerome Forissier const char *name; 1105e588771SClément Léger enum dt_driver_type type; 111a4f139d7SJerome Forissier const struct dt_device_match *match_table; /* null-terminated */ 112a4f139d7SJerome Forissier const void *driver; 11301254f1dSEtienne Carriere TEE_Result (*probe)(const void *fdt, int node, const void *compat_data); 114a4f139d7SJerome Forissier }; 115a4f139d7SJerome Forissier 11661bdedeaSJerome Forissier #define DEFINE_DT_DRIVER(name) \ 117ace4d69dSEtienne Carriere SCATTERED_ARRAY_DEFINE_PG_ITEM(dt_drivers, struct dt_driver) 118a4f139d7SJerome Forissier 119a4f139d7SJerome Forissier /* 120a4f139d7SJerome Forissier * Find a driver that is suitable for the given DT node, that is, with 121a4f139d7SJerome Forissier * a matching "compatible" property. 122a4f139d7SJerome Forissier * 123a4f139d7SJerome Forissier * @fdt: pointer to the device tree 124a4f139d7SJerome Forissier * @offs: node offset 125a4f139d7SJerome Forissier */ 126a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 127a4f139d7SJerome Forissier 1289fe4c797SJerome Forissier /* 1297ba16abbSJerome Forissier * Map a device into secure or non-secure memory and return the base VA and 1307ba16abbSJerome Forissier * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 1317ba16abbSJerome Forissier * MEM_AREA_IO_NSEC, depending on the device status. 1327ba16abbSJerome Forissier * If the mapping already exists, the function simply returns the @vbase and 1337ba16abbSJerome Forissier * @size information. 1347ba16abbSJerome Forissier * 1357ba16abbSJerome Forissier * @offs is the offset of the node that describes the device in @fdt. 1367ba16abbSJerome Forissier * @base receives the base virtual address corresponding to the base physical 1377ba16abbSJerome Forissier * address of the "reg" property 1387ba16abbSJerome Forissier * @size receives the size of the mapping 139*a5d5bbc8SVesa Jääskeläinen * @mapping what kind of mapping is done for memory. 1407ba16abbSJerome Forissier * 1417ba16abbSJerome Forissier * Returns 0 on success or -1 in case of error. 1427ba16abbSJerome Forissier */ 143*a5d5bbc8SVesa Jääskeläinen int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size, 144*a5d5bbc8SVesa Jääskeläinen enum dt_map_dev_directive mapping); 1457ba16abbSJerome Forissier 1467ba16abbSJerome Forissier /* 14750f3b323SPeng Fan * Check whether the node at @offs contains the property with propname or not. 14850f3b323SPeng Fan * 14950f3b323SPeng Fan * @offs is the offset of the node that describes the device in @fdt. 15050f3b323SPeng Fan * @propname is the property that need to check 15150f3b323SPeng Fan * 15250f3b323SPeng Fan * Returns true on success or false if no propname. 15350f3b323SPeng Fan */ 15450f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname); 15550f3b323SPeng Fan 15650f3b323SPeng Fan /* 15795cdc5e0SCedric Neveux * Modify or add "status" property to "disabled" 15895cdc5e0SCedric Neveux * 15995cdc5e0SCedric Neveux * @fdt reference to the Device Tree 16095cdc5e0SCedric Neveux * @node is the node offset to modify 16195cdc5e0SCedric Neveux * 16295cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 16395cdc5e0SCedric Neveux */ 16495cdc5e0SCedric Neveux int dt_disable_status(void *fdt, int node); 16595cdc5e0SCedric Neveux 16695cdc5e0SCedric Neveux /* 16795cdc5e0SCedric Neveux * Force secure-status = "okay" and status="disabled" for the target node. 16895cdc5e0SCedric Neveux * 16995cdc5e0SCedric Neveux * @fdt reference to the Device Tree 17095cdc5e0SCedric Neveux * @node is the node offset to modify 17195cdc5e0SCedric Neveux * 17295cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 17395cdc5e0SCedric Neveux */ 17495cdc5e0SCedric Neveux int dt_enable_secure_status(void *fdt, int node); 17595cdc5e0SCedric Neveux 17695cdc5e0SCedric Neveux /* 1779fe4c797SJerome Forissier * FDT manipulation functions, not provided by <libfdt.h> 1789fe4c797SJerome Forissier */ 1799fe4c797SJerome Forissier 1809fe4c797SJerome Forissier /* 1819fe4c797SJerome Forissier * Return the base address for the "reg" property of the specified node or 1829fe4c797SJerome Forissier * (paddr_t)-1 in case of error 1839fe4c797SJerome Forissier */ 1849fe4c797SJerome Forissier paddr_t _fdt_reg_base_address(const void *fdt, int offs); 1859fe4c797SJerome Forissier 1869fe4c797SJerome Forissier /* 1879fe4c797SJerome Forissier * Return the reg size for the reg property of the specified node or -1 in case 1889fe4c797SJerome Forissier * of error 1899fe4c797SJerome Forissier */ 190df7cecc0SLionel Debieve size_t _fdt_reg_size(const void *fdt, int offs); 1919fe4c797SJerome Forissier 1929fe4c797SJerome Forissier /* 1939fe4c797SJerome Forissier * Read the status and secure-status properties into a bitfield. 194c020046dSEtienne Carriere * Return -1 on failure, DT_STATUS_DISABLED if the node is disabled, 195c020046dSEtienne Carriere * otherwise return a combination of DT_STATUS_OK_NSEC and DT_STATUS_OK_SEC. 1969fe4c797SJerome Forissier */ 1979fe4c797SJerome Forissier int _fdt_get_status(const void *fdt, int offs); 1989fe4c797SJerome Forissier 199c0cfb36cSEtienne Carriere /* 200c0cfb36cSEtienne Carriere * fdt_fill_device_info - Get generic device info from a node 201c0cfb36cSEtienne Carriere * 202c0cfb36cSEtienne Carriere * This function fills the generic information from a given node. 203c0cfb36cSEtienne Carriere * Currently supports a single base register, a single clock, 204c0cfb36cSEtienne Carriere * a single reset ID line and a single interrupt ID. 205c0cfb36cSEtienne Carriere * Default DT_INFO_* macros are used when the relate property is not found. 206c0cfb36cSEtienne Carriere */ 207df45c114SEtienne Carriere void _fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 208df45c114SEtienne Carriere int node); 209876826f3SGabriel Fernandez /* 210876826f3SGabriel Fernandez * Read cells from a given property of the given node. Any number of 32-bit 211876826f3SGabriel Fernandez * cells of the property can be read. Returns 0 on success, or a negative 212876826f3SGabriel Fernandez * FDT error value otherwise. 213876826f3SGabriel Fernandez */ 214876826f3SGabriel Fernandez int _fdt_read_uint32_array(const void *fdt, int node, const char *prop_name, 215876826f3SGabriel Fernandez uint32_t *array, size_t count); 216876826f3SGabriel Fernandez 217876826f3SGabriel Fernandez /* 218876826f3SGabriel Fernandez * Read one cell from a given property of the given node. 219876826f3SGabriel Fernandez * Returns 0 on success, or a negative FDT error value otherwise. 220876826f3SGabriel Fernandez */ 221876826f3SGabriel Fernandez int _fdt_read_uint32(const void *fdt, int node, const char *prop_name, 222876826f3SGabriel Fernandez uint32_t *value); 223876826f3SGabriel Fernandez 224876826f3SGabriel Fernandez /* 225876826f3SGabriel Fernandez * Read one cell from a property of a cell or default to a given value 226876826f3SGabriel Fernandez * Returns the 32bit cell value or @dflt_value on failure. 227876826f3SGabriel Fernandez */ 228876826f3SGabriel Fernandez uint32_t _fdt_read_uint32_default(const void *fdt, int node, 229876826f3SGabriel Fernandez const char *prop_name, uint32_t dflt_value); 230876826f3SGabriel Fernandez 231876826f3SGabriel Fernandez /* 232876826f3SGabriel Fernandez * Check whether the node at @node has a reference name. 233876826f3SGabriel Fernandez * 234876826f3SGabriel Fernandez * @node is the offset of the node that describes the device in @fdt. 235876826f3SGabriel Fernandez * 236876826f3SGabriel Fernandez * Returns true on success or false if no property 237876826f3SGabriel Fernandez */ 238876826f3SGabriel Fernandez bool _fdt_check_node(const void *fdt, int node); 239c0cfb36cSEtienne Carriere 2409fe4c797SJerome Forissier #else /* !CFG_DT */ 241a4f139d7SJerome Forissier 242a4f139d7SJerome Forissier static inline const struct dt_driver *dt_find_compatible_driver( 243a4f139d7SJerome Forissier const void *fdt __unused, 244a4f139d7SJerome Forissier int offs __unused) 245a4f139d7SJerome Forissier { 246a4f139d7SJerome Forissier return NULL; 247a4f139d7SJerome Forissier } 248a4f139d7SJerome Forissier 2497ba16abbSJerome Forissier static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 250*a5d5bbc8SVesa Jääskeläinen vaddr_t *vbase __unused, size_t *size __unused, 251*a5d5bbc8SVesa Jääskeläinen enum dt_map_dev_directive mapping __unused) 2527ba16abbSJerome Forissier { 2537ba16abbSJerome Forissier return -1; 2547ba16abbSJerome Forissier } 2557ba16abbSJerome Forissier 2569fe4c797SJerome Forissier static inline paddr_t _fdt_reg_base_address(const void *fdt __unused, 2579fe4c797SJerome Forissier int offs __unused) 2589fe4c797SJerome Forissier { 2599fe4c797SJerome Forissier return (paddr_t)-1; 2609fe4c797SJerome Forissier } 2619fe4c797SJerome Forissier 262df7cecc0SLionel Debieve static inline size_t _fdt_reg_size(const void *fdt __unused, 2639fe4c797SJerome Forissier int offs __unused) 2649fe4c797SJerome Forissier { 265df7cecc0SLionel Debieve return (size_t)-1; 2669fe4c797SJerome Forissier } 2679fe4c797SJerome Forissier 2689fe4c797SJerome Forissier static inline int _fdt_get_status(const void *fdt __unused, int offs __unused) 2699fe4c797SJerome Forissier { 2709fe4c797SJerome Forissier return -1; 2719fe4c797SJerome Forissier } 2729fe4c797SJerome Forissier 2731e866588SJerome Forissier __noreturn 274df45c114SEtienne Carriere static inline void _fdt_fill_device_info(const void *fdt __unused, 275c0cfb36cSEtienne Carriere struct dt_node_info *info __unused, 276c0cfb36cSEtienne Carriere int node __unused) 277c0cfb36cSEtienne Carriere { 278c0cfb36cSEtienne Carriere panic(); 279c0cfb36cSEtienne Carriere } 280876826f3SGabriel Fernandez 281876826f3SGabriel Fernandez static inline int _fdt_read_uint32_array(const void *fdt __unused, 282876826f3SGabriel Fernandez int node __unused, 283876826f3SGabriel Fernandez const char *prop_name __unused, 284876826f3SGabriel Fernandez uint32_t *array __unused, 285876826f3SGabriel Fernandez size_t count __unused) 286876826f3SGabriel Fernandez { 287876826f3SGabriel Fernandez return -1; 288876826f3SGabriel Fernandez } 289876826f3SGabriel Fernandez 290876826f3SGabriel Fernandez static inline int _fdt_read_uint32(const void *fdt __unused, 291876826f3SGabriel Fernandez int node __unused, 292876826f3SGabriel Fernandez const char *prop_name __unused, 293876826f3SGabriel Fernandez uint32_t *value __unused) 294876826f3SGabriel Fernandez { 295876826f3SGabriel Fernandez return -1; 296876826f3SGabriel Fernandez } 297876826f3SGabriel Fernandez 298876826f3SGabriel Fernandez static inline uint32_t _fdt_read_uint32_default(const void *fdt __unused, 299876826f3SGabriel Fernandez int node __unused, 300876826f3SGabriel Fernandez const char *prop_name __unused, 301876826f3SGabriel Fernandez uint32_t dflt_value __unused) 302876826f3SGabriel Fernandez { 303876826f3SGabriel Fernandez return dflt_value; 304876826f3SGabriel Fernandez } 305876826f3SGabriel Fernandez 306a4f139d7SJerome Forissier #endif /* !CFG_DT */ 307a4f139d7SJerome Forissier 308a4f139d7SJerome Forissier #define for_each_dt_driver(drv) \ 30961bdedeaSJerome Forissier for (drv = SCATTERED_ARRAY_BEGIN(dt_drivers, struct dt_driver); \ 31061bdedeaSJerome Forissier drv < SCATTERED_ARRAY_END(dt_drivers, struct dt_driver); \ 31161bdedeaSJerome Forissier drv++) 312a4f139d7SJerome Forissier 313a4f139d7SJerome Forissier #endif /* KERNEL_DT_H */ 314