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> 12a4f139d7SJerome Forissier #include <stdint.h> 1301254f1dSEtienne Carriere #include <tee_api_types.h> 14a4f139d7SJerome Forissier #include <types_ext.h> 159fe4c797SJerome Forissier #include <util.h> 169fe4c797SJerome Forissier 179fe4c797SJerome Forissier /* 1823b1daf4SPeng Fan * Bitfield to reflect status and secure-status values ("okay", "disabled" 1923b1daf4SPeng Fan * or not present) 209fe4c797SJerome Forissier */ 21b4bfc9a9SJens Wiklander #define DT_STATUS_DISABLED U(0) 229fe4c797SJerome Forissier #define DT_STATUS_OK_NSEC BIT(0) 239fe4c797SJerome Forissier #define DT_STATUS_OK_SEC BIT(1) 24a4f139d7SJerome Forissier 25c0cfb36cSEtienne Carriere #define DT_INFO_INVALID_REG ((paddr_t)-1) 26df7cecc0SLionel Debieve #define DT_INFO_INVALID_REG_SIZE ((size_t)-1) 27c0cfb36cSEtienne Carriere #define DT_INFO_INVALID_CLOCK -1 28c0cfb36cSEtienne Carriere #define DT_INFO_INVALID_RESET -1 2995cdc5e0SCedric Neveux #define DT_INFO_INVALID_INTERRUPT -1 3095cdc5e0SCedric Neveux 31c0cfb36cSEtienne Carriere /* 32c0cfb36cSEtienne Carriere * @status: Bit mask for DT_STATUS_* 33c0cfb36cSEtienne Carriere * @reg: Device register physical base address or DT_INFO_INVALID_REG 3406fd21ddSLionel Debieve * @reg_size: Device register size or DT_INFO_INVALID_REG_SIZE 35c0cfb36cSEtienne Carriere * @clock: Device identifier (positive value) or DT_INFO_INVALID_CLOCK 36c0cfb36cSEtienne Carriere * @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK 377acb3a47SLudovic Barre * @interrupt: Device interrupt identifier (positive value) or 387acb3a47SLudovic Barre * DT_INFO_INVALID_INTERRUPT 39702fe5a7SClément Léger * @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if 40702fe5a7SClément Léger * not present 41702fe5a7SClément Léger * @prio: interrupt priority parsed from interrupts properties or 0 if not 42702fe5a7SClément Léger * present 43c0cfb36cSEtienne Carriere */ 44c0cfb36cSEtienne Carriere struct dt_node_info { 45c0cfb36cSEtienne Carriere unsigned int status; 46c0cfb36cSEtienne Carriere paddr_t reg; 4706fd21ddSLionel Debieve size_t reg_size; 48c0cfb36cSEtienne Carriere int clock; 49c0cfb36cSEtienne Carriere int reset; 507acb3a47SLudovic Barre int interrupt; 51702fe5a7SClément Léger uint32_t type; 52702fe5a7SClément Léger uint32_t prio; 53c0cfb36cSEtienne Carriere }; 54c0cfb36cSEtienne Carriere 55a4f139d7SJerome Forissier #if defined(CFG_DT) 56a4f139d7SJerome Forissier 57a4f139d7SJerome Forissier /* 58a4f139d7SJerome Forissier * DT-aware drivers 59a4f139d7SJerome Forissier */ 60a4f139d7SJerome Forissier 61a4f139d7SJerome Forissier struct dt_device_match { 62a4f139d7SJerome Forissier const char *compatible; 637e6a39feSEtienne Carriere const void *compat_data; 64a4f139d7SJerome Forissier }; 65a4f139d7SJerome Forissier 665e588771SClément Léger enum dt_driver_type { 675e588771SClément Léger DT_DRIVER_NOTYPE, 685e588771SClément Léger DT_DRIVER_UART, 692305544bSClément Léger DT_DRIVER_CLK, 705e588771SClément Léger }; 715e588771SClément Léger 7201254f1dSEtienne Carriere /* 7301254f1dSEtienne Carriere * dt_driver_probe_func - Callback probe function for a driver. 7401254f1dSEtienne Carriere * 7501254f1dSEtienne Carriere * @fdt: FDT base address 7601254f1dSEtienne Carriere * @nodeoffset: Offset of the node in the FDT 7701254f1dSEtienne Carriere * @compat_data: Data registered for the compatible that probed the device 7801254f1dSEtienne Carriere * 7901254f1dSEtienne Carriere * Return TEE_SUCCESS on successful probe, 80*b3a88b52SEtienne Carriere * TEE_ERROR_DEFER_DRIVER_INIT if probe must be deferred 8101254f1dSEtienne Carriere * TEE_ERROR_ITEM_NOT_FOUND when no driver matched node's compatible string 8201254f1dSEtienne Carriere * Any other TEE_ERROR_* compliant code. 8301254f1dSEtienne Carriere */ 8401254f1dSEtienne Carriere typedef TEE_Result (*dt_driver_probe_func)(const void *fdt, int nodeoffset, 8501254f1dSEtienne Carriere const void *compat_data); 8601254f1dSEtienne Carriere 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 104fd118772SJerome Forissier #define __dt_driver __section(".rodata.dtdrv" __SECTION_FLAGS_RODATA) 105a4f139d7SJerome Forissier 106a4f139d7SJerome Forissier /* 107a4f139d7SJerome Forissier * Find a driver that is suitable for the given DT node, that is, with 108a4f139d7SJerome Forissier * a matching "compatible" property. 109a4f139d7SJerome Forissier * 110a4f139d7SJerome Forissier * @fdt: pointer to the device tree 111a4f139d7SJerome Forissier * @offs: node offset 112a4f139d7SJerome Forissier */ 113a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 114a4f139d7SJerome Forissier 115a4f139d7SJerome Forissier const struct dt_driver *__dt_driver_start(void); 116a4f139d7SJerome Forissier 117a4f139d7SJerome Forissier const struct dt_driver *__dt_driver_end(void); 118a4f139d7SJerome Forissier 1199fe4c797SJerome Forissier /* 1207ba16abbSJerome Forissier * Map a device into secure or non-secure memory and return the base VA and 1217ba16abbSJerome Forissier * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 1227ba16abbSJerome Forissier * MEM_AREA_IO_NSEC, depending on the device status. 1237ba16abbSJerome Forissier * If the mapping already exists, the function simply returns the @vbase and 1247ba16abbSJerome Forissier * @size information. 1257ba16abbSJerome Forissier * 1267ba16abbSJerome Forissier * @offs is the offset of the node that describes the device in @fdt. 1277ba16abbSJerome Forissier * @base receives the base virtual address corresponding to the base physical 1287ba16abbSJerome Forissier * address of the "reg" property 1297ba16abbSJerome Forissier * @size receives the size of the mapping 1307ba16abbSJerome Forissier * 1317ba16abbSJerome Forissier * Returns 0 on success or -1 in case of error. 1327ba16abbSJerome Forissier */ 1337ba16abbSJerome Forissier int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size); 1347ba16abbSJerome Forissier 1357ba16abbSJerome Forissier /* 13650f3b323SPeng Fan * Check whether the node at @offs contains the property with propname or not. 13750f3b323SPeng Fan * 13850f3b323SPeng Fan * @offs is the offset of the node that describes the device in @fdt. 13950f3b323SPeng Fan * @propname is the property that need to check 14050f3b323SPeng Fan * 14150f3b323SPeng Fan * Returns true on success or false if no propname. 14250f3b323SPeng Fan */ 14350f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname); 14450f3b323SPeng Fan 14550f3b323SPeng Fan /* 14695cdc5e0SCedric Neveux * Modify or add "status" property to "disabled" 14795cdc5e0SCedric Neveux * 14895cdc5e0SCedric Neveux * @fdt reference to the Device Tree 14995cdc5e0SCedric Neveux * @node is the node offset to modify 15095cdc5e0SCedric Neveux * 15195cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 15295cdc5e0SCedric Neveux */ 15395cdc5e0SCedric Neveux int dt_disable_status(void *fdt, int node); 15495cdc5e0SCedric Neveux 15595cdc5e0SCedric Neveux /* 15695cdc5e0SCedric Neveux * Force secure-status = "okay" and status="disabled" for the target node. 15795cdc5e0SCedric Neveux * 15895cdc5e0SCedric Neveux * @fdt reference to the Device Tree 15995cdc5e0SCedric Neveux * @node is the node offset to modify 16095cdc5e0SCedric Neveux * 16195cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 16295cdc5e0SCedric Neveux */ 16395cdc5e0SCedric Neveux int dt_enable_secure_status(void *fdt, int node); 16495cdc5e0SCedric Neveux 16595cdc5e0SCedric Neveux /* 1669fe4c797SJerome Forissier * FDT manipulation functions, not provided by <libfdt.h> 1679fe4c797SJerome Forissier */ 1689fe4c797SJerome Forissier 1699fe4c797SJerome Forissier /* 1709fe4c797SJerome Forissier * Return the base address for the "reg" property of the specified node or 1719fe4c797SJerome Forissier * (paddr_t)-1 in case of error 1729fe4c797SJerome Forissier */ 1739fe4c797SJerome Forissier paddr_t _fdt_reg_base_address(const void *fdt, int offs); 1749fe4c797SJerome Forissier 1759fe4c797SJerome Forissier /* 1769fe4c797SJerome Forissier * Return the reg size for the reg property of the specified node or -1 in case 1779fe4c797SJerome Forissier * of error 1789fe4c797SJerome Forissier */ 179df7cecc0SLionel Debieve size_t _fdt_reg_size(const void *fdt, int offs); 1809fe4c797SJerome Forissier 1819fe4c797SJerome Forissier /* 1829fe4c797SJerome Forissier * Read the status and secure-status properties into a bitfield. 1839fe4c797SJerome Forissier * @status is set to DT_STATUS_DISABLED or a combination of DT_STATUS_OK_NSEC 18484c93d58SEtienne Carriere * and DT_STATUS_OK_SEC. 1859fe4c797SJerome Forissier */ 1869fe4c797SJerome Forissier int _fdt_get_status(const void *fdt, int offs); 1879fe4c797SJerome Forissier 188c0cfb36cSEtienne Carriere /* 189c0cfb36cSEtienne Carriere * fdt_fill_device_info - Get generic device info from a node 190c0cfb36cSEtienne Carriere * 191c0cfb36cSEtienne Carriere * This function fills the generic information from a given node. 192c0cfb36cSEtienne Carriere * Currently supports a single base register, a single clock, 193c0cfb36cSEtienne Carriere * a single reset ID line and a single interrupt ID. 194c0cfb36cSEtienne Carriere * Default DT_INFO_* macros are used when the relate property is not found. 195c0cfb36cSEtienne Carriere */ 196df45c114SEtienne Carriere void _fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 197df45c114SEtienne Carriere int node); 198c0cfb36cSEtienne Carriere 1999fe4c797SJerome Forissier #else /* !CFG_DT */ 200a4f139d7SJerome Forissier 201a4f139d7SJerome Forissier static inline const struct dt_driver *__dt_driver_start(void) 202a4f139d7SJerome Forissier { 203a4f139d7SJerome Forissier return NULL; 204a4f139d7SJerome Forissier } 205a4f139d7SJerome Forissier 206a4f139d7SJerome Forissier static inline const struct dt_driver *__dt_driver_end(void) 207a4f139d7SJerome Forissier { 208a4f139d7SJerome Forissier return NULL; 209a4f139d7SJerome Forissier } 210a4f139d7SJerome Forissier 211a4f139d7SJerome Forissier static inline const struct dt_driver *dt_find_compatible_driver( 212a4f139d7SJerome Forissier const void *fdt __unused, 213a4f139d7SJerome Forissier int offs __unused) 214a4f139d7SJerome Forissier { 215a4f139d7SJerome Forissier return NULL; 216a4f139d7SJerome Forissier } 217a4f139d7SJerome Forissier 2187ba16abbSJerome Forissier static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 2197ba16abbSJerome Forissier vaddr_t *vbase __unused, size_t *size __unused) 2207ba16abbSJerome Forissier { 2217ba16abbSJerome Forissier return -1; 2227ba16abbSJerome Forissier } 2237ba16abbSJerome Forissier 2249fe4c797SJerome Forissier static inline paddr_t _fdt_reg_base_address(const void *fdt __unused, 2259fe4c797SJerome Forissier int offs __unused) 2269fe4c797SJerome Forissier { 2279fe4c797SJerome Forissier return (paddr_t)-1; 2289fe4c797SJerome Forissier } 2299fe4c797SJerome Forissier 230df7cecc0SLionel Debieve static inline size_t _fdt_reg_size(const void *fdt __unused, 2319fe4c797SJerome Forissier int offs __unused) 2329fe4c797SJerome Forissier { 233df7cecc0SLionel Debieve return (size_t)-1; 2349fe4c797SJerome Forissier } 2359fe4c797SJerome Forissier 2369fe4c797SJerome Forissier static inline int _fdt_get_status(const void *fdt __unused, int offs __unused) 2379fe4c797SJerome Forissier { 2389fe4c797SJerome Forissier return -1; 2399fe4c797SJerome Forissier } 2409fe4c797SJerome Forissier 2411e866588SJerome Forissier __noreturn 242df45c114SEtienne Carriere static inline void _fdt_fill_device_info(const void *fdt __unused, 243c0cfb36cSEtienne Carriere struct dt_node_info *info __unused, 244c0cfb36cSEtienne Carriere int node __unused) 245c0cfb36cSEtienne Carriere { 246c0cfb36cSEtienne Carriere panic(); 247c0cfb36cSEtienne Carriere } 248a4f139d7SJerome Forissier #endif /* !CFG_DT */ 249a4f139d7SJerome Forissier 250a4f139d7SJerome Forissier #define for_each_dt_driver(drv) \ 251a4f139d7SJerome Forissier for (drv = __dt_driver_start(); drv < __dt_driver_end(); drv++) 252a4f139d7SJerome Forissier 253a4f139d7SJerome Forissier #endif /* KERNEL_DT_H */ 254