Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/imagination: Add gpuid module parameter

The "gpuid" module parameter is used to override the gpuid read from a
hardware register and is useful for testing the loading of different
firmware (including processing of the firmware header) without having
the hardware to hand.

Signed-off-by: Alexandru Dadu <alexandru.dadu@imgtec.com>
Reviewed-by: Alessio Belle <alessio.belle@imgtec.com>
Link: https://patch.msgid.link/20260113-device-support-info-v1-4-91e5db7f7294@imgtec.com
Signed-off-by: Matt Coster <matt.coster@imgtec.com>

authored by

Alexandru Dadu and committed by
Matt Coster
3bf74137 ee184ab0

+114 -10
+109 -8
drivers/gpu/drm/imagination/pvr_device.c
··· 421 421 } 422 422 423 423 /** 424 - * pvr_load_gpu_id() - Load a PowerVR device's GPU ID (BVNC) from control registers. 424 + * pvr_gpuid_decode_reg() - Decode the GPU ID from GPU register 425 425 * 426 - * Sets struct pvr_dev.gpu_id. 426 + * Sets the b, v, n, c fields of struct pvr_dev.gpu_id. 427 427 * 428 428 * @pvr_dev: Target PowerVR device. 429 + * @gpu_id: Output to be updated with the GPU ID. 429 430 */ 430 431 static void 431 - pvr_load_gpu_id(struct pvr_device *pvr_dev) 432 + pvr_gpuid_decode_reg(const struct pvr_device *pvr_dev, struct pvr_gpu_id *gpu_id) 432 433 { 433 - struct pvr_gpu_id *gpu_id = &pvr_dev->gpu_id; 434 - u64 bvnc; 435 - 436 434 /* 437 435 * Try reading the BVNC using the newer (cleaner) method first. If the 438 436 * B value is zero, fall back to the older method. 439 437 */ 440 - bvnc = pvr_cr_read64(pvr_dev, ROGUE_CR_CORE_ID__PBVNC); 438 + u64 bvnc = pvr_cr_read64(pvr_dev, ROGUE_CR_CORE_ID__PBVNC); 441 439 442 440 gpu_id->b = PVR_CR_FIELD_GET(bvnc, CORE_ID__PBVNC__BRANCH_ID); 443 441 if (gpu_id->b != 0) { ··· 452 454 gpu_id->n = FIELD_GET(0xFF00, core_id_config); 453 455 gpu_id->c = FIELD_GET(0x00FF, core_id_config); 454 456 } 457 + } 458 + 459 + /** 460 + * pvr_gpuid_decode_string() - Decode the GPU ID from a module input string 461 + * 462 + * Sets the b, v, n, c fields of struct pvr_dev.gpu_id. 463 + * 464 + * @pvr_dev: Target PowerVR device. 465 + * @param_bvnc: GPU ID (BVNC) module parameter. 466 + * @gpu_id: Output to be updated with the GPU ID. 467 + */ 468 + static int 469 + pvr_gpuid_decode_string(const struct pvr_device *pvr_dev, 470 + const char *param_bvnc, struct pvr_gpu_id *gpu_id) 471 + { 472 + const struct drm_device *drm_dev = &pvr_dev->base; 473 + char str_cpy[PVR_GPUID_STRING_MAX_LENGTH]; 474 + char *pos, *tkn; 475 + int ret, idx = 0; 476 + u16 user_bvnc_u16[4]; 477 + u8 dot_cnt = 0; 478 + 479 + ret = strscpy(str_cpy, param_bvnc); 480 + 481 + /* 482 + * strscpy() should return at least a size 7 for the input to be valid. 483 + * Returns -E2BIG for the case when the string is empty or too long. 484 + */ 485 + if (ret < PVR_GPUID_STRING_MIN_LENGTH) { 486 + drm_info(drm_dev, 487 + "Invalid size of the input GPU ID (BVNC): %s", 488 + str_cpy); 489 + return -EINVAL; 490 + } 491 + 492 + while (*param_bvnc) { 493 + if (*param_bvnc == '.') 494 + dot_cnt++; 495 + param_bvnc++; 496 + } 497 + 498 + if (dot_cnt != 3) { 499 + drm_info(drm_dev, 500 + "Invalid format of the input GPU ID (BVNC): %s", 501 + str_cpy); 502 + return -EINVAL; 503 + } 504 + 505 + pos = str_cpy; 506 + 507 + while ((tkn = strsep(&pos, ".")) != NULL && idx < 4) { 508 + /* kstrtou16() will also handle the case of consecutive dots */ 509 + ret = kstrtou16(tkn, 10, &user_bvnc_u16[idx]); 510 + if (ret) { 511 + drm_info(drm_dev, 512 + "Invalid format of the input GPU ID (BVNC): %s", 513 + str_cpy); 514 + return -EINVAL; 515 + } 516 + idx++; 517 + } 518 + 519 + gpu_id->b = user_bvnc_u16[0]; 520 + gpu_id->v = user_bvnc_u16[1]; 521 + gpu_id->n = user_bvnc_u16[2]; 522 + gpu_id->c = user_bvnc_u16[3]; 523 + 524 + return 0; 525 + } 526 + 527 + static char *pvr_gpuid_override; 528 + module_param_named(gpuid, pvr_gpuid_override, charp, 0400); 529 + MODULE_PARM_DESC(gpuid, "GPU ID (BVNC) to be used instead of the value read from hardware."); 530 + 531 + /** 532 + * pvr_load_gpu_id() - Load a PowerVR device's GPU ID (BVNC) from control 533 + * registers or input parameter. The input parameter is processed instead 534 + * of the GPU register if provided. 535 + * 536 + * Sets the arch field of struct pvr_dev.gpu_id. 537 + * 538 + * @pvr_dev: Target PowerVR device. 539 + */ 540 + static int 541 + pvr_load_gpu_id(struct pvr_device *pvr_dev) 542 + { 543 + struct pvr_gpu_id *gpu_id = &pvr_dev->gpu_id; 544 + 545 + if (!pvr_gpuid_override || !pvr_gpuid_override[0]) { 546 + pvr_gpuid_decode_reg(pvr_dev, gpu_id); 547 + } else { 548 + drm_warn(from_pvr_device(pvr_dev), 549 + "Using custom GPU ID (BVNC) provided by the user!"); 550 + 551 + int err = pvr_gpuid_decode_string(pvr_dev, pvr_gpuid_override, 552 + gpu_id); 553 + if (err) 554 + return err; 555 + } 556 + 557 + return 0; 455 558 } 456 559 457 560 /** ··· 615 516 { 616 517 int err; 617 518 618 - pvr_load_gpu_id(pvr_dev); 519 + err = pvr_load_gpu_id(pvr_dev); 520 + if (err) 521 + return err; 619 522 620 523 err = pvr_request_firmware(pvr_dev); 621 524 if (err)
+5 -2
drivers/gpu/drm/imagination/pvr_device.h
··· 39 39 /* Forward declaration from <linux/pwrseq/consumer.h> */ 40 40 struct pwrseq_desc; 41 41 42 + #define PVR_GPUID_STRING_MIN_LENGTH 7U 43 + #define PVR_GPUID_STRING_MAX_LENGTH 32U 44 + 42 45 /** 43 46 * struct pvr_gpu_id - Hardware GPU ID information for a PowerVR device 44 47 * @b: Branch ID. ··· 561 558 * Return: The value of the requested register. 562 559 */ 563 560 static __always_inline u32 564 - pvr_cr_read32(struct pvr_device *pvr_dev, u32 reg) 561 + pvr_cr_read32(const struct pvr_device *pvr_dev, u32 reg) 565 562 { 566 563 return ioread32(pvr_dev->regs + reg); 567 564 } ··· 574 571 * Return: The value of the requested register. 575 572 */ 576 573 static __always_inline u64 577 - pvr_cr_read64(struct pvr_device *pvr_dev, u32 reg) 574 + pvr_cr_read64(const struct pvr_device *pvr_dev, u32 reg) 578 575 { 579 576 return ioread64(pvr_dev->regs + reg); 580 577 }