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> 12*61bdedeaSJerome 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, 695e588771SClément Léger }; 705e588771SClément Léger 7101254f1dSEtienne Carriere /* 7201254f1dSEtienne Carriere * dt_driver_probe_func - Callback probe function for a driver. 7301254f1dSEtienne Carriere * 7401254f1dSEtienne Carriere * @fdt: FDT base address 7501254f1dSEtienne Carriere * @nodeoffset: Offset of the node in the FDT 7601254f1dSEtienne Carriere * @compat_data: Data registered for the compatible that probed the device 7701254f1dSEtienne Carriere * 7801254f1dSEtienne Carriere * Return TEE_SUCCESS on successful probe, 79b3a88b52SEtienne Carriere * TEE_ERROR_DEFER_DRIVER_INIT if probe must be deferred 8001254f1dSEtienne Carriere * TEE_ERROR_ITEM_NOT_FOUND when no driver matched node's compatible string 8101254f1dSEtienne Carriere * Any other TEE_ERROR_* compliant code. 8201254f1dSEtienne Carriere */ 8301254f1dSEtienne Carriere typedef TEE_Result (*dt_driver_probe_func)(const void *fdt, int nodeoffset, 8401254f1dSEtienne Carriere const void *compat_data); 8501254f1dSEtienne Carriere 86670fa4aaSEtienne Carriere #if defined(CFG_DT) 8701254f1dSEtienne Carriere /* 8801254f1dSEtienne Carriere * Driver instance registered to be probed on compatible node found in the DT. 8901254f1dSEtienne Carriere * 9001254f1dSEtienne Carriere * @name: Driver name 9101254f1dSEtienne Carriere * @type: Drive type 9201254f1dSEtienne Carriere * @match_table: Compatible matching identifiers, null terminated 9301254f1dSEtienne Carriere * @driver: Driver private reference or NULL 9401254f1dSEtienne Carriere * @probe: Probe callback (see dt_driver_probe_func) or NULL 9501254f1dSEtienne Carriere */ 96a4f139d7SJerome Forissier struct dt_driver { 97a4f139d7SJerome Forissier const char *name; 985e588771SClément Léger enum dt_driver_type type; 99a4f139d7SJerome Forissier const struct dt_device_match *match_table; /* null-terminated */ 100a4f139d7SJerome Forissier const void *driver; 10101254f1dSEtienne Carriere TEE_Result (*probe)(const void *fdt, int node, const void *compat_data); 102a4f139d7SJerome Forissier }; 103a4f139d7SJerome Forissier 104*61bdedeaSJerome Forissier #define DEFINE_DT_DRIVER(name) \ 105*61bdedeaSJerome Forissier SCATTERED_ARRAY_DEFINE_ITEM(dt_drivers, struct dt_driver) 106a4f139d7SJerome Forissier 107a4f139d7SJerome Forissier /* 108a4f139d7SJerome Forissier * Find a driver that is suitable for the given DT node, that is, with 109a4f139d7SJerome Forissier * a matching "compatible" property. 110a4f139d7SJerome Forissier * 111a4f139d7SJerome Forissier * @fdt: pointer to the device tree 112a4f139d7SJerome Forissier * @offs: node offset 113a4f139d7SJerome Forissier */ 114a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 115a4f139d7SJerome Forissier 1169fe4c797SJerome Forissier /* 1177ba16abbSJerome Forissier * Map a device into secure or non-secure memory and return the base VA and 1187ba16abbSJerome Forissier * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 1197ba16abbSJerome Forissier * MEM_AREA_IO_NSEC, depending on the device status. 1207ba16abbSJerome Forissier * If the mapping already exists, the function simply returns the @vbase and 1217ba16abbSJerome Forissier * @size information. 1227ba16abbSJerome Forissier * 1237ba16abbSJerome Forissier * @offs is the offset of the node that describes the device in @fdt. 1247ba16abbSJerome Forissier * @base receives the base virtual address corresponding to the base physical 1257ba16abbSJerome Forissier * address of the "reg" property 1267ba16abbSJerome Forissier * @size receives the size of the mapping 1277ba16abbSJerome Forissier * 1287ba16abbSJerome Forissier * Returns 0 on success or -1 in case of error. 1297ba16abbSJerome Forissier */ 1307ba16abbSJerome Forissier int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size); 1317ba16abbSJerome Forissier 1327ba16abbSJerome Forissier /* 13350f3b323SPeng Fan * Check whether the node at @offs contains the property with propname or not. 13450f3b323SPeng Fan * 13550f3b323SPeng Fan * @offs is the offset of the node that describes the device in @fdt. 13650f3b323SPeng Fan * @propname is the property that need to check 13750f3b323SPeng Fan * 13850f3b323SPeng Fan * Returns true on success or false if no propname. 13950f3b323SPeng Fan */ 14050f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname); 14150f3b323SPeng Fan 14250f3b323SPeng Fan /* 14395cdc5e0SCedric Neveux * Modify or add "status" property to "disabled" 14495cdc5e0SCedric Neveux * 14595cdc5e0SCedric Neveux * @fdt reference to the Device Tree 14695cdc5e0SCedric Neveux * @node is the node offset to modify 14795cdc5e0SCedric Neveux * 14895cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 14995cdc5e0SCedric Neveux */ 15095cdc5e0SCedric Neveux int dt_disable_status(void *fdt, int node); 15195cdc5e0SCedric Neveux 15295cdc5e0SCedric Neveux /* 15395cdc5e0SCedric Neveux * Force secure-status = "okay" and status="disabled" for the target node. 15495cdc5e0SCedric Neveux * 15595cdc5e0SCedric Neveux * @fdt reference to the Device Tree 15695cdc5e0SCedric Neveux * @node is the node offset to modify 15795cdc5e0SCedric Neveux * 15895cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 15995cdc5e0SCedric Neveux */ 16095cdc5e0SCedric Neveux int dt_enable_secure_status(void *fdt, int node); 16195cdc5e0SCedric Neveux 16295cdc5e0SCedric Neveux /* 1639fe4c797SJerome Forissier * FDT manipulation functions, not provided by <libfdt.h> 1649fe4c797SJerome Forissier */ 1659fe4c797SJerome Forissier 1669fe4c797SJerome Forissier /* 1679fe4c797SJerome Forissier * Return the base address for the "reg" property of the specified node or 1689fe4c797SJerome Forissier * (paddr_t)-1 in case of error 1699fe4c797SJerome Forissier */ 1709fe4c797SJerome Forissier paddr_t _fdt_reg_base_address(const void *fdt, int offs); 1719fe4c797SJerome Forissier 1729fe4c797SJerome Forissier /* 1739fe4c797SJerome Forissier * Return the reg size for the reg property of the specified node or -1 in case 1749fe4c797SJerome Forissier * of error 1759fe4c797SJerome Forissier */ 176df7cecc0SLionel Debieve size_t _fdt_reg_size(const void *fdt, int offs); 1779fe4c797SJerome Forissier 1789fe4c797SJerome Forissier /* 1799fe4c797SJerome Forissier * Read the status and secure-status properties into a bitfield. 180c020046dSEtienne Carriere * Return -1 on failure, DT_STATUS_DISABLED if the node is disabled, 181c020046dSEtienne Carriere * otherwise return a combination of DT_STATUS_OK_NSEC and DT_STATUS_OK_SEC. 1829fe4c797SJerome Forissier */ 1839fe4c797SJerome Forissier int _fdt_get_status(const void *fdt, int offs); 1849fe4c797SJerome Forissier 185c0cfb36cSEtienne Carriere /* 186c0cfb36cSEtienne Carriere * fdt_fill_device_info - Get generic device info from a node 187c0cfb36cSEtienne Carriere * 188c0cfb36cSEtienne Carriere * This function fills the generic information from a given node. 189c0cfb36cSEtienne Carriere * Currently supports a single base register, a single clock, 190c0cfb36cSEtienne Carriere * a single reset ID line and a single interrupt ID. 191c0cfb36cSEtienne Carriere * Default DT_INFO_* macros are used when the relate property is not found. 192c0cfb36cSEtienne Carriere */ 193df45c114SEtienne Carriere void _fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 194df45c114SEtienne Carriere int node); 195c0cfb36cSEtienne Carriere 1969fe4c797SJerome Forissier #else /* !CFG_DT */ 197a4f139d7SJerome Forissier 198a4f139d7SJerome Forissier static inline const struct dt_driver *dt_find_compatible_driver( 199a4f139d7SJerome Forissier const void *fdt __unused, 200a4f139d7SJerome Forissier int offs __unused) 201a4f139d7SJerome Forissier { 202a4f139d7SJerome Forissier return NULL; 203a4f139d7SJerome Forissier } 204a4f139d7SJerome Forissier 2057ba16abbSJerome Forissier static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 2067ba16abbSJerome Forissier vaddr_t *vbase __unused, size_t *size __unused) 2077ba16abbSJerome Forissier { 2087ba16abbSJerome Forissier return -1; 2097ba16abbSJerome Forissier } 2107ba16abbSJerome Forissier 2119fe4c797SJerome Forissier static inline paddr_t _fdt_reg_base_address(const void *fdt __unused, 2129fe4c797SJerome Forissier int offs __unused) 2139fe4c797SJerome Forissier { 2149fe4c797SJerome Forissier return (paddr_t)-1; 2159fe4c797SJerome Forissier } 2169fe4c797SJerome Forissier 217df7cecc0SLionel Debieve static inline size_t _fdt_reg_size(const void *fdt __unused, 2189fe4c797SJerome Forissier int offs __unused) 2199fe4c797SJerome Forissier { 220df7cecc0SLionel Debieve return (size_t)-1; 2219fe4c797SJerome Forissier } 2229fe4c797SJerome Forissier 2239fe4c797SJerome Forissier static inline int _fdt_get_status(const void *fdt __unused, int offs __unused) 2249fe4c797SJerome Forissier { 2259fe4c797SJerome Forissier return -1; 2269fe4c797SJerome Forissier } 2279fe4c797SJerome Forissier 2281e866588SJerome Forissier __noreturn 229df45c114SEtienne Carriere static inline void _fdt_fill_device_info(const void *fdt __unused, 230c0cfb36cSEtienne Carriere struct dt_node_info *info __unused, 231c0cfb36cSEtienne Carriere int node __unused) 232c0cfb36cSEtienne Carriere { 233c0cfb36cSEtienne Carriere panic(); 234c0cfb36cSEtienne Carriere } 235a4f139d7SJerome Forissier #endif /* !CFG_DT */ 236a4f139d7SJerome Forissier 237a4f139d7SJerome Forissier #define for_each_dt_driver(drv) \ 238*61bdedeaSJerome Forissier for (drv = SCATTERED_ARRAY_BEGIN(dt_drivers, struct dt_driver); \ 239*61bdedeaSJerome Forissier drv < SCATTERED_ARRAY_END(dt_drivers, struct dt_driver); \ 240*61bdedeaSJerome Forissier drv++) 241a4f139d7SJerome Forissier 242a4f139d7SJerome Forissier #endif /* KERNEL_DT_H */ 243