240 lines
7.9 KiB
Diff
240 lines
7.9 KiB
Diff
From 3e3f2f1f9514969b9df1b64a9a12a7a5a1aa7550 Mon Sep 17 00:00:00 2001
|
|
From: Ben Hutchings <ben@decadent.org.uk>
|
|
Date: Wed, 15 Oct 2008 01:29:35 +0100
|
|
Subject: [PATCH 06/24] radeon: Use request_firmware() to load CP microcode
|
|
|
|
Tested on Radeon 7500 (RV200) with and without firmware installed.
|
|
---
|
|
drivers/gpu/drm/Kconfig | 2 +-
|
|
drivers/gpu/drm/radeon/radeon_cp.c | 115 +++++++++++++++++++++++------------
|
|
drivers/gpu/drm/radeon/radeon_drv.h | 6 ++
|
|
3 files changed, 83 insertions(+), 40 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
|
|
index a93d249..09ed655 100644
|
|
--- a/drivers/gpu/drm/Kconfig
|
|
+++ b/drivers/gpu/drm/Kconfig
|
|
@@ -35,7 +35,7 @@ config DRM_R128
|
|
config DRM_RADEON
|
|
tristate "ATI Radeon"
|
|
depends on DRM && PCI
|
|
- depends on BROKEN
|
|
+ select FW_LOADER
|
|
help
|
|
Choose this option if you have an ATI Radeon graphics card. There
|
|
are both PCI and AGP versions. You don't need to choose this to
|
|
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
|
|
index dcebb4b..a460149 100644
|
|
--- a/drivers/gpu/drm/radeon/radeon_cp.c
|
|
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
|
|
@@ -35,10 +35,23 @@
|
|
#include "radeon_drv.h"
|
|
#include "r300_reg.h"
|
|
|
|
-#include "radeon_microcode.h"
|
|
-
|
|
#define RADEON_FIFO_DEBUG 0
|
|
|
|
+/* Firmware Names */
|
|
+#define FIRMWARE_R100 "radeon/R100_cp.bin"
|
|
+#define FIRMWARE_R200 "radeon/R200_cp.bin"
|
|
+#define FIRMWARE_R300 "radeon/R300_cp.bin"
|
|
+#define FIRMWARE_R420 "radeon/R420_cp.bin"
|
|
+#define FIRMWARE_RS690 "radeon/RS690_cp.bin"
|
|
+#define FIRMWARE_R520 "radeon/R520_cp.bin"
|
|
+
|
|
+MODULE_FIRMWARE(FIRMWARE_R100);
|
|
+MODULE_FIRMWARE(FIRMWARE_R200);
|
|
+MODULE_FIRMWARE(FIRMWARE_R300);
|
|
+MODULE_FIRMWARE(FIRMWARE_R420);
|
|
+MODULE_FIRMWARE(FIRMWARE_RS690);
|
|
+MODULE_FIRMWARE(FIRMWARE_R520);
|
|
+
|
|
static int radeon_do_cleanup_cp(struct drm_device * dev);
|
|
static void radeon_do_cp_start(drm_radeon_private_t * dev_priv);
|
|
|
|
@@ -318,37 +331,34 @@ static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
|
|
*/
|
|
|
|
/* Load the microcode for the CP */
|
|
-static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
|
|
+static int radeon_cp_init_microcode(drm_radeon_private_t *dev_priv)
|
|
{
|
|
- int i;
|
|
+ struct platform_device *pdev;
|
|
+ const char *fw_name = NULL;
|
|
+ int err;
|
|
+
|
|
DRM_DEBUG("\n");
|
|
|
|
- radeon_do_wait_for_idle(dev_priv);
|
|
+ pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
|
|
+ err = IS_ERR(pdev);
|
|
+ if (err) {
|
|
+ printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_ADDR, 0);
|
|
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R100) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV100) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV200) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS100) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS200)) {
|
|
DRM_INFO("Loading R100 Microcode\n");
|
|
- for (i = 0; i < 256; i++) {
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
|
|
- R100_cp_microcode[i][1]);
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
|
|
- R100_cp_microcode[i][0]);
|
|
- }
|
|
+ fw_name = FIRMWARE_R100;
|
|
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R200) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV250) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV280) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS300)) {
|
|
DRM_INFO("Loading R200 Microcode\n");
|
|
- for (i = 0; i < 256; i++) {
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
|
|
- R200_cp_microcode[i][1]);
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
|
|
- R200_cp_microcode[i][0]);
|
|
- }
|
|
+ fw_name = FIRMWARE_R200;
|
|
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) ||
|
|
@@ -356,31 +366,16 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
|
|
DRM_INFO("Loading R300 Microcode\n");
|
|
- for (i = 0; i < 256; i++) {
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
|
|
- R300_cp_microcode[i][1]);
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
|
|
- R300_cp_microcode[i][0]);
|
|
- }
|
|
+ fw_name = FIRMWARE_R300;
|
|
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R423) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV410)) {
|
|
DRM_INFO("Loading R400 Microcode\n");
|
|
- for (i = 0; i < 256; i++) {
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
|
|
- R420_cp_microcode[i][1]);
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
|
|
- R420_cp_microcode[i][0]);
|
|
- }
|
|
+ fw_name = FIRMWARE_R420;
|
|
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
|
|
DRM_INFO("Loading RS690/RS740 Microcode\n");
|
|
- for (i = 0; i < 256; i++) {
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
|
|
- RS690_cp_microcode[i][1]);
|
|
- RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
|
|
- RS690_cp_microcode[i][0]);
|
|
- }
|
|
+ fw_name = FIRMWARE_RS690;
|
|
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) ||
|
|
@@ -388,11 +383,41 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV560) ||
|
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV570)) {
|
|
DRM_INFO("Loading R500 Microcode\n");
|
|
- for (i = 0; i < 256; i++) {
|
|
+ fw_name = FIRMWARE_R520;
|
|
+ }
|
|
+
|
|
+ err = request_firmware(&dev_priv->fw, fw_name, &pdev->dev);
|
|
+ platform_device_unregister(pdev);
|
|
+ if (err) {
|
|
+ printk(KERN_ERR "radeon_cp: Failed to load firmware \"%s\"\n",
|
|
+ fw_name);
|
|
+ } else if (dev_priv->fw->size % 8) {
|
|
+ printk(KERN_ERR
|
|
+ "radeon_cp: Bogus length %zu in firmware \"%s\"\n",
|
|
+ dev_priv->fw->size, fw_name);
|
|
+ err = -EINVAL;
|
|
+ release_firmware(dev_priv->fw);
|
|
+ dev_priv->fw = NULL;
|
|
+ }
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static void radeon_cp_load_microcode(drm_radeon_private_t *dev_priv)
|
|
+{
|
|
+ const __be32 *fw_data;
|
|
+ int i, size;
|
|
+
|
|
+ radeon_do_wait_for_idle(dev_priv);
|
|
+
|
|
+ if (dev_priv->fw) {
|
|
+ size = dev_priv->fw->size / 4;
|
|
+ fw_data = (const __be32 *)&dev_priv->fw->data[0];
|
|
+ RADEON_WRITE(RADEON_CP_ME_RAM_ADDR, 0);
|
|
+ for (i = 0; i < size; i += 2) {
|
|
RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
|
|
- R520_cp_microcode[i][1]);
|
|
+ be32_to_cpup(&fw_data[i]));
|
|
RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
|
|
- R520_cp_microcode[i][0]);
|
|
+ be32_to_cpup(&fw_data[i + 1]));
|
|
}
|
|
}
|
|
}
|
|
@@ -1216,6 +1241,14 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
|
|
radeon_set_pcigart(dev_priv, 1);
|
|
}
|
|
|
|
+ if (!dev_priv->fw) {
|
|
+ int err = radeon_cp_init_microcode(dev_priv);
|
|
+ if (err) {
|
|
+ DRM_ERROR("Failed to load firmware!\n");
|
|
+ radeon_do_cleanup_cp(dev);
|
|
+ return err;
|
|
+ }
|
|
+ }
|
|
radeon_cp_load_microcode(dev_priv);
|
|
radeon_cp_init_ring_buffer(dev, dev_priv);
|
|
|
|
@@ -1442,6 +1475,10 @@ void radeon_do_release(struct drm_device * dev)
|
|
|
|
/* deallocate kernel resources */
|
|
radeon_do_cleanup_cp(dev);
|
|
+ if (dev_priv->fw) {
|
|
+ release_firmware(dev_priv->fw);
|
|
+ dev_priv->fw = NULL;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
|
|
index 3bbb871..51984d7 100644
|
|
--- a/drivers/gpu/drm/radeon/radeon_drv.h
|
|
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
|
|
@@ -31,6 +31,9 @@
|
|
#ifndef __RADEON_DRV_H__
|
|
#define __RADEON_DRV_H__
|
|
|
|
+#include <linux/firmware.h>
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
/* General customization:
|
|
*/
|
|
|
|
@@ -317,6 +320,9 @@ typedef struct drm_radeon_private {
|
|
int num_gb_pipes;
|
|
int track_flush;
|
|
drm_local_map_t *mmio;
|
|
+
|
|
+ /* firmware */
|
|
+ const struct firmware *fw;
|
|
} drm_radeon_private_t;
|
|
|
|
typedef struct drm_radeon_buf_priv {
|
|
--
|
|
1.6.1.3
|
|
|