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