[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#494009: binary firmware in drivers/char/drm/radeon_microcode.h



Here's a patch to radeon to make it use request_firmware.  This is
compile-tested only, but I have hardware I can test on shortly.  The
firmware files can be produced by writing the arrays as 32-bit
little-endian values.  They should be suitable for inclusion in
firmware-nonfree, so I am including a patch for that as well.

Ben.

diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
index ea26dfd..17edd8a 100644
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -35,6 +35,7 @@ config DRM_R128
 config DRM_RADEON
 	tristate "ATI Radeon"
 	depends on DRM && PCI
+	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/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index e53158f..8408e34 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -29,14 +29,14 @@
  *    Gareth Hughes <gareth@valinux.com>
  */
 
+#include <linux/firmware.h>
+
 #include "drmP.h"
 #include "drm.h"
 #include "radeon_drm.h"
 #include "radeon_drv.h"
 #include "r300_reg.h"
 
-#include "radeon_microcode.h"
-
 #define RADEON_FIFO_DEBUG	0
 
 static int radeon_do_cleanup_cp(struct drm_device * dev);
@@ -319,83 +319,71 @@ static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
  * CP control, initialization
  */
 
+static const char *radeon_cp_family_name(drm_radeon_private_t * dev_priv)
+{
+	switch (dev_priv->flags & RADEON_FAMILY_MASK) {
+	case CHIP_R100: case CHIP_RV100: case CHIP_RV200: case CHIP_RS100:
+	case CHIP_RS200:
+		return "R100";
+	case CHIP_R200: case CHIP_RV250: case CHIP_RV280: case CHIP_RS300:
+		return "R200";
+	case CHIP_R300: case CHIP_R350: case CHIP_RV350: case CHIP_RV380:
+	case CHIP_RS480:
+		return "R300";
+	case CHIP_R420: case CHIP_RV410:
+		return "R400";
+	case CHIP_RS690:
+		return "RS690";
+	case CHIP_RV515: case CHIP_R520: case CHIP_RV530: case CHIP_R580:
+	case CHIP_RV560: case CHIP_RV570:
+		return "R500";
+	default:
+		WARN_ON(1); /* new chip needs a name */
+		return "";
+	}
+}
+
 /* Load the microcode for the CP */
 static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
 {
+	const __le32 *microcode;
 	int i;
 	DRM_DEBUG("\n");
 
 	radeon_do_wait_for_idle(dev_priv);
 
+	DRM_INFO("Loading %s Microcode\n", radeon_cp_family_name(dev_priv));
+	microcode = (const __le32 *)dev_priv->microcode->data;
 	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]);
-		}
-	} 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]);
-		}
-	} 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) ||
-		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
-		   ((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]);
-		}
-	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
-		   ((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]);
-		}
-	} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
-		DRM_INFO("Loading RS690 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]);
-		}
-	} 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) ||
-		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R580) ||
-		   ((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++) {
-			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
-				     R520_cp_microcode[i][1]);
-			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
-				     R520_cp_microcode[i][0]);
-		}
+	for (i = 0; i < 256; i++) {
+		RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
+			     le32_to_cpu(microcode[2 * i + 1]));
+		RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
+			     le32_to_cpu(microcode[2 * i + 0]));
 	}
 }
 
