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/panic.h> 11 #include <scattered_array.h> 12 #include <stdint.h> 13 #include <tee_api_types.h> 14 #include <types_ext.h> 15 #include <util.h> 16 17 /* 18 * Bitfield to reflect status and secure-status values ("okay", "disabled" 19 * or not present) 20 */ 21 #define DT_STATUS_DISABLED U(0) 22 #define DT_STATUS_OK_NSEC BIT(0) 23 #define DT_STATUS_OK_SEC BIT(1) 24 25 #define DT_INFO_INVALID_REG ((paddr_t)-1) 26 #define DT_INFO_INVALID_REG_SIZE ((size_t)-1) 27 #define DT_INFO_INVALID_CLOCK -1 28 #define DT_INFO_INVALID_RESET -1 29 #define DT_INFO_INVALID_INTERRUPT -1 30 31 /* 32 * @status: Bit mask for DT_STATUS_* 33 * @reg: Device register physical base address or DT_INFO_INVALID_REG 34 * @reg_size: Device register size or DT_INFO_INVALID_REG_SIZE 35 * @clock: Device identifier (positive value) or DT_INFO_INVALID_CLOCK 36 * @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK 37 * @interrupt: Device interrupt identifier (positive value) or 38 * DT_INFO_INVALID_INTERRUPT 39 * @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if 40 * not present 41 * @prio: interrupt priority parsed from interrupts properties or 0 if not 42 * present 43 */ 44 struct dt_node_info { 45 unsigned int status; 46 paddr_t reg; 47 size_t reg_size; 48 int clock; 49 int reset; 50 int interrupt; 51 uint32_t type; 52 uint32_t prio; 53 }; 54 55 /* 56 * DT-aware drivers 57 */ 58 59 struct dt_device_match { 60 const char *compatible; 61 const void *compat_data; 62 }; 63 64 /* 65 * DT_MAP_AUTO: Uses status properties from device tree to determine mapping. 66 * DT_MAP_SECURE: Force mapping for device to be secure. 67 * DT_MAP_NON_SECURE: Force mapping for device to be non-secure. 68 */ 69 enum dt_map_dev_directive { 70 DT_MAP_AUTO, 71 DT_MAP_SECURE, 72 DT_MAP_NON_SECURE 73 }; 74 75 /* 76 * struct dt_descriptor - Descriptor of the device tree 77 * @blob: Pointer to the device tree binary 78 * @frag_id: Used ID of fragments for device tree overlay 79 */ 80 struct dt_descriptor { 81 void *blob; 82 #ifdef _CFG_USE_DTB_OVERLAY 83 int frag_id; 84 #endif 85 }; 86 87 extern uint8_t embedded_secure_dtb[]; 88 89 #ifdef CFG_DT 90 /* 91 * dt_getprop_as_number() - get a DT property a unsigned number 92 * @fdt: DT base address 93 * @nodeoffset: node offset 94 * @name: property string name 95 * @num: output number read 96 * Return 0 on success and a negative FDT error value on error 97 * 98 * The size of the property determines if it is read as an unsigned 32-bit 99 * or 64-bit integer. 100 */ 101 int dt_getprop_as_number(const void *fdt, int nodeoffset, const char *name, 102 uint64_t *num); 103 104 /* 105 * Find a driver that is suitable for the given DT node, that is, with 106 * a matching "compatible" property. 107 * 108 * @fdt: pointer to the device tree 109 * @offs: node offset 110 */ 111 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 112 113 /* 114 * Map a device into secure or non-secure memory and return the base VA and 115 * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 116 * MEM_AREA_IO_NSEC, depending on the device status. 117 * If the mapping already exists, the function simply returns the @vbase and 118 * @size information. 119 * 120 * @offs is the offset of the node that describes the device in @fdt. 121 * @base receives the base virtual address corresponding to the base physical 122 * address of the "reg" property 123 * @size receives the size of the mapping 124 * @mapping what kind of mapping is done for memory. 125 * 126 * Returns 0 on success or -1 in case of error. 127 */ 128 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size, 129 enum dt_map_dev_directive mapping); 130 131 /* 132 * Check whether the node at @offs contains the property with propname or not. 133 * 134 * @offs is the offset of the node that describes the device in @fdt. 135 * @propname is the property that need to check 136 * 137 * Returns true on success or false if no propname. 138 */ 139 bool dt_have_prop(const void *fdt, int offs, const char *propname); 140 141 /* 142 * Modify or add "status" property to "disabled" 143 * 144 * @fdt reference to the Device Tree 145 * @node is the node offset to modify 146 * 147 * Returns 0 on success or -1 on failure 148 */ 149 int dt_disable_status(void *fdt, int node); 150 151 /* 152 * Force secure-status = "okay" and status="disabled" for the target node. 153 * 154 * @fdt reference to the Device Tree 155 * @node is the node offset to modify 156 * 157 * Returns 0 on success or -1 on failure 158 */ 159 int dt_enable_secure_status(void *fdt, int node); 160 161 /* 162 * FDT manipulation functions, not provided by <libfdt.h> 163 */ 164 165 /* 166 * Return the base address for the "reg" property of the specified node or 167 * (paddr_t)-1 in case of error 168 */ 169 paddr_t fdt_reg_base_address(const void *fdt, int offs); 170 171 /* 172 * Return the reg size for the reg property of the specified node or -1 in case 173 * of error 174 */ 175 size_t fdt_reg_size(const void *fdt, int offs); 176 177 /* 178 * Read the base address and/or reg size for the "reg" property of the 179 * specified node. 180 * @fdt: Reference to the Device Tree 181 * @offs: Offset to the node to read "reg" property from 182 * @base: Pointer to the output base address value, or NULL 183 * @size: Pointer to the output size value, or NULL 184 * Returns 0 on success and a negative FDT error value in case of failure 185 */ 186 int fdt_reg_info(const void *fdt, int offs, paddr_t *base, size_t *size); 187 188 /* 189 * Read the status and secure-status properties into a bitfield. 190 * Return -1 on failure, DT_STATUS_DISABLED if the node is disabled, 191 * otherwise return a combination of DT_STATUS_OK_NSEC and DT_STATUS_OK_SEC. 192 */ 193 int fdt_get_status(const void *fdt, int offs); 194 195 /* 196 * fdt_fill_device_info - Get generic device info from a node 197 * 198 * This function fills the generic information from a given node. 199 * Currently supports a single base register, a single clock, 200 * a single reset ID line and a single interrupt ID. 201 * Default DT_INFO_* macros are used when the relate property is not found. 202 */ 203 void fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 204 int node); 205 /* 206 * Read cells from a given property of the given node. Any number of 32-bit 207 * cells of the property can be read. Returns 0 on success, or a negative 208 * FDT error value otherwise. 209 */ 210 int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name, 211 uint32_t *array, size_t count); 212 213 /* 214 * Read one cell from a given multi-value property of the given node. 215 * Returns 0 on success, or a negative FDT error value otherwise. 216 */ 217 int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name, 218 int index, uint32_t *value); 219 220 /* 221 * Read one cell from a given property of the given node. 222 * Returns 0 on success, or a negative FDT error value otherwise. 223 */ 224 int fdt_read_uint32(const void *fdt, int node, const char *prop_name, 225 uint32_t *value); 226 227 /* 228 * Read one cell from a property of a cell or default to a given value 229 * Returns the 32bit cell value or @dflt_value on failure. 230 */ 231 uint32_t fdt_read_uint32_default(const void *fdt, int node, 232 const char *prop_name, uint32_t dflt_value); 233 234 /* 235 * This function fills reg node info (base & size) with an index. 236 * 237 * Returns 0 on success and a negative FDT error code on failure. 238 */ 239 int fdt_get_reg_props_by_index(const void *fdt, int node, int index, 240 paddr_t *base, size_t *size); 241 242 /* 243 * This function fills reg node info (base & size) with an index found by 244 * checking the reg-names node. 245 * 246 * Returns 0 on success and a negative FDT error code on failure. 247 */ 248 int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name, 249 paddr_t *base, size_t *size); 250 251 /* 252 * Returns embedded DTB if present, then external DTB if found, 253 * then manifest DTB if found, then NULL. 254 */ 255 void *get_dt(void); 256 257 /* 258 * get_secure_dt() - returns secure DTB for drivers 259 * 260 * Returns device tree that is considered secure for drivers to use. 261 * 262 * 1. Returns embedded DTB if available, 263 * 2. Secure external DTB if available, 264 * 3. Manifest DTB if available, 265 * 4. If neither then NULL 266 */ 267 void *get_secure_dt(void); 268 269 /* Returns embedded DTB location if present, otherwise NULL */ 270 void *get_embedded_dt(void); 271 272 /* Returns true if passed DTB is same as Embedded DTB, otherwise false */ 273 static inline bool is_embedded_dt(void *fdt) 274 { 275 return fdt && fdt == get_embedded_dt(); 276 } 277 278 /* Returns DTB descriptor of the external DTB if present, otherwise NULL */ 279 struct dt_descriptor *get_external_dt_desc(void); 280 281 /* 282 * init_external_dt() - Initialize the external DTB located at given address. 283 * @phys_dt: Physical address where the external DTB located. 284 * @dt_sz: Maximum size of the external DTB. 285 * 286 * Initialize the external DTB. 287 * 288 * 1. Add MMU mapping of the external DTB, 289 * 2. Initialize device tree overlay 290 */ 291 void init_external_dt(unsigned long phys_dt, size_t dt_sz); 292 293 /* Returns external DTB if present, otherwise NULL */ 294 void *get_external_dt(void); 295 296 /* 297 * add_dt_path_subnode() - Add new child node into a parent node. 298 * @dt: Pointer to a device tree descriptor which has DTB. 299 * @path: Path to the parent node. 300 * @subnode: Name of the child node. 301 * 302 * Returns the offset of the child node in DTB on success or a negative libfdt 303 * error number. 304 */ 305 int add_dt_path_subnode(struct dt_descriptor *dt, const char *path, 306 const char *subnode); 307 308 /* 309 * add_dt_node_overlay_fragment() - Add an overlay node fragment for a node. 310 * @node: Offset of the node where to add an overlay fragment 311 * 312 * Returns the offset into the __overlay__ child node which can be used 313 * by the caller to add properties on success or a negative libfdt 314 * error number. 315 */ 316 int add_dt_node_overlay_fragment(int node); 317 318 /* 319 * add_res_mem_dt_node() - Create "reserved-memory" parent and child nodes. 320 * @dt: Pointer to a device tree descriptor which has DTB. 321 * @name: Name of the child node. 322 * @pa: Physical address of specific reserved memory region. 323 * @size: Size of specific reserved memory region. 324 * 325 * Returns 0 if succeeds, otherwise a negative libfdt error number. 326 */ 327 int add_res_mem_dt_node(struct dt_descriptor *dt, const char *name, 328 paddr_t pa, size_t size); 329 330 /* 331 * init_manifest_dt() - Initialize the manifest DTB to given address. 332 * @fdt: Physical address where the manifest DTB located. 333 * @max_size: Maximum size of the DTB 334 * 335 * Initialize the manifest DTB to physical address 336 */ 337 void init_manifest_dt(void *fdt, size_t max_size); 338 339 /* 340 * reinit_manifest_dt() - Reinitialize the manifest DTB 341 * 342 * Reserve used physical memory, add MMU mapping of the manifest DTB, and 343 * initialize device tree overlay 344 */ 345 void reinit_manifest_dt(void); 346 347 /* Returns TOS_FW_CONFIG DTB or SP manifest DTB if present, otherwise NULL */ 348 void *get_manifest_dt(void); 349 350 #else /* !CFG_DT */ 351 352 static inline const struct dt_driver *dt_find_compatible_driver( 353 const void *fdt __unused, 354 int offs __unused) 355 { 356 return NULL; 357 } 358 359 static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 360 vaddr_t *vbase __unused, size_t *size __unused, 361 enum dt_map_dev_directive mapping __unused) 362 { 363 return -1; 364 } 365 366 static inline paddr_t fdt_reg_base_address(const void *fdt __unused, 367 int offs __unused) 368 { 369 return (paddr_t)-1; 370 } 371 372 static inline size_t fdt_reg_size(const void *fdt __unused, 373 int offs __unused) 374 { 375 return (size_t)-1; 376 } 377 378 static inline int fdt_reg_info(const void *fdt __unused, int offs __unused, 379 paddr_t *base __unused, size_t *size __unused) 380 { 381 return -1; 382 } 383 384 static inline int fdt_get_status(const void *fdt __unused, int offs __unused) 385 { 386 return -1; 387 } 388 389 __noreturn 390 static inline void fdt_fill_device_info(const void *fdt __unused, 391 struct dt_node_info *info __unused, 392 int node __unused) 393 { 394 panic(); 395 } 396 397 static inline int fdt_read_uint32_array(const void *fdt __unused, 398 int node __unused, 399 const char *prop_name __unused, 400 uint32_t *array __unused, 401 size_t count __unused) 402 { 403 return -1; 404 } 405 406 static inline int fdt_read_uint32(const void *fdt __unused, 407 int node __unused, 408 const char *prop_name __unused, 409 uint32_t *value __unused) 410 { 411 return -1; 412 } 413 414 static inline uint32_t fdt_read_uint32_default(const void *fdt __unused, 415 int node __unused, 416 const char *prop_name __unused, 417 uint32_t dflt_value __unused) 418 { 419 return dflt_value; 420 } 421 422 static inline int fdt_read_uint32_index(const void *fdt __unused, 423 int node __unused, 424 const char *prop_name __unused, 425 int index __unused, 426 uint32_t *value __unused) 427 { 428 return -1; 429 } 430 431 static inline int fdt_get_reg_props_by_index(const void *fdt __unused, 432 int node __unused, 433 int index __unused, 434 paddr_t *base __unused, 435 size_t *size __unused) 436 { 437 return -1; 438 } 439 440 static inline int fdt_get_reg_props_by_name(const void *fdt __unused, 441 int node __unused, 442 const char *name __unused, 443 paddr_t *base __unused, 444 size_t *size __unused) 445 { 446 return -1; 447 } 448 449 static inline int dt_getprop_as_number(const void *fdt __unused, 450 int nodeoffset __unused, 451 const char *name __unused, 452 uint64_t *num __unused) 453 { 454 return -1; 455 } 456 457 static inline void *get_dt(void) 458 { 459 return NULL; 460 } 461 462 static inline void *get_secure_dt(void) 463 { 464 return NULL; 465 } 466 467 static inline void *get_embedded_dt(void) 468 { 469 return NULL; 470 } 471 472 static inline bool is_embedded_dt(void *fdt __unused) 473 { 474 return false; 475 } 476 477 static inline struct dt_descriptor *get_external_dt_desc(void) 478 { 479 return NULL; 480 } 481 482 static inline void init_external_dt(unsigned long phys_dt __unused, 483 size_t dt_sz __unused) 484 { 485 } 486 487 static inline void *get_external_dt(void) 488 { 489 return NULL; 490 } 491 492 static inline int add_dt_path_subnode(struct dt_descriptor *dt __unused, 493 const char *path __unused, 494 const char *subnode __unused) 495 { 496 return -1; 497 } 498 499 static inline int add_dt_node_overlay_fragment(int node __unused) 500 { 501 return -1; 502 } 503 504 static inline int add_res_mem_dt_node(struct dt_descriptor *dt __unused, 505 const char *name __unused, 506 paddr_t pa __unused, 507 size_t size __unused) 508 { 509 return -1; 510 } 511 512 static inline void init_manifest_dt(void *fdt __unused, 513 size_t max_size __unused) 514 { 515 } 516 517 static inline void reinit_manifest_dt(void) 518 { 519 } 520 521 static inline void *get_manifest_dt(void) 522 { 523 return NULL; 524 } 525 526 #endif /* !CFG_DT */ 527 528 #ifdef CFG_DT_CACHED_NODE_INFO 529 /* 530 * Find the offset of a parent node in the parent node cache 531 * @fdt: FDT to work on 532 * @node_offset: Offset of the node we look for its parent 533 * @parent_offset: Output parent node offset upon success 534 * @return 0 on success and -1 on failure 535 */ 536 int fdt_find_cached_parent_node(const void *fdt, int node_offset, 537 int *parent_offset); 538 539 /* 540 * Find the address/size cells value of a parent node in the parent node cache 541 * @fdt: FDT to work on 542 * @node_offset: Offset of the node we look for its parent 543 * @address_cells: Pointer to output #address-cells value upon success or NULL 544 * @size_cells: Pointer to output #size-cells value upon success or NULL 545 * @return 0 on success and -FDT_ERR_NOTFOUND on failure 546 */ 547 int fdt_find_cached_parent_reg_cells(const void *fdt, int node_offset, 548 int *address_cells, int *size_cells); 549 /* 550 * Find the node offset from its phandle in the phandle cache 551 * @fdt: FDT to work on 552 * @phandle: Node phandle 553 * @node_offset: Pointer to output node offset upon success 554 * @return 0 on success and -FDT_ERR_NOTFOUND on failure 555 */ 556 int fdt_find_cached_node_phandle(const void *fdt, uint32_t phandle, 557 int *node_offset); 558 #else 559 static inline int fdt_find_cached_parent_node(const void *fdt __unused, 560 int node_offset __unused, 561 int *parent_offset __unused) 562 { 563 return -1; 564 } 565 566 static inline int fdt_find_cached_parent_reg_cells(const void *fdt __unused, 567 int node_offset __unused, 568 int *address_cells __unused, 569 int *size_cells __unused) 570 { 571 return -1; 572 } 573 574 static inline int fdt_find_cached_node_phandle(const void *fdt __unused, 575 uint32_t phandle __unused, 576 int *node_offset __unused) 577 { 578 return -1; 579 } 580 #endif /* CFG_DT_CACHED_NODE_INFO */ 581 #endif /* __KERNEL_DT_H */ 582