diff options
author | Ben Hutchings <ben@decadent.org.uk> | 2009-08-29 09:53:51 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-08-30 19:09:30 -0400 |
commit | 70967ab9c0c9017645d167d33675eab996633631 (patch) | |
tree | 5ec85349ccbf2bd21ab4929223d94ac11d17fa44 /drivers/gpu/drm/radeon/r100.c | |
parent | 1ae70072f0699916c1a77a9bacad958ee46f7395 (diff) |
radeon: Use request_firmware()
Loosely based on a patch by
Jaswinder Singh Rajput <jaswinderlinux@gmail.com>.
KMS support by Dave Airlie <airlied@redhat.com>.
For Radeon 100- to 500-series, firmware blobs look like:
struct {
__be32 datah;
__be32 datal;
} cp_ucode[256];
For Radeon 600-series, there are two separate firmware blobs:
__be32 me_ucode[PM4_UCODE_SIZE * 3];
__be32 pfp_ucode[PFP_UCODE_SIZE];
For Radeon 700-series, likewise:
__be32 me_ucode[R700_PM4_UCODE_SIZE];
__be32 pfp_ucode[R700_PFP_UCODE_SIZE];
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/r100.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r100.c | 119 |
1 files changed, 84 insertions, 35 deletions
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 90ff8e0ac04e..639d5b216eed 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c | |||
@@ -29,9 +29,27 @@ | |||
29 | #include "drmP.h" | 29 | #include "drmP.h" |
30 | #include "drm.h" | 30 | #include "drm.h" |
31 | #include "radeon_drm.h" | 31 | #include "radeon_drm.h" |
32 | #include "radeon_microcode.h" | ||
33 | #include "radeon_reg.h" | 32 | #include "radeon_reg.h" |
34 | #include "radeon.h" | 33 | #include "radeon.h" |
34 | #include <linux/firmware.h> | ||
35 | #include <linux/platform_device.h> | ||
36 | |||
37 | /* Firmware Names */ | ||
38 | #define FIRMWARE_R100 "radeon/R100_cp.bin" | ||
39 | #define FIRMWARE_R200 "radeon/R200_cp.bin" | ||
40 | #define FIRMWARE_R300 "radeon/R300_cp.bin" | ||
41 | #define FIRMWARE_R420 "radeon/R420_cp.bin" | ||
42 | #define FIRMWARE_RS690 "radeon/RS690_cp.bin" | ||
43 | #define FIRMWARE_RS600 "radeon/RS600_cp.bin" | ||
44 | #define FIRMWARE_R520 "radeon/R520_cp.bin" | ||
45 | |||
46 | MODULE_FIRMWARE(FIRMWARE_R100); | ||
47 | MODULE_FIRMWARE(FIRMWARE_R200); | ||
48 | MODULE_FIRMWARE(FIRMWARE_R300); | ||
49 | MODULE_FIRMWARE(FIRMWARE_R420); | ||
50 | MODULE_FIRMWARE(FIRMWARE_RS690); | ||
51 | MODULE_FIRMWARE(FIRMWARE_RS600); | ||
52 | MODULE_FIRMWARE(FIRMWARE_R520); | ||
35 | 53 | ||
36 | /* This files gather functions specifics to: | 54 | /* This files gather functions specifics to: |
37 | * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 | 55 | * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 |
@@ -478,33 +496,33 @@ void r100_ring_start(struct radeon_device *rdev) | |||
478 | radeon_ring_unlock_commit(rdev); | 496 | radeon_ring_unlock_commit(rdev); |
479 | } | 497 | } |
480 | 498 | ||
481 | static void r100_cp_load_microcode(struct radeon_device *rdev) | 499 | |
500 | /* Load the microcode for the CP */ | ||
501 | static int r100_cp_init_microcode(struct radeon_device *rdev) | ||
482 | { | 502 | { |
483 | int i; | 503 | struct platform_device *pdev; |
504 | const char *fw_name = NULL; | ||
505 | int err; | ||
484 | 506 | ||
485 | if (r100_gui_wait_for_idle(rdev)) { | 507 | DRM_DEBUG("\n"); |
486 | printk(KERN_WARNING "Failed to wait GUI idle while " | ||
487 | "programming pipes. Bad things might happen.\n"); | ||
488 | } | ||
489 | 508 | ||
490 | WREG32(RADEON_CP_ME_RAM_ADDR, 0); | 509 | pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); |
510 | err = IS_ERR(pdev); | ||
511 | if (err) { | ||
512 | printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); | ||
513 | return -EINVAL; | ||
514 | } | ||
491 | if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || | 515 | if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || |
492 | (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || | 516 | (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || |
493 | (rdev->family == CHIP_RS200)) { | 517 | (rdev->family == CHIP_RS200)) { |
494 | DRM_INFO("Loading R100 Microcode\n"); | 518 | DRM_INFO("Loading R100 Microcode\n"); |
495 | for (i = 0; i < 256; i++) { | 519 | fw_name = FIRMWARE_R100; |
496 | WREG32(RADEON_CP_ME_RAM_DATAH, R100_cp_microcode[i][1]); | ||
497 | WREG32(RADEON_CP_ME_RAM_DATAL, R100_cp_microcode[i][0]); | ||
498 | } | ||
499 | } else if ((rdev->family == CHIP_R200) || | 520 | } else if ((rdev->family == CHIP_R200) || |
500 | (rdev->family == CHIP_RV250) || | 521 | (rdev->family == CHIP_RV250) || |
501 | (rdev->family == CHIP_RV280) || | 522 | (rdev->family == CHIP_RV280) || |
502 | (rdev->family == CHIP_RS300)) { | 523 | (rdev->family == CHIP_RS300)) { |
503 | DRM_INFO("Loading R200 Microcode\n"); | 524 | DRM_INFO("Loading R200 Microcode\n"); |
504 | for (i = 0; i < 256; i++) { | 525 | fw_name = FIRMWARE_R200; |
505 | WREG32(RADEON_CP_ME_RAM_DATAH, R200_cp_microcode[i][1]); | ||
506 | WREG32(RADEON_CP_ME_RAM_DATAL, R200_cp_microcode[i][0]); | ||
507 | } | ||
508 | } else if ((rdev->family == CHIP_R300) || | 526 | } else if ((rdev->family == CHIP_R300) || |
509 | (rdev->family == CHIP_R350) || | 527 | (rdev->family == CHIP_R350) || |
510 | (rdev->family == CHIP_RV350) || | 528 | (rdev->family == CHIP_RV350) || |
@@ -512,31 +530,19 @@ static void r100_cp_load_microcode(struct radeon_device *rdev) | |||
512 | (rdev->family == CHIP_RS400) || | 530 | (rdev->family == CHIP_RS400) || |
513 | (rdev->family == CHIP_RS480)) { | 531 | (rdev->family == CHIP_RS480)) { |
514 | DRM_INFO("Loading R300 Microcode\n"); | 532 | DRM_INFO("Loading R300 Microcode\n"); |
515 | for (i = 0; i < 256; i++) { | 533 | fw_name = FIRMWARE_R300; |
516 | WREG32(RADEON_CP_ME_RAM_DATAH, R300_cp_microcode[i][1]); | ||
517 | WREG32(RADEON_CP_ME_RAM_DATAL, R300_cp_microcode[i][0]); | ||
518 | } | ||
519 | } else if ((rdev->family == CHIP_R420) || | 534 | } else if ((rdev->family == CHIP_R420) || |
520 | (rdev->family == CHIP_R423) || | 535 | (rdev->family == CHIP_R423) || |
521 | (rdev->family == CHIP_RV410)) { | 536 | (rdev->family == CHIP_RV410)) { |
522 | DRM_INFO("Loading R400 Microcode\n"); | 537 | DRM_INFO("Loading R400 Microcode\n"); |
523 | for (i = 0; i < 256; i++) { | 538 | fw_name = FIRMWARE_R420; |
524 | WREG32(RADEON_CP_ME_RAM_DATAH, R420_cp_microcode[i][1]); | ||
525 | WREG32(RADEON_CP_ME_RAM_DATAL, R420_cp_microcode[i][0]); | ||
526 | } | ||
527 | } else if ((rdev->family == CHIP_RS690) || | 539 | } else if ((rdev->family == CHIP_RS690) || |
528 | (rdev->family == CHIP_RS740)) { | 540 | (rdev->family == CHIP_RS740)) { |
529 | DRM_INFO("Loading RS690/RS740 Microcode\n"); | 541 | DRM_INFO("Loading RS690/RS740 Microcode\n"); |
530 | for (i = 0; i < 256; i++) { | 542 | fw_name = FIRMWARE_RS690; |
531 | WREG32(RADEON_CP_ME_RAM_DATAH, RS690_cp_microcode[i][1]); | ||
532 | WREG32(RADEON_CP_ME_RAM_DATAL, RS690_cp_microcode[i][0]); | ||
533 | } | ||
534 | } else if (rdev->family == CHIP_RS600) { | 543 | } else if (rdev->family == CHIP_RS600) { |
535 | DRM_INFO("Loading RS600 Microcode\n"); | 544 | DRM_INFO("Loading RS600 Microcode\n"); |
536 | for (i = 0; i < 256; i++) { | 545 | fw_name = FIRMWARE_RS600; |
537 | WREG32(RADEON_CP_ME_RAM_DATAH, RS600_cp_microcode[i][1]); | ||
538 | WREG32(RADEON_CP_ME_RAM_DATAL, RS600_cp_microcode[i][0]); | ||
539 | } | ||
540 | } else if ((rdev->family == CHIP_RV515) || | 546 | } else if ((rdev->family == CHIP_RV515) || |
541 | (rdev->family == CHIP_R520) || | 547 | (rdev->family == CHIP_R520) || |
542 | (rdev->family == CHIP_RV530) || | 548 | (rdev->family == CHIP_RV530) || |
@@ -544,9 +550,43 @@ static void r100_cp_load_microcode(struct radeon_device *rdev) | |||
544 | (rdev->family == CHIP_RV560) || | 550 | (rdev->family == CHIP_RV560) || |
545 | (rdev->family == CHIP_RV570)) { | 551 | (rdev->family == CHIP_RV570)) { |
546 | DRM_INFO("Loading R500 Microcode\n"); | 552 | DRM_INFO("Loading R500 Microcode\n"); |
547 | for (i = 0; i < 256; i++) { | 553 | fw_name = FIRMWARE_R520; |
548 | WREG32(RADEON_CP_ME_RAM_DATAH, R520_cp_microcode[i][1]); | 554 | } |
549 | WREG32(RADEON_CP_ME_RAM_DATAL, R520_cp_microcode[i][0]); | 555 | |
556 | err = request_firmware(&rdev->fw, fw_name, &pdev->dev); | ||
557 | platform_device_unregister(pdev); | ||
558 | if (err) { | ||
559 | printk(KERN_ERR "radeon_cp: Failed to load firmware \"%s\"\n", | ||
560 | fw_name); | ||
561 | } else if (rdev->fw->size % 8) { | ||
562 | printk(KERN_ERR | ||
563 | "radeon_cp: Bogus length %zu in firmware \"%s\"\n", | ||
564 | rdev->fw->size, fw_name); | ||
565 | err = -EINVAL; | ||
566 | release_firmware(rdev->fw); | ||
567 | rdev->fw = NULL; | ||
568 | } | ||
569 | return err; | ||
570 | } | ||
571 | static void r100_cp_load_microcode(struct radeon_device *rdev) | ||
572 | { | ||
573 | const __be32 *fw_data; | ||
574 | int i, size; | ||
575 | |||
576 | if (r100_gui_wait_for_idle(rdev)) { | ||
577 | printk(KERN_WARNING "Failed to wait GUI idle while " | ||
578 | "programming pipes. Bad things might happen.\n"); | ||
579 | } | ||
580 | |||
581 | if (rdev->fw) { | ||
582 | size = rdev->fw->size / 4; | ||
583 | fw_data = (const __be32 *)&rdev->fw->data[0]; | ||
584 | WREG32(RADEON_CP_ME_RAM_ADDR, 0); | ||
585 | for (i = 0; i < size; i += 2) { | ||
586 | WREG32(RADEON_CP_ME_RAM_DATAH, | ||
587 | be32_to_cpup(&fw_data[i])); | ||
588 | WREG32(RADEON_CP_ME_RAM_DATAL, | ||
589 | be32_to_cpup(&fw_data[i + 1])); | ||
550 | } | 590 | } |
551 | } | 591 | } |
552 | } | 592 | } |
@@ -585,6 +625,15 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) | |||
585 | } else { | 625 | } else { |
586 | DRM_INFO("radeon: cp idle (0x%08X)\n", tmp); | 626 | DRM_INFO("radeon: cp idle (0x%08X)\n", tmp); |
587 | } | 627 | } |
628 | |||
629 | if (!rdev->fw) { | ||
630 | r = r100_cp_init_microcode(rdev); | ||
631 | if (r) { | ||
632 | DRM_ERROR("Failed to load firmware!\n"); | ||
633 | return r; | ||
634 | } | ||
635 | } | ||
636 | |||
588 | /* Align ring size */ | 637 | /* Align ring size */ |
589 | rb_bufsz = drm_order(ring_size / 8); | 638 | rb_bufsz = drm_order(ring_size / 8); |
590 | ring_size = (1 << (rb_bufsz + 1)) * 4; | 639 | ring_size = (1 << (rb_bufsz + 1)) * 4; |