Angel Pons | 3ef916f | 2020-04-02 23:49:13 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 2 | |
| 3 | #include <cbfs.h> |
| 4 | #include <string.h> |
| 5 | #include <console/console.h> |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 6 | #include <device/mmio.h> |
Elyes HAOUAS | 5fd93e0 | 2019-05-15 21:07:30 +0200 | [diff] [blame] | 7 | #include <types.h> |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 8 | |
Elyes HAOUAS | 5fd93e0 | 2019-05-15 21:07:30 +0200 | [diff] [blame] | 9 | #include "hwilib.h" |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 10 | |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 11 | #define MAX_BLOCK_NUM 4 |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 12 | #define LEN_HIB 0x1fd |
| 13 | #define LEN_SIB 0x121 |
| 14 | #define LEN_EIB 0x0b5 |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 15 | #define MIN_LEN_XIB 0x201 |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 16 | #define NEXT_OFFSET_HIB 0x1dc |
| 17 | #define NEXT_OFFSET_SIB 0x104 |
| 18 | #define NEXT_OFFSET_EIB 0x0b0 |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 19 | #define NEXT_OFFSET_XIB 0x014 |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 20 | #define LEN_UNIQUEL_NUM 0x010 |
| 21 | #define LEN_HW_REV 0x002 |
| 22 | #define LEN_MAC_ADDRESS 0x006 |
| 23 | #define LEN_SPD 0x080 |
| 24 | #define LEN_EDID 0x080 |
| 25 | #define LEN_OFFSET 0x00c |
| 26 | #define EIB_FEATRUE_OFFSET 0x00e |
| 27 | #define LEN_MAGIC_NUM 0x007 |
| 28 | #define BLOCK_MAGIC "H1W2M3I" |
Werner Zeh | d35a481 | 2019-02-20 06:38:04 +0100 | [diff] [blame] | 29 | #define HWI_MAX_NAME_LEN 32 |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 30 | |
| 31 | /* Define all supported block types. */ |
| 32 | enum { |
| 33 | BLK_HIB, |
| 34 | BLK_SIB, |
| 35 | BLK_EIB, |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 36 | BLK_XIB |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 37 | }; |
| 38 | |
| 39 | /* This structure holds a valid position for a given field |
| 40 | * Every field can have multiple positions of which the first available |
| 41 | * will be taken by the library. |
| 42 | */ |
| 43 | struct param_pos { |
| 44 | uint8_t blk_type; /* Valid for a specific block type */ |
| 45 | uint32_t offset; /* Offset in given block */ |
| 46 | uint32_t len; /* Length for the field in this block */ |
| 47 | }; |
| 48 | |
| 49 | /* This structure holds all the needed information for a given field type |
| 50 | * and a pointer to a function which is able to extract the desired data. |
| 51 | */ |
| 52 | struct param_info { |
| 53 | struct param_pos pos[MAX_BLOCK_NUM]; |
| 54 | uint64_t mask; |
| 55 | uint8_t mask_offset; |
| 56 | uint32_t (*get_field)(const struct param_info *param, uint8_t *dst, |
| 57 | uint32_t maxlen); |
| 58 | }; |
| 59 | |
| 60 | /* Storage for pointers to the different blocks. The contents will be filled |
| 61 | * in hwilib_find_blocks(). |
| 62 | */ |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 63 | static uint8_t *all_blocks[MAX_BLOCK_NUM]; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 64 | |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 65 | /* As the length of extended block is variable, save all length to a global |
| 66 | * variable so that they can be used later to check boundaries. |
| 67 | */ |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 68 | static uint16_t all_blk_size[MAX_BLOCK_NUM]; |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 69 | |
Werner Zeh | d35a481 | 2019-02-20 06:38:04 +0100 | [diff] [blame] | 70 | /* Storage for the cbfs file name of the currently open hwi file. */ |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 71 | static char current_hwi[HWI_MAX_NAME_LEN]; |
Werner Zeh | d35a481 | 2019-02-20 06:38:04 +0100 | [diff] [blame] | 72 | |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 73 | |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 74 | static uint32_t hwilib_read_bytes (const struct param_info *param, uint8_t *dst, |
| 75 | uint32_t maxlen); |
| 76 | |
| 77 | /* Add all supported fields to this variable. It is important to use the |
| 78 | * field type of a given field as the array index so that all the information |
| 79 | * is on the appropriate place inside the array. In this way one do not need |
| 80 | * to search for fields but can simply use an index into the array. |
| 81 | */ |
| 82 | static const struct param_info params[] = { |
| 83 | [HIB_VerID] = { |
| 84 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x8, .len = 4}, |
| 85 | .get_field = hwilib_read_bytes }, |
| 86 | [SIB_VerID] = { |
| 87 | .pos[0] = {.blk_type = BLK_SIB, .offset = 0x8, .len = 4}, |
| 88 | .get_field = hwilib_read_bytes }, |
| 89 | [EIB_VerID] = { |
| 90 | .pos[0] = {.blk_type = BLK_EIB, .offset = 0x8, .len = 4}, |
| 91 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 92 | [XIB_VerID] = { |
| 93 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x8, .len = 4}, |
| 94 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 95 | [HIB_HwRev] = { |
| 96 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xbe, .len = 2}, |
| 97 | .get_field = hwilib_read_bytes }, |
| 98 | [SIB_HwRev] = { |
| 99 | .pos[0] = {.blk_type = BLK_SIB, .offset = 0xc8, .len = 2}, |
| 100 | .get_field = hwilib_read_bytes }, |
Werner Zeh | ba7525d | 2016-11-23 07:31:35 +0100 | [diff] [blame] | 101 | [HWID] = { |
| 102 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1a8, .len = 4}, |
| 103 | .pos[1] = {.blk_type = BLK_SIB, .offset = 0xd0, .len = 4}, |
| 104 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 105 | [UniqueNum] = { |
| 106 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xa2, .len = 10}, |
| 107 | .pos[1] = {.blk_type = BLK_SIB, .offset = 0xa2, .len = 10}, |
| 108 | .get_field = hwilib_read_bytes }, |
| 109 | [Mac1] = { |
| 110 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xc0, .len = 6}, |
| 111 | .get_field = hwilib_read_bytes }, |
| 112 | [Mac1Aux] = { |
| 113 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xc6, .len = 1}, |
| 114 | .get_field = hwilib_read_bytes }, |
| 115 | [Mac2] = { |
| 116 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xc8, .len = 6}, |
| 117 | .get_field = hwilib_read_bytes }, |
| 118 | [Mac2Aux] = { |
| 119 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xce, .len = 1}, |
| 120 | .get_field = hwilib_read_bytes }, |
| 121 | [Mac3] = { |
| 122 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xd0, .len = 6}, |
| 123 | .get_field = hwilib_read_bytes }, |
| 124 | [Mac3Aux] = { |
| 125 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xd6, .len = 1}, |
| 126 | .get_field = hwilib_read_bytes }, |
| 127 | [Mac4] = { |
| 128 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xd8, .len = 6}, |
| 129 | .get_field = hwilib_read_bytes }, |
| 130 | [Mac4Aux] = { |
| 131 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xde, .len = 1}, |
| 132 | .get_field = hwilib_read_bytes }, |
| 133 | [SPD] = { |
| 134 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0xe0, .len = 0x80}, |
| 135 | .get_field = hwilib_read_bytes }, |
| 136 | [FF_FreezeDis] = { |
Werner Zeh | 5e21cd4 | 2017-06-30 10:05:06 +0200 | [diff] [blame] | 137 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1b8, .len = 1}, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 138 | .mask = 0x10, |
| 139 | .mask_offset = 4, |
| 140 | .get_field = hwilib_read_bytes }, |
| 141 | [FF_FanReq] = { |
Werner Zeh | 5e21cd4 | 2017-06-30 10:05:06 +0200 | [diff] [blame] | 142 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1b9, .len = 1}, |
| 143 | .mask = 0x04, |
| 144 | .mask_offset = 2, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 145 | .get_field = hwilib_read_bytes }, |
Mario Scheithauer | 59dd466 | 2017-06-12 09:46:09 +0200 | [diff] [blame] | 146 | [NvramVirtTimeDsaveReset] = { |
| 147 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1be, .len = 2}, |
| 148 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 149 | [BiosFlags] = { |
| 150 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1c0, .len = 4}, |
| 151 | .get_field = hwilib_read_bytes }, |
| 152 | [MacMapping1] = { |
| 153 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1cc, .len = 4}, |
| 154 | .get_field = hwilib_read_bytes }, |
| 155 | [MacMapping2] = { |
| 156 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d0, .len = 4}, |
| 157 | .get_field = hwilib_read_bytes }, |
| 158 | [MacMapping3] = { |
| 159 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d4, .len = 4}, |
| 160 | .get_field = hwilib_read_bytes }, |
| 161 | [MacMapping4] = { |
| 162 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1d8, .len = 4}, |
| 163 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 164 | [RTCType] = { |
| 165 | .pos[0] = {.blk_type = BLK_HIB, .offset = 0x1e8, .len = 1}, |
| 166 | .get_field = hwilib_read_bytes }, |
Mario Scheithauer | 59dd466 | 2017-06-12 09:46:09 +0200 | [diff] [blame] | 167 | [BL_Brightness] = { |
| 168 | .pos[0] = {.blk_type = BLK_SIB, .offset = 0xd8, .len = 1}, |
| 169 | .get_field = hwilib_read_bytes }, |
| 170 | [PF_PwmFreq] = { |
| 171 | .pos[0] = {.blk_type = BLK_SIB, .offset = 0xe7, .len = 1}, |
| 172 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 173 | [PF_Color_Depth] = { |
| 174 | .pos[0] = {.blk_type = BLK_SIB, .offset = 0xea, .len = 1}, |
| 175 | .mask = 0x03, |
| 176 | .mask_offset = 0, |
| 177 | .get_field = hwilib_read_bytes }, |
| 178 | [PF_DisplType] = { |
| 179 | .pos[0] = {.blk_type = BLK_SIB, .offset = 0xe3, .len = 1}, |
| 180 | .get_field = hwilib_read_bytes }, |
| 181 | [PF_DisplCon] = { |
| 182 | .pos[0] = {.blk_type = BLK_SIB, .offset = 0xf2, .len = 1}, |
| 183 | .get_field = hwilib_read_bytes }, |
| 184 | [Edid] = { |
| 185 | .pos[0] = {.blk_type = BLK_EIB, .offset = 0x10, .len = 0x80}, |
| 186 | .get_field = hwilib_read_bytes }, |
| 187 | [VddRef] = { |
| 188 | .pos[0] = {.blk_type = BLK_EIB, .offset = 0x90, .len = 2}, |
| 189 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 190 | [XMac1] = { |
| 191 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0xfc, .len = 6}, |
| 192 | .get_field = hwilib_read_bytes }, |
| 193 | [XMac1Aux] = { |
| 194 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x102, .len = 1}, |
| 195 | .get_field = hwilib_read_bytes }, |
| 196 | [XMac2] = { |
| 197 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x114, .len = 6}, |
| 198 | .get_field = hwilib_read_bytes }, |
| 199 | [XMac2Aux] = { |
| 200 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x11a, .len = 1}, |
| 201 | .get_field = hwilib_read_bytes }, |
| 202 | [XMac3] = { |
| 203 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x12c, .len = 6}, |
| 204 | .get_field = hwilib_read_bytes }, |
| 205 | [XMac3Aux] = { |
| 206 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x132, .len = 1}, |
| 207 | .get_field = hwilib_read_bytes }, |
| 208 | [XMac4] = { |
| 209 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x144, .len = 6}, |
| 210 | .get_field = hwilib_read_bytes }, |
| 211 | [XMac4Aux] = { |
| 212 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x14a, .len = 1}, |
| 213 | .get_field = hwilib_read_bytes }, |
| 214 | [XMac5] = { |
| 215 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x15c, .len = 6}, |
| 216 | .get_field = hwilib_read_bytes }, |
| 217 | [XMac5Aux] = { |
| 218 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x162, .len = 1}, |
| 219 | .get_field = hwilib_read_bytes }, |
| 220 | [XMac6] = { |
| 221 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x174, .len = 6}, |
| 222 | .get_field = hwilib_read_bytes }, |
| 223 | [XMac6Aux] = { |
| 224 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x17a, .len = 1}, |
| 225 | .get_field = hwilib_read_bytes }, |
| 226 | [XMac7] = { |
| 227 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x18c, .len = 6}, |
| 228 | .get_field = hwilib_read_bytes }, |
| 229 | [XMac7Aux] = { |
| 230 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x192, .len = 1}, |
| 231 | .get_field = hwilib_read_bytes }, |
| 232 | [XMac8] = { |
| 233 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1a4, .len = 6}, |
| 234 | .get_field = hwilib_read_bytes }, |
| 235 | [XMac8Aux] = { |
| 236 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1aa, .len = 1}, |
| 237 | .get_field = hwilib_read_bytes }, |
| 238 | [XMac9] = { |
| 239 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1bc, .len = 6}, |
| 240 | .get_field = hwilib_read_bytes }, |
| 241 | [XMac9Aux] = { |
| 242 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c2, .len = 1}, |
| 243 | .get_field = hwilib_read_bytes }, |
| 244 | [XMac10] = { |
| 245 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1d4, .len = 6}, |
| 246 | .get_field = hwilib_read_bytes }, |
| 247 | [XMac10Aux] = { |
| 248 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1da, .len = 1}, |
| 249 | .get_field = hwilib_read_bytes }, |
| 250 | [XMac1Mapping] = { |
| 251 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0xec, .len = 16}, |
| 252 | .get_field = hwilib_read_bytes }, |
| 253 | [XMac2Mapping] = { |
| 254 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x104, .len = 16}, |
| 255 | .get_field = hwilib_read_bytes }, |
| 256 | [XMac3Mapping] = { |
| 257 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x11c, .len = 16}, |
| 258 | .get_field = hwilib_read_bytes }, |
| 259 | [XMac4Mapping] = { |
| 260 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x134, .len = 16}, |
| 261 | .get_field = hwilib_read_bytes }, |
| 262 | [XMac5Mapping] = { |
| 263 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x14c, .len = 16}, |
| 264 | .get_field = hwilib_read_bytes }, |
| 265 | [XMac6Mapping] = { |
| 266 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x164, .len = 16}, |
| 267 | .get_field = hwilib_read_bytes }, |
| 268 | [XMac7Mapping] = { |
| 269 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x17c, .len = 16}, |
| 270 | .get_field = hwilib_read_bytes }, |
| 271 | [XMac8Mapping] = { |
| 272 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x194, .len = 16}, |
| 273 | .get_field = hwilib_read_bytes }, |
| 274 | [XMac9Mapping] = { |
| 275 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1ac, .len = 16}, |
| 276 | .get_field = hwilib_read_bytes }, |
| 277 | [XMac10Mapping] = { |
| 278 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c4, .len = 16}, |
| 279 | .get_field = hwilib_read_bytes }, |
| 280 | [netKind1] = { |
| 281 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x103, .len = 1}, |
| 282 | .get_field = hwilib_read_bytes }, |
| 283 | [netKind2] = { |
| 284 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x11b, .len = 1}, |
| 285 | .get_field = hwilib_read_bytes }, |
| 286 | [netKind3] = { |
| 287 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x133, .len = 1}, |
| 288 | .get_field = hwilib_read_bytes }, |
| 289 | [netKind4] = { |
| 290 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x14b, .len = 1}, |
| 291 | .get_field = hwilib_read_bytes }, |
| 292 | [netKind5] = { |
| 293 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x163, .len = 1}, |
| 294 | .get_field = hwilib_read_bytes }, |
| 295 | [netKind6] = { |
| 296 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x17b, .len = 1}, |
| 297 | .get_field = hwilib_read_bytes }, |
| 298 | [netKind7] = { |
| 299 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x193, .len = 1}, |
| 300 | .get_field = hwilib_read_bytes }, |
| 301 | [netKind8] = { |
| 302 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1ab, .len = 1}, |
| 303 | .get_field = hwilib_read_bytes }, |
| 304 | [netKind9] = { |
| 305 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c3, .len = 1}, |
| 306 | .get_field = hwilib_read_bytes }, |
| 307 | [netKind10] = { |
| 308 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1db, .len = 1}, |
| 309 | .get_field = hwilib_read_bytes }, |
| 310 | [T_Warn] = { |
| 311 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x18, .len = 4}, |
| 312 | .get_field = hwilib_read_bytes }, |
| 313 | [T_Crit] = { |
| 314 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x1c, .len = 4}, |
| 315 | .get_field = hwilib_read_bytes }, |
| 316 | [FANSamplingTime] = { |
| 317 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x20, .len = 4}, |
| 318 | .get_field = hwilib_read_bytes }, |
| 319 | [FANSetPoint] = { |
| 320 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x24, .len = 4}, |
| 321 | .get_field = hwilib_read_bytes }, |
| 322 | [FANKp] = { |
| 323 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x28, .len = 4}, |
| 324 | .get_field = hwilib_read_bytes }, |
| 325 | [FANKi] = { |
| 326 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x2c, .len = 4}, |
| 327 | .get_field = hwilib_read_bytes }, |
| 328 | [FANKd] = { |
| 329 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x30, .len = 4}, |
| 330 | .get_field = hwilib_read_bytes }, |
| 331 | [FANHystVal] = { |
| 332 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x34, .len = 4}, |
| 333 | .get_field = hwilib_read_bytes }, |
| 334 | [FANHystThreshold] = { |
| 335 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x38, .len = 4}, |
| 336 | .get_field = hwilib_read_bytes }, |
| 337 | [FANHystCtrl] = { |
| 338 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x3c, .len = 4}, |
| 339 | .get_field = hwilib_read_bytes }, |
| 340 | [FANMaxSpeed] = { |
| 341 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x40, .len = 2}, |
| 342 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 909536a | 2017-07-27 13:43:24 +0200 | [diff] [blame] | 343 | [FANStartSpeed] = { |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 344 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x42, .len = 2}, |
| 345 | .get_field = hwilib_read_bytes }, |
| 346 | [FANSensorDelay] = { |
| 347 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x44, .len = 4}, |
| 348 | .get_field = hwilib_read_bytes }, |
| 349 | [FANSensorNum] = { |
| 350 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x48, .len = 1}, |
| 351 | .get_field = hwilib_read_bytes }, |
| 352 | [FANSensorSelect] = { |
| 353 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x49, .len = 1}, |
| 354 | .get_field = hwilib_read_bytes }, |
| 355 | [FANSensorCfg0] = { |
| 356 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x4c, .len = 20}, |
| 357 | .get_field = hwilib_read_bytes }, |
| 358 | [FANSensorCfg1] = { |
| 359 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x60, .len = 20}, |
| 360 | .get_field = hwilib_read_bytes }, |
| 361 | [FANSensorCfg2] = { |
| 362 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x74, .len = 20}, |
| 363 | .get_field = hwilib_read_bytes }, |
| 364 | [FANSensorCfg3] = { |
| 365 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x88, .len = 20}, |
| 366 | .get_field = hwilib_read_bytes }, |
| 367 | [FANSensorCfg4] = { |
| 368 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x9c, .len = 20}, |
| 369 | .get_field = hwilib_read_bytes }, |
| 370 | [FANSensorCfg5] = { |
| 371 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0xb0, .len = 20}, |
| 372 | .get_field = hwilib_read_bytes }, |
| 373 | [FANSensorCfg6] = { |
| 374 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0xc4, .len = 20}, |
| 375 | .get_field = hwilib_read_bytes }, |
| 376 | [FANSensorCfg7] = { |
| 377 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0xd8, .len = 20}, |
| 378 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 461797e | 2017-09-12 07:58:14 +0200 | [diff] [blame] | 379 | [LegacyDelay] = { |
| 380 | .pos[0] = {.blk_type = BLK_XIB, .offset = 0x20c, .len = 4}, |
| 381 | .get_field = hwilib_read_bytes }, |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 382 | }; |
| 383 | |
| 384 | /** \brief This functions reads the given field from the first valid hwinfo |
| 385 | * block |
| 386 | * @param *param Parameter to read from hwinfo |
| 387 | * @param *dst Pointer to memory where the data will be stored in |
| 388 | * @return number of copied bytes on success, 0 on error |
| 389 | */ |
| 390 | static uint32_t hwilib_read_bytes (const struct param_info *param, uint8_t *dst, |
| 391 | uint32_t maxlen) |
| 392 | { |
| 393 | uint8_t i = 0, *blk = NULL; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 394 | |
| 395 | if (!param || !dst) |
| 396 | return 0; |
| 397 | /* Take the first valid block to get the parameter from */ |
| 398 | do { |
Werner Zeh | 8f91623 | 2016-12-01 10:53:14 +0100 | [diff] [blame] | 399 | if ((param->pos[i].len) && (param->pos[i].offset) && |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 400 | (all_blocks[param->pos[i].blk_type])) { |
| 401 | blk = all_blocks[param->pos[i].blk_type]; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 402 | break; |
| 403 | } |
| 404 | i++; |
| 405 | } while (i < MAX_BLOCK_NUM); |
| 406 | |
| 407 | /* Ensure there is a valid block available for this parameter and |
| 408 | * the length of the parameter do not exceed maxlen or block len. |
| 409 | */ |
| 410 | if ((!blk) || (param->pos[i].len > maxlen) || |
| 411 | (param->pos[i].len + param->pos[i].offset > |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 412 | all_blk_size[param->pos[i].blk_type])) |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 413 | return 0; |
| 414 | /* We can now copy the wanted data. */ |
| 415 | memcpy(dst, (blk + param->pos[i].offset), param->pos[i].len); |
| 416 | /* If there is a mask given, apply it only for parameters with a |
| 417 | * length of 1, 2, 4 or 8 bytes. |
| 418 | */ |
| 419 | if (param->mask) { |
| 420 | switch (param->pos[i].len) { |
| 421 | case 1: |
| 422 | /* Apply a mask on a 8 bit value */ |
| 423 | *dst &= (param->mask & 0xff); |
| 424 | *dst >>= (param->mask_offset); |
| 425 | break; |
| 426 | case 2: |
| 427 | /* Apply mask on a 16 bit value */ |
| 428 | *((uint16_t *)(dst)) &= (param->mask & 0xffff); |
| 429 | *((uint16_t *)(dst)) >>= (param->mask_offset); |
| 430 | break; |
| 431 | case 4: |
| 432 | /* Apply mask on a 32 bit value */ |
| 433 | *((uint32_t *)(dst)) &= (param->mask & 0xffffffff); |
| 434 | *((uint32_t *)(dst)) >>= (param->mask_offset); |
| 435 | break; |
| 436 | case 8: |
| 437 | /* Apply mask on a 64 bit value */ |
| 438 | *((uint64_t *)(dst)) &= (param->mask); |
| 439 | *((uint64_t *)(dst)) >>= (param->mask_offset); |
| 440 | break; |
| 441 | default: |
| 442 | /* Warn if there is a mask for an invalid length. */ |
| 443 | printk(BIOS_WARNING, |
| 444 | "HWILIB: Invalid field length for given mask.\n"); |
| 445 | break; |
| 446 | } |
| 447 | } |
| 448 | return param->pos[i].len; |
| 449 | } |
| 450 | |
| 451 | /** \brief This function finds all available block types in a given cbfs file. |
| 452 | * @param *hwi_filename Name of the cbfs-file to use. |
| 453 | * @return CB_SUCCESS when no error, otherwise error code |
| 454 | */ |
| 455 | enum cb_err hwilib_find_blocks (const char *hwi_filename) |
| 456 | { |
| 457 | uint8_t *ptr = NULL, *base = NULL; |
| 458 | uint32_t next_offset = 1; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 459 | size_t filesize = 0; |
| 460 | |
| 461 | /* Check for a valid parameter */ |
| 462 | if (!hwi_filename) |
| 463 | return CB_ERR_ARG; |
Werner Zeh | d35a481 | 2019-02-20 06:38:04 +0100 | [diff] [blame] | 464 | /* Check if this file is already open. If yes, just leave as there is |
| 465 | nothing left to do here. */ |
Arthur Heymans | 5b0db35 | 2019-11-21 08:00:27 +0100 | [diff] [blame] | 466 | if (!strncmp(current_hwi, hwi_filename, HWI_MAX_NAME_LEN)) { |
Werner Zeh | d35a481 | 2019-02-20 06:38:04 +0100 | [diff] [blame] | 467 | printk(BIOS_SPEW, "HWILIB: File \"%s\" already open.\n", |
| 468 | hwi_filename); |
| 469 | return CB_SUCCESS; |
| 470 | } |
| 471 | |
Julius Werner | 834b3ec | 2020-03-04 16:52:08 -0800 | [diff] [blame^] | 472 | ptr = cbfs_map(hwi_filename, &filesize); |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 473 | if (!ptr) { |
| 474 | printk(BIOS_ERR,"HWILIB: Missing file \"%s\" in cbfs.\n", |
| 475 | hwi_filename); |
| 476 | return CB_ERR; |
| 477 | } |
| 478 | /* Ensure the block has the right magic */ |
| 479 | if (strncmp((char*)ptr, BLOCK_MAGIC, LEN_MAGIC_NUM)) { |
| 480 | printk(BIOS_ERR, "HWILIB: Bad magic at start of block!\n"); |
| 481 | return CB_ERR; |
| 482 | } |
| 483 | /* Reset all static pointers to blocks as they might have been set |
| 484 | * in prior calls to this function. |
| 485 | * This way the caller do not need to "close" already opened blocks. |
| 486 | */ |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 487 | memset(all_blocks, 0, (MAX_BLOCK_NUM * sizeof (uint8_t *))); |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 488 | /* Check which blocks are available by examining the length field. */ |
| 489 | base = ptr; |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 490 | /* Fill in sizes of all fixed length blocks. */ |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 491 | all_blk_size[BLK_HIB] = LEN_HIB; |
| 492 | all_blk_size[BLK_SIB] = LEN_SIB; |
| 493 | all_blk_size[BLK_EIB] = LEN_EIB; |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 494 | /* Length of BLK_XIB is variable and will be filled if block is found */ |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 495 | all_blk_size[BLK_XIB] = 0; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 496 | while(!(strncmp((char *)ptr, BLOCK_MAGIC, LEN_MAGIC_NUM)) && |
| 497 | next_offset) { |
| 498 | uint16_t len = read16(ptr + LEN_OFFSET); |
| 499 | /* Ensure file size boundaries for a given block. */ |
| 500 | if ((ptr - base + len) > filesize) |
| 501 | break; |
| 502 | if (len == LEN_HIB) { |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 503 | all_blocks[BLK_HIB] = ptr; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 504 | next_offset = read32(ptr + NEXT_OFFSET_HIB); |
| 505 | if (next_offset) |
| 506 | ptr = base + next_offset; |
| 507 | } else if (len == LEN_SIB) { |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 508 | all_blocks[BLK_SIB] = ptr; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 509 | next_offset = read32(ptr + NEXT_OFFSET_SIB); |
| 510 | if (next_offset) |
| 511 | ptr = base + next_offset; |
| 512 | } else if (len == LEN_EIB) { |
| 513 | /* Skip preliminary blocks */ |
| 514 | if (!(read16(ptr + EIB_FEATRUE_OFFSET) & 0x01)) |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 515 | all_blocks[BLK_EIB] = ptr; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 516 | next_offset = read32(ptr + NEXT_OFFSET_EIB); |
| 517 | if (next_offset) |
| 518 | ptr = base + next_offset; |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 519 | } else if (len >= MIN_LEN_XIB) { |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 520 | all_blocks[BLK_XIB] = ptr; |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 521 | next_offset = read32(ptr + NEXT_OFFSET_XIB); |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 522 | all_blk_size[BLK_XIB] = len; |
Werner Zeh | 66c20c4 | 2016-06-28 14:31:30 +0200 | [diff] [blame] | 523 | if (next_offset) |
| 524 | ptr = base + next_offset; |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 525 | } else { |
| 526 | next_offset = 0; |
| 527 | } |
| 528 | } |
| 529 | /* We should have found at least one valid block */ |
Arthur Heymans | b6c9a5d | 2019-11-20 19:35:59 +0100 | [diff] [blame] | 530 | if (all_blocks[BLK_HIB] || all_blocks[BLK_SIB] || all_blocks[BLK_EIB] || |
| 531 | all_blocks[BLK_XIB]) { |
Werner Zeh | d35a481 | 2019-02-20 06:38:04 +0100 | [diff] [blame] | 532 | /* Save currently opened hwi filename. */ |
Arthur Heymans | 5b0db35 | 2019-11-21 08:00:27 +0100 | [diff] [blame] | 533 | strncpy(current_hwi, hwi_filename, HWI_MAX_NAME_LEN); |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 534 | return CB_SUCCESS; |
Werner Zeh | d35a481 | 2019-02-20 06:38:04 +0100 | [diff] [blame] | 535 | } |
Werner Zeh | 223498f | 2016-04-22 14:14:45 +0200 | [diff] [blame] | 536 | else |
| 537 | return CB_ERR; |
| 538 | } |
| 539 | |
| 540 | /** \brief This functions is used from caller to get a specific field from |
| 541 | * hwinfo block. |
| 542 | * @param field Field type to read from hwinfo |
| 543 | * @param *dst Pointer to memory where the data will be stored in |
| 544 | * @return number of copied bytes on success, 0 on error |
| 545 | */ |
| 546 | uint32_t hwilib_get_field (hwinfo_field_t field, uint8_t *dst, uint32_t maxlen) |
| 547 | { |
| 548 | /* Check the boundaries of params-variable */ |
| 549 | if ((uint32_t)field < ARRAY_SIZE(params)) |
| 550 | return params[field].get_field(¶ms[field], dst, maxlen); |
| 551 | else |
| 552 | return 0; |
| 553 | } |