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