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> 10*702fe5a7SClé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) 251527e616SMarek Vasut #define DT_INFO_INVALID_REG_SIZE ((ssize_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 37*702fe5a7SClément Léger * @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if 38*702fe5a7SClément Léger * not present 39*702fe5a7SClément Léger * @prio: interrupt priority parsed from interrupts properties or 0 if not 40*702fe5a7SClé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; 48*702fe5a7SClément Léger uint32_t type; 49*702fe5a7SClé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; 60a4f139d7SJerome Forissier }; 61a4f139d7SJerome Forissier 62a4f139d7SJerome Forissier struct dt_driver { 63a4f139d7SJerome Forissier const char *name; 64a4f139d7SJerome Forissier const struct dt_device_match *match_table; /* null-terminated */ 65a4f139d7SJerome Forissier const void *driver; 66a4f139d7SJerome Forissier }; 67a4f139d7SJerome Forissier 68fd118772SJerome Forissier #define __dt_driver __section(".rodata.dtdrv" __SECTION_FLAGS_RODATA) 69a4f139d7SJerome Forissier 70a4f139d7SJerome Forissier /* 71a4f139d7SJerome Forissier * Find a driver that is suitable for the given DT node, that is, with 72a4f139d7SJerome Forissier * a matching "compatible" property. 73a4f139d7SJerome Forissier * 74a4f139d7SJerome Forissier * @fdt: pointer to the device tree 75a4f139d7SJerome Forissier * @offs: node offset 76a4f139d7SJerome Forissier */ 77a4f139d7SJerome Forissier const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 78a4f139d7SJerome Forissier 79a4f139d7SJerome Forissier const struct dt_driver *__dt_driver_start(void); 80a4f139d7SJerome Forissier 81a4f139d7SJerome Forissier const struct dt_driver *__dt_driver_end(void); 82a4f139d7SJerome Forissier 839fe4c797SJerome Forissier /* 847ba16abbSJerome Forissier * Map a device into secure or non-secure memory and return the base VA and 857ba16abbSJerome Forissier * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 867ba16abbSJerome Forissier * MEM_AREA_IO_NSEC, depending on the device status. 877ba16abbSJerome Forissier * If the mapping already exists, the function simply returns the @vbase and 887ba16abbSJerome Forissier * @size information. 897ba16abbSJerome Forissier * 907ba16abbSJerome Forissier * @offs is the offset of the node that describes the device in @fdt. 917ba16abbSJerome Forissier * @base receives the base virtual address corresponding to the base physical 927ba16abbSJerome Forissier * address of the "reg" property 937ba16abbSJerome Forissier * @size receives the size of the mapping 947ba16abbSJerome Forissier * 957ba16abbSJerome Forissier * Returns 0 on success or -1 in case of error. 967ba16abbSJerome Forissier */ 977ba16abbSJerome Forissier int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size); 987ba16abbSJerome Forissier 997ba16abbSJerome Forissier /* 10050f3b323SPeng Fan * Check whether the node at @offs contains the property with propname or not. 10150f3b323SPeng Fan * 10250f3b323SPeng Fan * @offs is the offset of the node that describes the device in @fdt. 10350f3b323SPeng Fan * @propname is the property that need to check 10450f3b323SPeng Fan * 10550f3b323SPeng Fan * Returns true on success or false if no propname. 10650f3b323SPeng Fan */ 10750f3b323SPeng Fan bool dt_have_prop(const void *fdt, int offs, const char *propname); 10850f3b323SPeng Fan 10950f3b323SPeng Fan /* 11095cdc5e0SCedric Neveux * Modify or add "status" property to "disabled" 11195cdc5e0SCedric Neveux * 11295cdc5e0SCedric Neveux * @fdt reference to the Device Tree 11395cdc5e0SCedric Neveux * @node is the node offset to modify 11495cdc5e0SCedric Neveux * 11595cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 11695cdc5e0SCedric Neveux */ 11795cdc5e0SCedric Neveux int dt_disable_status(void *fdt, int node); 11895cdc5e0SCedric Neveux 11995cdc5e0SCedric Neveux /* 12095cdc5e0SCedric Neveux * Force secure-status = "okay" and status="disabled" for the target node. 12195cdc5e0SCedric Neveux * 12295cdc5e0SCedric Neveux * @fdt reference to the Device Tree 12395cdc5e0SCedric Neveux * @node is the node offset to modify 12495cdc5e0SCedric Neveux * 12595cdc5e0SCedric Neveux * Returns 0 on success or -1 on failure 12695cdc5e0SCedric Neveux */ 12795cdc5e0SCedric Neveux int dt_enable_secure_status(void *fdt, int node); 12895cdc5e0SCedric Neveux 12995cdc5e0SCedric Neveux /* 1309fe4c797SJerome Forissier * FDT manipulation functions, not provided by <libfdt.h> 1319fe4c797SJerome Forissier */ 1329fe4c797SJerome Forissier 1339fe4c797SJerome Forissier /* 1349fe4c797SJerome Forissier * Return the base address for the "reg" property of the specified node or 1359fe4c797SJerome Forissier * (paddr_t)-1 in case of error 1369fe4c797SJerome Forissier */ 1379fe4c797SJerome Forissier paddr_t _fdt_reg_base_address(const void *fdt, int offs); 1389fe4c797SJerome Forissier 1399fe4c797SJerome Forissier /* 1409fe4c797SJerome Forissier * Return the reg size for the reg property of the specified node or -1 in case 1419fe4c797SJerome Forissier * of error 1429fe4c797SJerome Forissier */ 1439fe4c797SJerome Forissier ssize_t _fdt_reg_size(const void *fdt, int offs); 1449fe4c797SJerome Forissier 1459fe4c797SJerome Forissier /* 1469fe4c797SJerome Forissier * Read the status and secure-status properties into a bitfield. 1479fe4c797SJerome Forissier * @status is set to DT_STATUS_DISABLED or a combination of DT_STATUS_OK_NSEC 14884c93d58SEtienne Carriere * and DT_STATUS_OK_SEC. 1499fe4c797SJerome Forissier */ 1509fe4c797SJerome Forissier int _fdt_get_status(const void *fdt, int offs); 1519fe4c797SJerome Forissier 152c0cfb36cSEtienne Carriere /* 153c0cfb36cSEtienne Carriere * fdt_fill_device_info - Get generic device info from a node 154c0cfb36cSEtienne Carriere * 155c0cfb36cSEtienne Carriere * This function fills the generic information from a given node. 156c0cfb36cSEtienne Carriere * Currently supports a single base register, a single clock, 157c0cfb36cSEtienne Carriere * a single reset ID line and a single interrupt ID. 158c0cfb36cSEtienne Carriere * Default DT_INFO_* macros are used when the relate property is not found. 159c0cfb36cSEtienne Carriere */ 160df45c114SEtienne Carriere void _fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 161df45c114SEtienne Carriere int node); 162c0cfb36cSEtienne Carriere 1639fe4c797SJerome Forissier #else /* !CFG_DT */ 164a4f139d7SJerome Forissier 165a4f139d7SJerome Forissier static inline const struct dt_driver *__dt_driver_start(void) 166a4f139d7SJerome Forissier { 167a4f139d7SJerome Forissier return NULL; 168a4f139d7SJerome Forissier } 169a4f139d7SJerome Forissier 170a4f139d7SJerome Forissier static inline const struct dt_driver *__dt_driver_end(void) 171a4f139d7SJerome Forissier { 172a4f139d7SJerome Forissier return NULL; 173a4f139d7SJerome Forissier } 174a4f139d7SJerome Forissier 175a4f139d7SJerome Forissier static inline const struct dt_driver *dt_find_compatible_driver( 176a4f139d7SJerome Forissier const void *fdt __unused, 177a4f139d7SJerome Forissier int offs __unused) 178a4f139d7SJerome Forissier { 179a4f139d7SJerome Forissier return NULL; 180a4f139d7SJerome Forissier } 181a4f139d7SJerome Forissier 1827ba16abbSJerome Forissier static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 1837ba16abbSJerome Forissier vaddr_t *vbase __unused, size_t *size __unused) 1847ba16abbSJerome Forissier { 1857ba16abbSJerome Forissier return -1; 1867ba16abbSJerome Forissier } 1877ba16abbSJerome Forissier 1889fe4c797SJerome Forissier static inline paddr_t _fdt_reg_base_address(const void *fdt __unused, 1899fe4c797SJerome Forissier int offs __unused) 1909fe4c797SJerome Forissier { 1919fe4c797SJerome Forissier return (paddr_t)-1; 1929fe4c797SJerome Forissier } 1939fe4c797SJerome Forissier 1949fe4c797SJerome Forissier static inline ssize_t _fdt_reg_size(const void *fdt __unused, 1959fe4c797SJerome Forissier int offs __unused) 1969fe4c797SJerome Forissier { 1979fe4c797SJerome Forissier return -1; 1989fe4c797SJerome Forissier } 1999fe4c797SJerome Forissier 2009fe4c797SJerome Forissier static inline int _fdt_get_status(const void *fdt __unused, int offs __unused) 2019fe4c797SJerome Forissier { 2029fe4c797SJerome Forissier return -1; 2039fe4c797SJerome Forissier } 2049fe4c797SJerome Forissier 2051e866588SJerome Forissier __noreturn 206df45c114SEtienne Carriere static inline void _fdt_fill_device_info(const void *fdt __unused, 207c0cfb36cSEtienne Carriere struct dt_node_info *info __unused, 208c0cfb36cSEtienne Carriere int node __unused) 209c0cfb36cSEtienne Carriere { 210c0cfb36cSEtienne Carriere panic(); 211c0cfb36cSEtienne Carriere } 212a4f139d7SJerome Forissier #endif /* !CFG_DT */ 213a4f139d7SJerome Forissier 214a4f139d7SJerome Forissier #define for_each_dt_driver(drv) \ 215a4f139d7SJerome Forissier for (drv = __dt_driver_start(); drv < __dt_driver_end(); drv++) 216a4f139d7SJerome Forissier 217a4f139d7SJerome Forissier #endif /* KERNEL_DT_H */ 218