11bb92983SJerome Forissier /* SPDX-License-Identifier: BSD-2-Clause */ 2a4f139d7SJerome Forissier /* 3a4f139d7SJerome Forissier * Copyright (c) 2016, 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> 13a4f139d7SJerome Forissier #include <types_ext.h> 149fe4c797SJerome Forissier #include <util.h> 159fe4c797SJerome Forissier 169fe4c797SJerome Forissier /* 1723b1daf4SPeng Fan * Bitfield to reflect status and secure-status values ("okay", "disabled" 1823b1daf4SPeng Fan * or not present) 199fe4c797SJerome Forissier */ 20b4bfc9a9SJens Wiklander #define DT_STATUS_DISABLED U(0) 219fe4c797SJerome Forissier #define DT_STATUS_OK_NSEC BIT(0) 229fe4c797SJerome Forissier #define DT_STATUS_OK_SEC BIT(1) 23a4f139d7SJerome Forissier 24c0cfb36cSEtienne Carriere #define DT_INFO_INVALID_REG ((paddr_t)-1) 25*df7cecc0SLionel Debieve #define DT_INFO_INVALID_REG_SIZE ((size_t)-1) 26c0cfb36cSEtienne Carriere #define DT_INFO_INVALID_CLOCK -1 27c0cfb36cSEtienne Carriere #define DT_INFO_INVALID_RESET -1 2895cdc5e0SCedric Neveux #define DT_INFO_INVALID_INTERRUPT -1 2995cdc5e0SCedric Neveux 30c0cfb36cSEtienne Carriere /* 31c0cfb36cSEtienne Carriere * @status: Bit mask for DT_STATUS_* 32c0cfb36cSEtienne Carriere * @reg: Device register physical base address or DT_INFO_INVALID_REG 33c0cfb36cSEtienne Carriere * @clock: Device identifier (positive value) or DT_INFO_INVALID_CLOCK 34c0cfb36cSEtienne Carriere * @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK 357acb3a47SLudovic Barre * @interrupt: Device interrupt identifier (positive value) or 367acb3a47SLudovic Barre * DT_INFO_INVALID_INTERRUPT 37702fe5a7SClément Léger * @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if 38702fe5a7SClément Léger * not present 39702fe5a7SClément Léger * @prio: interrupt priority parsed from interrupts properties or 0 if not 40702fe5a7SClément Léger * present 41c0cfb36cSEtienne Carriere */ 42c0cfb36cSEtienne Carriere struct dt_node_info { 43c0cfb36cSEtienne Carriere unsigned int status; 44c0cfb36cSEtienne Carriere paddr_t reg; 45c0cfb36cSEtienne Carriere int clock; 46c0cfb36cSEtienne Carriere int reset; 477acb3a47SLudovic Barre int interrupt; 48702fe5a7SClément Léger uint32_t type; 49702fe5a7SClément Léger uint32_t prio; 50c0cfb36cSEtienne Carriere }; 51c0cfb36cSEtienne Carriere 52a4f139d7SJerome Forissier #if defined(CFG_DT) 53a4f139d7SJerome Forissier 54a4f139d7SJerome Forissier /* 55a4f139d7SJerome Forissier * DT-aware drivers 56a4f139d7SJerome Forissier */ 57a4f139d7SJerome Forissier 58a4f139d7SJerome Forissier struct dt_device_match { 59a4f139d7SJerome Forissier const char *compatible; 607e6a39feSEtienne Carriere const void *compat_data; 61a4f139d7SJerome Forissier }; 62a4f139d7SJerome Forissier 635e588771SClément Léger enum dt_driver_type { 645e588771SClément Léger DT_DRIVER_NOTYPE, 655e588771SClément Léger DT_DRIVER_UART, 662305544bSClément Léger DT_DRIVER_CLK, 675e588771SClément Léger }; 685e588771SClément Léger 69a4f139d7SJerome Forissier struct dt_driver { 70a4f139d7SJerome Forissier const char *name; 715e588771SClément Léger enum dt_driver_type type; 72a4f139d7SJerome Forissier const struct dt_device_match *match_table; /* null-terminated */ 73a4f139d7SJerome Forissier const void *driver; 74a4f139d7SJerome Forissier }; 75a4f139d7SJerome Forissier 76fd118772SJerome Forissier #define __dt_driver __section(".rodata.dtdrv" __SECTION_FLAGS_RODATA) 77a4f139d7SJerome Forissier 78a4f139d7SJerome Forissier /* 79a4f139d7SJerome Forissier * Find a driver that is suitable for the given DT node, that is, with 80a4f139d7SJerome Forissier * a matching "compatible" property. 81a4f139d7SJerome Forissier * 82a4f139d7SJerome Forissier * @fdt: pointer to the device tree 83a4f139d7SJerome Forissier * @offs: node offset 84a4f139d7SJerome Forissier */ 85a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 86a4f139d7SJerome Forissier 87a4f139d7SJerome Forissier const struct dt_driver *__dt_driver_start(void); 88a4f139d7SJerome Forissier 89a4f139d7SJerome Forissier const struct dt_driver *__dt_driver_end(void); 90a4f139d7SJerome Forissier 919fe4c797SJerome Forissier /* 927ba16abbSJerome Forissier * Map a device into secure or non-secure memory and return the base VA and 937ba16abbSJerome Forissier * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 947ba16abbSJerome Forissier * MEM_AREA_IO_NSEC, depending on the device status. 957ba16abbSJerome Forissier * If the mapping already exists, the function simply returns the @vbase and 967ba16abbSJerome Forissier * @size information. 977ba16abbSJerome Forissier * 987ba16abbSJerome Forissier * @offs is the offset of the node that describes the device in @fdt. 997ba16abbSJerome Forissier * @base receives the base virtual address corresponding to the base physical 1007ba16abbSJerome Forissier * address of the "reg" property 1017ba16abbSJerome Forissier * @size receives the size of the mapping 1027ba16abbSJerome Forissier * 1037ba16abbSJerome Forissier * Returns 0 on success or -1 in case of error. 1047ba16abbSJerome Forissier */ 1057ba16abbSJerome Forissier int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size); 1067ba16abbSJerome Forissier 1077ba16abbSJerome Forissier /* 10850f3b323SPeng Fan * Check whether the node at @offs contains the property with propname or not. 10950f3b323SPeng Fan * 11050f3b323SPeng Fan * @offs is the offset of the node that describes the device in @fdt. 11150f3b323SPeng Fan * @propname is the property that need to check 11250f3b323SPeng Fan * 11350f3b323SPeng Fan * Returns true on success or false if no propname. 11450f3b323SPeng Fan */ 11550f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname); 11650f3b323SPeng Fan 11750f3b323SPeng Fan /* 11895cdc5e0SCedric Neveux * Modify or add "status" property to "disabled" 11995cdc5e0SCedric Neveux * 12095cdc5e0SCedric Neveux * @fdt reference to the Device Tree 12195cdc5e0SCedric Neveux * @node is the node offset to modify 12295cdc5e0SCedric Neveux * 12395cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 12495cdc5e0SCedric Neveux */ 12595cdc5e0SCedric Neveux int dt_disable_status(void *fdt, int node); 12695cdc5e0SCedric Neveux 12795cdc5e0SCedric Neveux /* 12895cdc5e0SCedric Neveux * Force secure-status = "okay" and status="disabled" for the target node. 12995cdc5e0SCedric Neveux * 13095cdc5e0SCedric Neveux * @fdt reference to the Device Tree 13195cdc5e0SCedric Neveux * @node is the node offset to modify 13295cdc5e0SCedric Neveux * 13395cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 13495cdc5e0SCedric Neveux */ 13595cdc5e0SCedric Neveux int dt_enable_secure_status(void *fdt, int node); 13695cdc5e0SCedric Neveux 13795cdc5e0SCedric Neveux /* 1389fe4c797SJerome Forissier * FDT manipulation functions, not provided by <libfdt.h> 1399fe4c797SJerome Forissier */ 1409fe4c797SJerome Forissier 1419fe4c797SJerome Forissier /* 1429fe4c797SJerome Forissier * Return the base address for the "reg" property of the specified node or 1439fe4c797SJerome Forissier * (paddr_t)-1 in case of error 1449fe4c797SJerome Forissier */ 1459fe4c797SJerome Forissier paddr_t _fdt_reg_base_address(const void *fdt, int offs); 1469fe4c797SJerome Forissier 1479fe4c797SJerome Forissier /* 1489fe4c797SJerome Forissier * Return the reg size for the reg property of the specified node or -1 in case 1499fe4c797SJerome Forissier * of error 1509fe4c797SJerome Forissier */ 151*df7cecc0SLionel Debieve size_t _fdt_reg_size(const void *fdt, int offs); 1529fe4c797SJerome Forissier 1539fe4c797SJerome Forissier /* 1549fe4c797SJerome Forissier * Read the status and secure-status properties into a bitfield. 1559fe4c797SJerome Forissier * @status is set to DT_STATUS_DISABLED or a combination of DT_STATUS_OK_NSEC 15684c93d58SEtienne Carriere * and DT_STATUS_OK_SEC. 1579fe4c797SJerome Forissier */ 1589fe4c797SJerome Forissier int _fdt_get_status(const void *fdt, int offs); 1599fe4c797SJerome Forissier 160c0cfb36cSEtienne Carriere /* 161c0cfb36cSEtienne Carriere * fdt_fill_device_info - Get generic device info from a node 162c0cfb36cSEtienne Carriere * 163c0cfb36cSEtienne Carriere * This function fills the generic information from a given node. 164c0cfb36cSEtienne Carriere * Currently supports a single base register, a single clock, 165c0cfb36cSEtienne Carriere * a single reset ID line and a single interrupt ID. 166c0cfb36cSEtienne Carriere * Default DT_INFO_* macros are used when the relate property is not found. 167c0cfb36cSEtienne Carriere */ 168df45c114SEtienne Carriere void _fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 169df45c114SEtienne Carriere int node); 170c0cfb36cSEtienne Carriere 1719fe4c797SJerome Forissier #else /* !CFG_DT */ 172a4f139d7SJerome Forissier 173a4f139d7SJerome Forissier static inline const struct dt_driver *__dt_driver_start(void) 174a4f139d7SJerome Forissier { 175a4f139d7SJerome Forissier return NULL; 176a4f139d7SJerome Forissier } 177a4f139d7SJerome Forissier 178a4f139d7SJerome Forissier static inline const struct dt_driver *__dt_driver_end(void) 179a4f139d7SJerome Forissier { 180a4f139d7SJerome Forissier return NULL; 181a4f139d7SJerome Forissier } 182a4f139d7SJerome Forissier 183a4f139d7SJerome Forissier static inline const struct dt_driver *dt_find_compatible_driver( 184a4f139d7SJerome Forissier const void *fdt __unused, 185a4f139d7SJerome Forissier int offs __unused) 186a4f139d7SJerome Forissier { 187a4f139d7SJerome Forissier return NULL; 188a4f139d7SJerome Forissier } 189a4f139d7SJerome Forissier 1907ba16abbSJerome Forissier static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 1917ba16abbSJerome Forissier vaddr_t *vbase __unused, size_t *size __unused) 1927ba16abbSJerome Forissier { 1937ba16abbSJerome Forissier return -1; 1947ba16abbSJerome Forissier } 1957ba16abbSJerome Forissier 1969fe4c797SJerome Forissier static inline paddr_t _fdt_reg_base_address(const void *fdt __unused, 1979fe4c797SJerome Forissier int offs __unused) 1989fe4c797SJerome Forissier { 1999fe4c797SJerome Forissier return (paddr_t)-1; 2009fe4c797SJerome Forissier } 2019fe4c797SJerome Forissier 202*df7cecc0SLionel Debieve static inline size_t _fdt_reg_size(const void *fdt __unused, 2039fe4c797SJerome Forissier int offs __unused) 2049fe4c797SJerome Forissier { 205*df7cecc0SLionel Debieve return (size_t)-1; 2069fe4c797SJerome Forissier } 2079fe4c797SJerome Forissier 2089fe4c797SJerome Forissier static inline int _fdt_get_status(const void *fdt __unused, int offs __unused) 2099fe4c797SJerome Forissier { 2109fe4c797SJerome Forissier return -1; 2119fe4c797SJerome Forissier } 2129fe4c797SJerome Forissier 2131e866588SJerome Forissier __noreturn 214df45c114SEtienne Carriere static inline void _fdt_fill_device_info(const void *fdt __unused, 215c0cfb36cSEtienne Carriere struct dt_node_info *info __unused, 216c0cfb36cSEtienne Carriere int node __unused) 217c0cfb36cSEtienne Carriere { 218c0cfb36cSEtienne Carriere panic(); 219c0cfb36cSEtienne Carriere } 220a4f139d7SJerome Forissier #endif /* !CFG_DT */ 221a4f139d7SJerome Forissier 222a4f139d7SJerome Forissier #define for_each_dt_driver(drv) \ 223a4f139d7SJerome Forissier for (drv = __dt_driver_start(); drv < __dt_driver_end(); drv++) 224a4f139d7SJerome Forissier 225a4f139d7SJerome Forissier #endif /* KERNEL_DT_H */ 226