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