1 /* 2 * Copyright 2017 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 /* 24 * dc_helper.c 25 * 26 * Created on: Aug 30, 2016 27 * Author: agrodzov 28 */ 29 30 #include <linux/delay.h> 31 #include <linux/stdarg.h> 32 33 #include "dm_services.h" 34 35 #include "dc.h" 36 #include "dc_dmub_srv.h" 37 #include "reg_helper.h" 38 39 #define DC_LOGGER \ 40 ctx->logger 41 42 struct dc_reg_value_masks { 43 uint32_t value; 44 uint32_t mask; 45 }; 46 47 static inline void set_reg_field_value_masks( 48 struct dc_reg_value_masks *field_value_mask, 49 uint32_t value, 50 uint32_t mask, 51 uint8_t shift) 52 { 53 ASSERT(mask != 0); 54 55 field_value_mask->value = (field_value_mask->value & ~mask) | (mask & (value << shift)); 56 field_value_mask->mask = field_value_mask->mask | mask; 57 } 58 59 static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask, 60 uint32_t addr, int n, 61 uint8_t shift1, uint32_t mask1, uint32_t field_value1, 62 va_list ap) 63 { 64 (void)addr; 65 uint32_t shift, mask, field_value; 66 int i = 1; 67 68 /* gather all bits value/mask getting updated in this register */ 69 set_reg_field_value_masks(field_value_mask, 70 field_value1, mask1, shift1); 71 72 while (i < n) { 73 shift = va_arg(ap, uint32_t); 74 mask = va_arg(ap, uint32_t); 75 field_value = va_arg(ap, uint32_t); 76 77 set_reg_field_value_masks(field_value_mask, 78 field_value, mask, (uint8_t)shift); 79 i++; 80 } 81 } 82 83 uint32_t generic_reg_update_ex(const struct dc_context *ctx, 84 uint32_t addr, int n, 85 uint8_t shift1, uint32_t mask1, uint32_t field_value1, 86 ...) 87 { 88 struct dc_reg_value_masks field_value_mask = {0}; 89 uint32_t reg_val; 90 va_list ap; 91 92 va_start(ap, field_value1); 93 94 set_reg_field_values(&field_value_mask, addr, n, shift1, mask1, 95 field_value1, ap); 96 97 va_end(ap); 98 99 /* mmio write directly */ 100 reg_val = dm_read_reg(ctx, addr); 101 reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; 102 dm_write_reg(ctx, addr, reg_val); 103 return reg_val; 104 } 105 106 uint32_t generic_reg_set_ex(const struct dc_context *ctx, 107 uint32_t addr, uint32_t reg_val, int n, 108 uint8_t shift1, uint32_t mask1, uint32_t field_value1, 109 ...) 110 { 111 struct dc_reg_value_masks field_value_mask = {0}; 112 va_list ap; 113 114 va_start(ap, field_value1); 115 116 set_reg_field_values(&field_value_mask, addr, n, shift1, mask1, 117 field_value1, ap); 118 119 va_end(ap); 120 121 /* mmio write directly */ 122 reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; 123 124 dm_write_reg(ctx, addr, reg_val); 125 return reg_val; 126 } 127 128 uint32_t generic_reg_get(const struct dc_context *ctx, uint32_t addr, 129 uint8_t shift, uint32_t mask, uint32_t *field_value) 130 { 131 uint32_t reg_val = dm_read_reg(ctx, addr); 132 *field_value = get_reg_field_value_ex(reg_val, mask, shift); 133 return reg_val; 134 } 135 136 uint32_t generic_reg_get2(const struct dc_context *ctx, uint32_t addr, 137 uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 138 uint8_t shift2, uint32_t mask2, uint32_t *field_value2) 139 { 140 uint32_t reg_val = dm_read_reg(ctx, addr); 141 *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 142 *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 143 return reg_val; 144 } 145 146 uint32_t generic_reg_get3(const struct dc_context *ctx, uint32_t addr, 147 uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 148 uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 149 uint8_t shift3, uint32_t mask3, uint32_t *field_value3) 150 { 151 uint32_t reg_val = dm_read_reg(ctx, addr); 152 *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 153 *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 154 *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 155 return reg_val; 156 } 157 158 uint32_t generic_reg_get4(const struct dc_context *ctx, uint32_t addr, 159 uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 160 uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 161 uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 162 uint8_t shift4, uint32_t mask4, uint32_t *field_value4) 163 { 164 uint32_t reg_val = dm_read_reg(ctx, addr); 165 *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 166 *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 167 *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 168 *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 169 return reg_val; 170 } 171 172 uint32_t generic_reg_get5(const struct dc_context *ctx, uint32_t addr, 173 uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 174 uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 175 uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 176 uint8_t shift4, uint32_t mask4, uint32_t *field_value4, 177 uint8_t shift5, uint32_t mask5, uint32_t *field_value5) 178 { 179 uint32_t reg_val = dm_read_reg(ctx, addr); 180 *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 181 *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 182 *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 183 *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 184 *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5); 185 return reg_val; 186 } 187 188 uint32_t generic_reg_get6(const struct dc_context *ctx, uint32_t addr, 189 uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 190 uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 191 uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 192 uint8_t shift4, uint32_t mask4, uint32_t *field_value4, 193 uint8_t shift5, uint32_t mask5, uint32_t *field_value5, 194 uint8_t shift6, uint32_t mask6, uint32_t *field_value6) 195 { 196 uint32_t reg_val = dm_read_reg(ctx, addr); 197 *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 198 *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 199 *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 200 *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 201 *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5); 202 *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6); 203 return reg_val; 204 } 205 206 uint32_t generic_reg_get7(const struct dc_context *ctx, uint32_t addr, 207 uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 208 uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 209 uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 210 uint8_t shift4, uint32_t mask4, uint32_t *field_value4, 211 uint8_t shift5, uint32_t mask5, uint32_t *field_value5, 212 uint8_t shift6, uint32_t mask6, uint32_t *field_value6, 213 uint8_t shift7, uint32_t mask7, uint32_t *field_value7) 214 { 215 uint32_t reg_val = dm_read_reg(ctx, addr); 216 *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 217 *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 218 *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 219 *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 220 *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5); 221 *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6); 222 *field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7); 223 return reg_val; 224 } 225 226 uint32_t generic_reg_get8(const struct dc_context *ctx, uint32_t addr, 227 uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 228 uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 229 uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 230 uint8_t shift4, uint32_t mask4, uint32_t *field_value4, 231 uint8_t shift5, uint32_t mask5, uint32_t *field_value5, 232 uint8_t shift6, uint32_t mask6, uint32_t *field_value6, 233 uint8_t shift7, uint32_t mask7, uint32_t *field_value7, 234 uint8_t shift8, uint32_t mask8, uint32_t *field_value8) 235 { 236 uint32_t reg_val = dm_read_reg(ctx, addr); 237 *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 238 *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 239 *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 240 *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 241 *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5); 242 *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6); 243 *field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7); 244 *field_value8 = get_reg_field_value_ex(reg_val, mask8, shift8); 245 return reg_val; 246 } 247 /* note: va version of this is pretty bad idea, since there is a output parameter pass by pointer 248 * compiler won't be able to check for size match and is prone to stack corruption type of bugs 249 250 uint32_t generic_reg_get(const struct dc_context *ctx, 251 uint32_t addr, int n, ...) 252 { 253 uint32_t shift, mask; 254 uint32_t *field_value; 255 uint32_t reg_val; 256 int i = 0; 257 258 reg_val = dm_read_reg(ctx, addr); 259 260 va_list ap; 261 va_start(ap, n); 262 263 while (i < n) { 264 shift = va_arg(ap, uint32_t); 265 mask = va_arg(ap, uint32_t); 266 field_value = va_arg(ap, uint32_t *); 267 268 *field_value = get_reg_field_value_ex(reg_val, mask, shift); 269 i++; 270 } 271 272 va_end(ap); 273 274 return reg_val; 275 } 276 */ 277 278 void generic_reg_wait(const struct dc_context *ctx, 279 uint32_t addr, uint32_t shift, uint32_t mask, uint32_t condition_value, 280 unsigned int delay_between_poll_us, unsigned int time_out_num_tries, 281 const char *func_name, int line) 282 { 283 uint32_t field_value; 284 uint32_t reg_val; 285 unsigned int i; 286 287 /* 288 * Something is terribly wrong if time out is > 3000ms. 289 * 3000ms is the maximum time needed for SMU to pass values back. 290 * This value comes from experiments. 291 * 292 */ 293 ASSERT(delay_between_poll_us * time_out_num_tries <= 3000000u); 294 295 for (i = 0; i <= time_out_num_tries; i++) { 296 if (i) { 297 if (delay_between_poll_us >= 1000) 298 msleep(delay_between_poll_us/1000); 299 else if (delay_between_poll_us > 0) 300 udelay(delay_between_poll_us); 301 } 302 303 reg_val = dm_read_reg(ctx, addr); 304 305 field_value = get_reg_field_value_ex(reg_val, mask, (uint8_t)shift); 306 307 if (field_value == condition_value) { 308 if (i * delay_between_poll_us > 1000) 309 DC_LOG_DC("REG_WAIT taking a while: %dms in %s line:%d\n", 310 delay_between_poll_us * i / 1000, 311 func_name, line); 312 return; 313 } 314 } 315 316 DC_LOG_WARNING("REG_WAIT timeout %dus * %d tries - %s line:%d\n", 317 delay_between_poll_us, time_out_num_tries, 318 func_name, line); 319 320 BREAK_TO_DEBUGGER(); 321 } 322 323 void generic_write_indirect_reg(const struct dc_context *ctx, 324 uint32_t addr_index, uint32_t addr_data, 325 uint32_t index, uint32_t data) 326 { 327 dm_write_reg(ctx, addr_index, index); 328 dm_write_reg(ctx, addr_data, data); 329 } 330 331 uint32_t generic_read_indirect_reg(const struct dc_context *ctx, 332 uint32_t addr_index, uint32_t addr_data, 333 uint32_t index) 334 { 335 uint32_t value = 0; 336 337 dm_write_reg(ctx, addr_index, index); 338 value = dm_read_reg(ctx, addr_data); 339 340 return value; 341 } 342 343 uint32_t generic_indirect_reg_get(const struct dc_context *ctx, 344 uint32_t addr_index, uint32_t addr_data, 345 uint32_t index, int n, 346 uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 347 ...) 348 { 349 uint32_t shift, mask, *field_value; 350 uint32_t value = 0; 351 int i = 1; 352 353 va_list ap; 354 355 va_start(ap, field_value1); 356 357 value = generic_read_indirect_reg(ctx, addr_index, addr_data, index); 358 *field_value1 = get_reg_field_value_ex(value, mask1, shift1); 359 360 while (i < n) { 361 shift = va_arg(ap, uint32_t); 362 mask = va_arg(ap, uint32_t); 363 field_value = va_arg(ap, uint32_t *); 364 365 *field_value = get_reg_field_value_ex(value, mask, (uint8_t)shift); 366 i++; 367 } 368 369 va_end(ap); 370 371 return value; 372 } 373 374 uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx, 375 uint32_t addr_index, uint32_t addr_data, 376 uint32_t index, uint32_t reg_val, int n, 377 uint8_t shift1, uint32_t mask1, uint32_t field_value1, 378 ...) 379 { 380 uint32_t shift, mask, field_value; 381 int i = 1; 382 383 va_list ap; 384 385 va_start(ap, field_value1); 386 387 reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1); 388 389 while (i < n) { 390 shift = va_arg(ap, uint32_t); 391 mask = va_arg(ap, uint32_t); 392 field_value = va_arg(ap, uint32_t); 393 394 reg_val = set_reg_field_value_ex(reg_val, field_value, mask, (uint8_t)shift); 395 i++; 396 } 397 398 generic_write_indirect_reg(ctx, addr_index, addr_data, index, reg_val); 399 va_end(ap); 400 401 return reg_val; 402 } 403 404 405 uint32_t generic_indirect_reg_update_ex_sync(const struct dc_context *ctx, 406 uint32_t index, uint32_t reg_val, int n, 407 uint8_t shift1, uint32_t mask1, uint32_t field_value1, 408 ...) 409 { 410 uint32_t shift, mask, field_value; 411 int i = 1; 412 413 va_list ap; 414 415 va_start(ap, field_value1); 416 417 reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1); 418 419 while (i < n) { 420 shift = va_arg(ap, uint32_t); 421 mask = va_arg(ap, uint32_t); 422 field_value = va_arg(ap, uint32_t); 423 424 reg_val = set_reg_field_value_ex(reg_val, field_value, mask, (uint8_t)shift); 425 i++; 426 } 427 428 dm_write_index_reg(ctx, CGS_IND_REG__PCIE, index, reg_val); 429 va_end(ap); 430 431 return reg_val; 432 } 433 434 uint32_t generic_indirect_reg_get_sync(const struct dc_context *ctx, 435 uint32_t index, int n, 436 uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 437 ...) 438 { 439 uint32_t shift, mask, *field_value; 440 uint32_t value = 0; 441 int i = 1; 442 443 va_list ap; 444 445 va_start(ap, field_value1); 446 447 value = dm_read_index_reg(ctx, CGS_IND_REG__PCIE, index); 448 *field_value1 = get_reg_field_value_ex(value, mask1, shift1); 449 450 while (i < n) { 451 shift = va_arg(ap, uint32_t); 452 mask = va_arg(ap, uint32_t); 453 field_value = va_arg(ap, uint32_t *); 454 455 *field_value = get_reg_field_value_ex(value, mask, (uint8_t)shift); 456 i++; 457 } 458 459 va_end(ap); 460 461 return value; 462 } 463 464 char *dce_version_to_string(const int version) 465 { 466 switch (version) { 467 case DCE_VERSION_6_0: 468 return "DCE 6.0"; 469 case DCE_VERSION_6_1: 470 return "DCE 6.1"; 471 case DCE_VERSION_6_4: 472 return "DCE 6.4"; 473 case DCE_VERSION_8_0: 474 return "DCE 8.0"; 475 case DCE_VERSION_8_1: 476 return "DCE 8.1"; 477 case DCE_VERSION_8_3: 478 return "DCE 8.3"; 479 case DCE_VERSION_10_0: 480 return "DCE 10.0"; 481 case DCE_VERSION_11_0: 482 return "DCE 11.0"; 483 case DCE_VERSION_11_2: 484 return "DCE 11.2"; 485 case DCE_VERSION_11_22: 486 return "DCE 11.22"; 487 case DCE_VERSION_12_0: 488 return "DCE 12.0"; 489 case DCE_VERSION_12_1: 490 return "DCE 12.1"; 491 case DCN_VERSION_1_0: 492 return "DCN 1.0"; 493 case DCN_VERSION_1_01: 494 return "DCN 1.0.1"; 495 case DCN_VERSION_2_0: 496 return "DCN 2.0"; 497 case DCN_VERSION_2_1: 498 return "DCN 2.1"; 499 case DCN_VERSION_2_01: 500 return "DCN 2.0.1"; 501 case DCN_VERSION_3_0: 502 return "DCN 3.0"; 503 case DCN_VERSION_3_01: 504 return "DCN 3.0.1"; 505 case DCN_VERSION_3_02: 506 return "DCN 3.0.2"; 507 case DCN_VERSION_3_03: 508 return "DCN 3.0.3"; 509 case DCN_VERSION_3_1: 510 return "DCN 3.1.2"; 511 case DCN_VERSION_3_14: 512 return "DCN 3.1.4"; 513 case DCN_VERSION_3_15: 514 return "DCN 3.1.5"; 515 case DCN_VERSION_3_16: 516 return "DCN 3.1.6"; 517 case DCN_VERSION_3_2: 518 return "DCN 3.2"; 519 case DCN_VERSION_3_21: 520 return "DCN 3.2.1"; 521 case DCN_VERSION_3_5: 522 return "DCN 3.5"; 523 case DCN_VERSION_3_51: 524 return "DCN 3.5.1"; 525 case DCN_VERSION_3_6: 526 return "DCN 3.6"; 527 case DCN_VERSION_4_01: 528 return "DCN 4.0.1"; 529 case DCN_VERSION_4_2: 530 return "DCN 4.2"; 531 case DCN_VERSION_4_2B: 532 return "DCN 4.2B"; 533 case DCN_VERSION_6_0: 534 return "DCN 6.0"; 535 default: 536 return "Unknown"; 537 } 538 } 539 540 bool dc_supports_vrr(const enum dce_version v) 541 { 542 return v >= DCE_VERSION_8_0; 543 } 544