1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Copyright (c) 2016-2021, 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 <scattered_array.h> 13 #include <stdint.h> 14 #include <tee_api_types.h> 15 #include <types_ext.h> 16 #include <util.h> 17 18 /* 19 * Bitfield to reflect status and secure-status values ("okay", "disabled" 20 * or not present) 21 */ 22 #define DT_STATUS_DISABLED U(0) 23 #define DT_STATUS_OK_NSEC BIT(0) 24 #define DT_STATUS_OK_SEC BIT(1) 25 26 #define DT_INFO_INVALID_REG ((paddr_t)-1) 27 #define DT_INFO_INVALID_REG_SIZE ((size_t)-1) 28 #define DT_INFO_INVALID_CLOCK -1 29 #define DT_INFO_INVALID_RESET -1 30 #define DT_INFO_INVALID_INTERRUPT -1 31 32 /* 33 * @status: Bit mask for DT_STATUS_* 34 * @reg: Device register physical base address or DT_INFO_INVALID_REG 35 * @reg_size: Device register size or DT_INFO_INVALID_REG_SIZE 36 * @clock: Device identifier (positive value) or DT_INFO_INVALID_CLOCK 37 * @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK 38 * @interrupt: Device interrupt identifier (positive value) or 39 * DT_INFO_INVALID_INTERRUPT 40 * @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if 41 * not present 42 * @prio: interrupt priority parsed from interrupts properties or 0 if not 43 * present 44 */ 45 struct dt_node_info { 46 unsigned int status; 47 paddr_t reg; 48 size_t reg_size; 49 int clock; 50 int reset; 51 int interrupt; 52 uint32_t type; 53 uint32_t prio; 54 }; 55 56 /* 57 * DT-aware drivers 58 */ 59 60 struct dt_device_match { 61 const char *compatible; 62 const void *compat_data; 63 }; 64 65 enum dt_driver_type { 66 DT_DRIVER_NOTYPE, 67 DT_DRIVER_UART, 68 DT_DRIVER_CLK, 69 DT_DRIVER_RSTCTRL, 70 DT_DRIVER_I2C, 71 }; 72 73 /* 74 * DT_MAP_AUTO: Uses status properties from device tree to determine mapping. 75 * DT_MAP_SECURE: Force mapping for device to be secure. 76 * DT_MAP_NON_SECURE: Force mapping for device to be non-secure. 77 */ 78 enum dt_map_dev_directive { 79 DT_MAP_AUTO, 80 DT_MAP_SECURE, 81 DT_MAP_NON_SECURE 82 }; 83 84 /* 85 * dt_driver_probe_func - Callback probe function for a driver. 86 * 87 * @fdt: FDT base address 88 * @nodeoffset: Offset of the node in the FDT 89 * @compat_data: Data registered for the compatible that probed the device 90 * 91 * Return TEE_SUCCESS on successful probe, 92 * TEE_ERROR_DEFER_DRIVER_INIT if probe must be deferred 93 * TEE_ERROR_ITEM_NOT_FOUND when no driver matched node's compatible string 94 * Any other TEE_ERROR_* compliant code. 95 */ 96 typedef TEE_Result (*dt_driver_probe_func)(const void *fdt, int nodeoffset, 97 const void *compat_data); 98 99 #if defined(CFG_DT) 100 /* 101 * Driver instance registered to be probed on compatible node found in the DT. 102 * 103 * @name: Driver name 104 * @type: Drive type 105 * @match_table: Compatible matching identifiers, null terminated 106 * @driver: Driver private reference or NULL 107 * @probe: Probe callback (see dt_driver_probe_func) or NULL 108 */ 109 struct dt_driver { 110 const char *name; 111 enum dt_driver_type type; 112 const struct dt_device_match *match_table; /* null-terminated */ 113 const void *driver; 114 TEE_Result (*probe)(const void *fdt, int node, const void *compat_data); 115 }; 116 117 #define DEFINE_DT_DRIVER(name) \ 118 SCATTERED_ARRAY_DEFINE_PG_ITEM(dt_drivers, struct dt_driver) 119 120 /* 121 * Find a driver that is suitable for the given DT node, that is, with 122 * a matching "compatible" property. 123 * 124 * @fdt: pointer to the device tree 125 * @offs: node offset 126 */ 127 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 128 129 /* 130 * Map a device into secure or non-secure memory and return the base VA and 131 * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 132 * MEM_AREA_IO_NSEC, depending on the device status. 133 * If the mapping already exists, the function simply returns the @vbase and 134 * @size information. 135 * 136 * @offs is the offset of the node that describes the device in @fdt. 137 * @base receives the base virtual address corresponding to the base physical 138 * address of the "reg" property 139 * @size receives the size of the mapping 140 * @mapping what kind of mapping is done for memory. 141 * 142 * Returns 0 on success or -1 in case of error. 143 */ 144 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size, 145 enum dt_map_dev_directive mapping); 146 147 /* 148 * Check whether the node at @offs contains the property with propname or not. 149 * 150 * @offs is the offset of the node that describes the device in @fdt. 151 * @propname is the property that need to check 152 * 153 * Returns true on success or false if no propname. 154 */ 155 bool dt_have_prop(const void *fdt, int offs, const char *propname); 156 157 /* 158 * Modify or add "status" property to "disabled" 159 * 160 * @fdt reference to the Device Tree 161 * @node is the node offset to modify 162 * 163 * Returns 0 on success or -1 on failure 164 */ 165 int dt_disable_status(void *fdt, int node); 166 167 /* 168 * Force secure-status = "okay" and status="disabled" for the target node. 169 * 170 * @fdt reference to the Device Tree 171 * @node is the node offset to modify 172 * 173 * Returns 0 on success or -1 on failure 174 */ 175 int dt_enable_secure_status(void *fdt, int node); 176 177 /* 178 * FDT manipulation functions, not provided by <libfdt.h> 179 */ 180 181 /* 182 * Return the base address for the "reg" property of the specified node or 183 * (paddr_t)-1 in case of error 184 */ 185 paddr_t fdt_reg_base_address(const void *fdt, int offs); 186 187 /* 188 * Return the reg size for the reg property of the specified node or -1 in case 189 * of error 190 */ 191 size_t fdt_reg_size(const void *fdt, int offs); 192 193 /* 194 * Read the status and secure-status properties into a bitfield. 195 * Return -1 on failure, DT_STATUS_DISABLED if the node is disabled, 196 * otherwise return a combination of DT_STATUS_OK_NSEC and DT_STATUS_OK_SEC. 197 */ 198 int fdt_get_status(const void *fdt, int offs); 199 200 /* 201 * fdt_fill_device_info - Get generic device info from a node 202 * 203 * This function fills the generic information from a given node. 204 * Currently supports a single base register, a single clock, 205 * a single reset ID line and a single interrupt ID. 206 * Default DT_INFO_* macros are used when the relate property is not found. 207 */ 208 void fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 209 int node); 210 /* 211 * Read cells from a given property of the given node. Any number of 32-bit 212 * cells of the property can be read. Returns 0 on success, or a negative 213 * FDT error value otherwise. 214 */ 215 int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name, 216 uint32_t *array, size_t count); 217 218 /* 219 * Read one cell from a given multi-value property of the given node. 220 * Returns 0 on success, or a negative FDT error value otherwise. 221 */ 222 int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name, 223 int index, uint32_t *value); 224 225 /* 226 * Read one cell from a given property of the given node. 227 * Returns 0 on success, or a negative FDT error value otherwise. 228 */ 229 int fdt_read_uint32(const void *fdt, int node, const char *prop_name, 230 uint32_t *value); 231 232 /* 233 * Read one cell from a property of a cell or default to a given value 234 * Returns the 32bit cell value or @dflt_value on failure. 235 */ 236 uint32_t fdt_read_uint32_default(const void *fdt, int node, 237 const char *prop_name, uint32_t dflt_value); 238 239 /* 240 * Check whether the node at @node has a reference name. 241 * 242 * @node is the offset of the node that describes the device in @fdt. 243 * 244 * Returns true on success or false if no property 245 */ 246 bool fdt_check_node(const void *fdt, int node); 247 248 /* 249 * This function fills reg node info (base & size) with an index. 250 * 251 * Returns 0 on success and a negative FDT error code on failure. 252 */ 253 int fdt_get_reg_props_by_index(const void *fdt, int node, int index, 254 paddr_t *base, size_t *size); 255 256 /* 257 * This function fills reg node info (base & size) with an index found by 258 * checking the reg-names node. 259 * 260 * Returns 0 on success and a negative FDT error code on failure. 261 */ 262 int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name, 263 paddr_t *base, size_t *size); 264 265 #else /* !CFG_DT */ 266 267 static inline const struct dt_driver *dt_find_compatible_driver( 268 const void *fdt __unused, 269 int offs __unused) 270 { 271 return NULL; 272 } 273 274 static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 275 vaddr_t *vbase __unused, size_t *size __unused, 276 enum dt_map_dev_directive mapping __unused) 277 { 278 return -1; 279 } 280 281 static inline paddr_t fdt_reg_base_address(const void *fdt __unused, 282 int offs __unused) 283 { 284 return (paddr_t)-1; 285 } 286 287 static inline size_t fdt_reg_size(const void *fdt __unused, 288 int offs __unused) 289 { 290 return (size_t)-1; 291 } 292 293 static inline int fdt_get_status(const void *fdt __unused, int offs __unused) 294 { 295 return -1; 296 } 297 298 __noreturn 299 static inline void fdt_fill_device_info(const void *fdt __unused, 300 struct dt_node_info *info __unused, 301 int node __unused) 302 { 303 panic(); 304 } 305 306 static inline int fdt_read_uint32_array(const void *fdt __unused, 307 int node __unused, 308 const char *prop_name __unused, 309 uint32_t *array __unused, 310 size_t count __unused) 311 { 312 return -1; 313 } 314 315 static inline int fdt_read_uint32(const void *fdt __unused, 316 int node __unused, 317 const char *prop_name __unused, 318 uint32_t *value __unused) 319 { 320 return -1; 321 } 322 323 static inline uint32_t fdt_read_uint32_default(const void *fdt __unused, 324 int node __unused, 325 const char *prop_name __unused, 326 uint32_t dflt_value __unused) 327 { 328 return dflt_value; 329 } 330 331 static inline int fdt_read_uint32_index(const void *fdt __unused, 332 int node __unused, 333 const char *prop_name __unused, 334 int index __unused, 335 uint32_t *value __unused) 336 { 337 return -1; 338 } 339 340 static inline int fdt_get_reg_props_by_index(const void *fdt __unused, 341 int node __unused, 342 int index __unused, 343 paddr_t *base __unused, 344 size_t *size __unused) 345 { 346 return -1; 347 } 348 349 static inline int fdt_get_reg_props_by_name(const void *fdt __unused, 350 int node __unused, 351 const char *name __unused, 352 paddr_t *base __unused, 353 size_t *size __unused) 354 { 355 return -1; 356 } 357 358 #endif /* !CFG_DT */ 359 360 #define for_each_dt_driver(drv) \ 361 for (drv = SCATTERED_ARRAY_BEGIN(dt_drivers, struct dt_driver); \ 362 drv < SCATTERED_ARRAY_END(dt_drivers, struct dt_driver); \ 363 drv++) 364 365 #endif /* KERNEL_DT_H */ 366