+static int radeon_cp_load_microcode_init(struct drm_device *dev,
+					 drm_radeon_private_t *dev_priv)
+{
+	char fw_name[40];
+	int rc;
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_cp_ucode.bin",
+		 radeon_cp_family_name(dev_priv));
+	rc = request_firmware(&dev_priv->microcode, fw_name, &dev->pdev->dev);
+	if (rc)
+		return rc;
+	if (dev_priv->microcode->size != 256 * 8) {
+		release_firmware(dev_priv->microcode);
+		dev_priv->microcode = NULL;
+		return -EINVAL;
+	}
+
+	radeon_cp_load_microcode(dev_priv);
+	return 0;
+}
+
 /* Flush any pending commands to the CP.  This should only be used just
  * prior to a wait for idle, as it informs the engine that the command
  * stream is ending.
@@ -853,6 +841,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
 static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	int rc;
 
 	DRM_DEBUG("\n");
 
@@ -1195,7 +1184,13 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
 		radeon_set_pcigart(dev_priv, 1);
 	}
 
-	radeon_cp_load_microcode(dev_priv);
+	rc = radeon_cp_load_microcode_init(dev, dev_priv);
+	if (rc) {
+		DRM_ERROR("failed to load microcode\n");
+		radeon_do_cleanup_cp(dev);
+		return rc;
+	}
+
 	radeon_cp_init_ring_buffer(dev, dev_priv);
 
 	dev_priv->last_buf = 0;
@@ -1218,6 +1213,11 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
 	if (dev->irq_enabled)
 		drm_irq_uninstall(dev);
 
+	if (dev_priv->microcode) {
+		release_firmware(dev_priv->microcode);
+		dev_priv->microcode = NULL;
+	}
+
 #if __OS_HAS_AGP
 	if (dev_priv->flags & RADEON_IS_AGP) {
 		if (dev_priv->cp_ring != NULL) {
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index 349ac3d..3414109 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -124,3 +124,9 @@ module_exit(radeon_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL and additional rights");
+MODULE_FIRMWARE("radeon/R100_cp_ucode.bin");
+MODULE_FIRMWARE("radeon/R200_cp_ucode.bin");
+MODULE_FIRMWARE("radeon/R300_cp_ucode.bin");
+MODULE_FIRMWARE("radeon/R400_cp_ucode.bin");
+MODULE_FIRMWARE("radeon/R500_cp_ucode.bin");
+MODULE_FIRMWARE("radeon/RS690_cp_ucode.bin");
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 3f0eca9..1f2c329 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -244,6 +244,7 @@ typedef struct drm_radeon_private {
 	int usec_timeout;
 
 	int microcode_version;
+	const struct firmware *microcode;
 
 	struct {
 		u32 boxes;
--- END ---

Patch for firmware-nonfree:

Index: defines
===================================================================
--- defines	(revision 12301)
+++ defines	(working copy)
@@ -1,5 +1,6 @@
 [base]
 packages:
+ ati
  bnx2
  iwlwifi
  qlogic
Index: ati/LICENSE
===================================================================
--- ati/LICENSE	(revision 0)
+++ ati/LICENSE	(revision 0)
@@ -0,0 +1,21 @@
+Copyright 2007 Advanced Micro Devices, Inc.
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: ati/defines
===================================================================
--- ati/defines	(revision 0)
+++ ati/defines	(revision 0)
@@ -0,0 +1,29 @@
+[base]
+desc: ATI Radeon graphics cards
+files:
+ radeon/R100_cp_ucode.bin
+ radeon/R200_cp_ucode.bin
+ radeon/R300_cp_ucode.bin
+ radeon/R400_cp_ucode.bin
+ radeon/R500_cp_ucode.bin
+ radeon/RS690_cp_ucode.bin
+longdesc: ATI Radeon graphics cards supported by the radeon driver
+uri: http://ftp.debian.org/debian/pool/non-free/f/firmware-nonfree
+
+[R100_cp_ucode.bin_base]
+desc: ATI Radeon R100-family CP microcode
+
+[R200_cp_ucode.bin_base]
+desc: ATI Radeon R200-family CP microcode
+
+[R300_cp_ucode.bin_base]
+desc: ATI Radeon R300-family CP microcode
+
+[R400_cp_ucode.bin_base]
+desc: ATI Radeon R400-family CP microcode
+
+[R500_cp_ucode.bin_base]
+desc: ATI Radeon R500-family CP microcode
+
+[RS690_cp_ucode.bin_base]
+desc: ATI Radeon RS690 CP microcode
--- END ---

Attachment: signature.asc
Description: This is a digitally signed message part


Reply to: