commit 61114ee8e98e86b3160d547b6dbe7ec7bac445f5 Author: Ben Hutchings Date: Wed Oct 15 01:29:35 2008 +0100 radeon: Use request_firmware() to load CP microcode Tested on Radeon 7500 (RV200) with and without firmware installed. diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig index 3b0dd6a..17edd8a 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/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/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index e53158f..2670dd3 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/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 u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) @@ -320,66 +333,48 @@ 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) || ((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]); - } + fw_name = FIRMWARE_R300; } 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]); - } + fw_name = FIRMWARE_R420; } 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]); - } + 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) || @@ -387,11 +382,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])); } } } @@ -1195,6 +1220,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); @@ -1421,6 +1454,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/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 3f0eca9..5cc808e 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -31,6 +31,9 @@ #ifndef __RADEON_DRV_H__ #define __RADEON_DRV_H__ +#include +#include + /* General customization: */ @@ -311,6 +314,9 @@ typedef struct drm_radeon_private { unsigned long fb_aper_offset; int num_gb_pipes; + + /* firmware */ + const struct firmware *fw; } drm_radeon_private_t; typedef struct drm_radeon_buf_priv {