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 <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 enum dt_driver_type { 65 DT_DRIVER_NOTYPE, 66 DT_DRIVER_UART, 67 DT_DRIVER_CLK, 68 }; 69 70 /* 71 * dt_driver_probe_func - Callback probe function for a driver. 72 * 73 * @fdt: FDT base address 74 * @nodeoffset: Offset of the node in the FDT 75 * @compat_data: Data registered for the compatible that probed the device 76 * 77 * Return TEE_SUCCESS on successful probe, 78 * TEE_ERROR_DEFER_DRIVER_INIT if probe must be deferred 79 * TEE_ERROR_ITEM_NOT_FOUND when no driver matched node's compatible string 80 * Any other TEE_ERROR_* compliant code. 81 */ 82 typedef TEE_Result (*dt_driver_probe_func)(const void *fdt, int nodeoffset, 83 const void *compat_data); 84 85 #if defined(CFG_DT) 86 /* 87 * Driver instance registered to be probed on compatible node found in the DT. 88 * 89 * @name: Driver name 90 * @type: Drive type 91 * @match_table: Compatible matching identifiers, null terminated 92 * @driver: Driver private reference or NULL 93 * @probe: Probe callback (see dt_driver_probe_func) or NULL 94 */ 95 struct dt_driver { 96 const char *name; 97 enum dt_driver_type type; 98 const struct dt_device_match *match_table; /* null-terminated */ 99 const void *driver; 100 TEE_Result (*probe)(const void *fdt, int node, const void *compat_data); 101 }; 102 103 #define __dt_driver __section(".rodata.dtdrv" __SECTION_FLAGS_RODATA) 104 105 /* 106 * Find a driver that is suitable for the given DT node, that is, with 107 * a matching "compatible" property. 108 * 109 * @fdt: pointer to the device tree 110 * @offs: node offset 111 */ 112 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs); 113 114 const struct dt_driver *__dt_driver_start(void); 115 116 const struct dt_driver *__dt_driver_end(void); 117 118 /* 119 * Map a device into secure or non-secure memory and return the base VA and 120 * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or 121 * MEM_AREA_IO_NSEC, depending on the device status. 122 * If the mapping already exists, the function simply returns the @vbase and 123 * @size information. 124 * 125 * @offs is the offset of the node that describes the device in @fdt. 126 * @base receives the base virtual address corresponding to the base physical 127 * address of the "reg" property 128 * @size receives the size of the mapping 129 * 130 * Returns 0 on success or -1 in case of error. 131 */ 132 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size); 133 134 /* 135 * Check whether the node at @offs contains the property with propname or not. 136 * 137 * @offs is the offset of the node that describes the device in @fdt. 138 * @propname is the property that need to check 139 * 140 * Returns true on success or false if no propname. 141 */ 142 bool dt_have_prop(const void *fdt, int offs, const char *propname); 143 144 /* 145 * Modify or add "status" property to "disabled" 146 * 147 * @fdt reference to the Device Tree 148 * @node is the node offset to modify 149 * 150 * Returns 0 on success or -1 on failure 151 */ 152 int dt_disable_status(void *fdt, int node); 153 154 /* 155 * Force secure-status = "okay" and status="disabled" for the target node. 156 * 157 * @fdt reference to the Device Tree 158 * @node is the node offset to modify 159 * 160 * Returns 0 on success or -1 on failure 161 */ 162 int dt_enable_secure_status(void *fdt, int node); 163 164 /* 165 * FDT manipulation functions, not provided by <libfdt.h> 166 */ 167 168 /* 169 * Return the base address for the "reg" property of the specified node or 170 * (paddr_t)-1 in case of error 171 */ 172 paddr_t _fdt_reg_base_address(const void *fdt, int offs); 173 174 /* 175 * Return the reg size for the reg property of the specified node or -1 in case 176 * of error 177 */ 178 size_t _fdt_reg_size(const void *fdt, int offs); 179 180 /* 181 * Read the status and secure-status properties into a bitfield. 182 * Return -1 on failure, DT_STATUS_DISABLED if the node is disabled, 183 * otherwise return a combination of DT_STATUS_OK_NSEC and DT_STATUS_OK_SEC. 184 */ 185 int _fdt_get_status(const void *fdt, int offs); 186 187 /* 188 * fdt_fill_device_info - Get generic device info from a node 189 * 190 * This function fills the generic information from a given node. 191 * Currently supports a single base register, a single clock, 192 * a single reset ID line and a single interrupt ID. 193 * Default DT_INFO_* macros are used when the relate property is not found. 194 */ 195 void _fdt_fill_device_info(const void *fdt, struct dt_node_info *info, 196 int node); 197 198 #else /* !CFG_DT */ 199 200 static inline const struct dt_driver *__dt_driver_start(void) 201 { 202 return NULL; 203 } 204 205 static inline const struct dt_driver *__dt_driver_end(void) 206 { 207 return NULL; 208 } 209 210 static inline const struct dt_driver *dt_find_compatible_driver( 211 const void *fdt __unused, 212 int offs __unused) 213 { 214 return NULL; 215 } 216 217 static inline int dt_map_dev(const void *fdt __unused, int offs __unused, 218 vaddr_t *vbase __unused, size_t *size __unused) 219 { 220 return -1; 221 } 222 223 static inline paddr_t _fdt_reg_base_address(const void *fdt __unused, 224 int offs __unused) 225 { 226 return (paddr_t)-1; 227 } 228 229 static inline size_t _fdt_reg_size(const void *fdt __unused, 230 int offs __unused) 231 { 232 return (size_t)-1; 233 } 234 235 static inline int _fdt_get_status(const void *fdt __unused, int offs __unused) 236 { 237 return -1; 238 } 239 240 __noreturn 241 static inline void _fdt_fill_device_info(const void *fdt __unused, 242 struct dt_node_info *info __unused, 243 int node __unused) 244 { 245 panic(); 246 } 247 #endif /* !CFG_DT */ 248 249 #define for_each_dt_driver(drv) \ 250 for (drv = __dt_driver_start(); drv < __dt_driver_end(); drv++) 251 252 #endif /* KERNEL_DT_H */ 253