1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Copyright (c) 2016, Linaro Limited 4 */ 5 6 #ifndef KERNEL_DT_H 7 #define KERNEL_DT_H 8 9 #include <compiler.h> 10 #include <kernel/interrupt.h> 11 #include <kernel/panic.h> 12 #include <stdint.h> 13 #include <types_ext.h> 14 #include <util.h> 15 16 /* 17 * Bitfield to reflect status and secure-status values ("okay", "disabled" 18 * or not present) 19 */ 20 #define DT_STATUS_DISABLED U(0) 21 #define DT_STATUS_OK_NSEC BIT(0) 22 #define DT_STATUS_OK_SEC BIT(1) 23 24 #define DT_INFO_INVALID_REG ((paddr_t)-1) 25 #define DT_INFO_INVALID_REG_SIZE ((ssize_t)-1) 26 #define DT_INFO_INVALID_CLOCK -1 27 #define DT_INFO_INVALID_RESET -1 28 #define DT_INFO_INVALID_INTERRUPT -1 29 30 /* 31 * @status: Bit mask for DT_STATUS_* 32 * @reg: Device register physical base address or DT_INFO_INVALID_REG 33 * @clock: Device identifier (positive value) or DT_INFO_INVALID_CLOCK 34 * @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK 35 * @interrupt: Device interrupt identifier (positive value) or 36 * DT_INFO_INVALID_INTERRUPT 37 * @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if 38 * not present 39 * @prio: interrupt priority parsed from interrupts properties or 0 if not 40 * present 41 */ 42 struct dt_node_info { 43 unsigned int status; 44 paddr_t reg; 45 int clock; 46 int reset; 47 int interrupt; 48 uint32_t type; 49 uint32_t prio; 50 }; 51 52 #if defined(CFG_DT) 53 54 /* 55 * DT-aware drivers 56 */ 57 58 struct dt_device_match { 59 const char *compatible; 60 }; 61 62 enum dt_driver_type { 63 DT_DRIVER_NOTYPE, 64 DT_DRIVER_UART, 65 DT_DRIVER_CLK, 66 }; 67 68 struct dt_driver { 69 const char *name; 70 enum dt_driver_type type; 71 const struct dt_device_match *match_table; /* null-terminated */ 72 const void *driver; 73 }; 74 75 #define __dt_driver __section(".rodata.dtdrv" __SECTION_FLAGS_RODATA) 76 77 /* 78 * Find a driver that is suitable for the given DT node, that is, with 79 * a matching "compatible" property. 80 * 81 * @fdt: pointer to the device tree 82 * @offs: node offset 83 */ 84 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 85 86 const struct dt_driver *__dt_driver_start(void); 87 88 const struct dt_driver *__dt_driver_end(void); 89 90 /* 91 * Map a device into secure or non-secure memory and return the base VA and 92 * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 93 * MEM_AREA_IO_NSEC, depending on the device status. 94 * If the mapping already exists, the function simply returns the @vbase and 95 * @size information. 96 * 97 * @offs is the offset of the node that describes the device in @fdt. 98 * @base receives the base virtual address corresponding to the base physical 99 * address of the "reg" property 100 * @size receives the size of the mapping 101 * 102 * Returns 0 on success or -1 in case of error. 103 */ 104 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size); 105 106 /* 107 * Check whether the node at @offs contains the property with propname or not. 108 * 109 * @offs is the offset of the node that describes the device in @fdt. 110 * @propname is the property that need to check 111 * 112 * Returns true on success or false if no propname. 113 */ 114 bool dt_have_prop(const void *fdt, int offs, const char *propname); 115 116 /* 117 * Modify or add "status" property to "disabled" 118 * 119 * @fdt reference to the Device Tree 120 * @node is the node offset to modify 121 * 122 * Returns 0 on success or -1 on failure 123 */ 124 int dt_disable_status(void *fdt, int node); 125 126 /* 127 * Force secure-status = "okay" and status="disabled" for the target node. 128 * 129 * @fdt reference to the Device Tree 130 * @node is the node offset to modify 131 * 132 * Returns 0 on success or -1 on failure 133 */ 134 int dt_enable_secure_status(void *fdt, int node); 135 136 /* 137 * FDT manipulation functions, not provided by <libfdt.h> 138 */ 139 140 /* 141 * Return the base address for the "reg" property of the specified node or 142 * (paddr_t)-1 in case of error 143 */ 144 paddr_t _fdt_reg_base_address(const void *fdt, int offs); 145 146 /* 147 * Return the reg size for the reg property of the specified node or -1 in case 148 * of error 149 */ 150 ssize_t _fdt_reg_size(const void *fdt, int offs); 151 152 /* 153 * Read the status and secure-status properties into a bitfield. 154 * @status is set to DT_STATUS_DISABLED or a combination of DT_STATUS_OK_NSEC 155 * and DT_STATUS_OK_SEC. 156 */ 157 int _fdt_get_status(const void *fdt, int offs); 158 159 /* 160 * fdt_fill_device_info - Get generic device info from a node 161 * 162 * This function fills the generic information from a given node. 163 * Currently supports a single base register, a single clock, 164 * a single reset ID line and a single interrupt ID. 165 * Default DT_INFO_* macros are used when the relate property is not found. 166 */ 167 void _fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 168 int node); 169 170 #else /* !CFG_DT */ 171 172 static inline const struct dt_driver *__dt_driver_start(void) 173 { 174 return NULL; 175 } 176 177 static inline const struct dt_driver *__dt_driver_end(void) 178 { 179 return NULL; 180 } 181 182 static inline const struct dt_driver *dt_find_compatible_driver( 183 const void *fdt __unused, 184 int offs __unused) 185 { 186 return NULL; 187 } 188 189 static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 190 vaddr_t *vbase __unused, size_t *size __unused) 191 { 192 return -1; 193 } 194 195 static inline paddr_t _fdt_reg_base_address(const void *fdt __unused, 196 int offs __unused) 197 { 198 return (paddr_t)-1; 199 } 200 201 static inline ssize_t _fdt_reg_size(const void *fdt __unused, 202 int offs __unused) 203 { 204 return -1; 205 } 206 207 static inline int _fdt_get_status(const void *fdt __unused, int offs __unused) 208 { 209 return -1; 210 } 211 212 __noreturn 213 static inline void _fdt_fill_device_info(const void *fdt __unused, 214 struct dt_node_info *info __unused, 215 int node __unused) 216 { 217 panic(); 218 } 219 #endif /* !CFG_DT */ 220 221 #define for_each_dt_driver(drv) \ 222 for (drv = __dt_driver_start(); drv < __dt_driver_end(); drv++) 223 224 #endif /* KERNEL_DT_H */ 225