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