Commit ece2be79 authored by Ben Hutchings's avatar Ben Hutchings Committed by Dave Airlie

drm/mga: Use request_firmware() to load microcode

Image format is IHEX, one record for each pipe in order (record
addresses are ignored).
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent c9c97b8c
...@@ -116,6 +116,7 @@ endchoice ...@@ -116,6 +116,7 @@ endchoice
config DRM_MGA config DRM_MGA
tristate "Matrox g200/g400" tristate "Matrox g200/g400"
depends on DRM depends on DRM
select FW_LOADER
help help
Choose this option if you have a Matrox G200, G400 or G450 graphics Choose this option if you have a Matrox G200, G400 or G450 graphics
card. If M is selected, the module will be called mga. AGP card. If M is selected, the module will be called mga. AGP
......
...@@ -444,7 +444,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev, ...@@ -444,7 +444,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
{ {
drm_mga_private_t *const dev_priv = drm_mga_private_t *const dev_priv =
(drm_mga_private_t *) dev->dev_private; (drm_mga_private_t *) dev->dev_private;
unsigned int warp_size = mga_warp_microcode_size(dev_priv); unsigned int warp_size = MGA_WARP_UCODE_SIZE;
int err; int err;
unsigned offset; unsigned offset;
const unsigned secondary_size = dma_bs->secondary_bin_count const unsigned secondary_size = dma_bs->secondary_bin_count
...@@ -619,7 +619,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev, ...@@ -619,7 +619,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
{ {
drm_mga_private_t *const dev_priv = drm_mga_private_t *const dev_priv =
(drm_mga_private_t *) dev->dev_private; (drm_mga_private_t *) dev->dev_private;
unsigned int warp_size = mga_warp_microcode_size(dev_priv); unsigned int warp_size = MGA_WARP_UCODE_SIZE;
unsigned int primary_size; unsigned int primary_size;
unsigned int bin_count; unsigned int bin_count;
int err; int err;
......
...@@ -177,7 +177,6 @@ extern void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv); ...@@ -177,7 +177,6 @@ extern void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv);
extern int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf); extern int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf);
/* mga_warp.c */ /* mga_warp.c */
extern unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv);
extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
extern int mga_warp_init(drm_mga_private_t * dev_priv); extern int mga_warp_init(drm_mga_private_t * dev_priv);
......
This diff is collapsed.
...@@ -27,132 +27,108 @@ ...@@ -27,132 +27,108 @@
* Gareth Hughes <gareth@valinux.com> * Gareth Hughes <gareth@valinux.com>
*/ */
#include <linux/firmware.h>
#include <linux/ihex.h>
#include <linux/platform_device.h>
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
#include "mga_drm.h" #include "mga_drm.h"
#include "mga_drv.h" #include "mga_drv.h"
#include "mga_ucode.h"
#define FIRMWARE_G200 "matrox/g200_warp.fw"
#define FIRMWARE_G400 "matrox/g400_warp.fw"
MODULE_FIRMWARE(FIRMWARE_G200);
MODULE_FIRMWARE(FIRMWARE_G400);
#define MGA_WARP_CODE_ALIGN 256 /* in bytes */ #define MGA_WARP_CODE_ALIGN 256 /* in bytes */
#define WARP_UCODE_SIZE( which ) \ #define WARP_UCODE_SIZE(size) ALIGN(size, MGA_WARP_CODE_ALIGN)
((sizeof(which) / MGA_WARP_CODE_ALIGN + 1) * MGA_WARP_CODE_ALIGN)
int mga_warp_install_microcode(drm_mga_private_t * dev_priv)
#define WARP_UCODE_INSTALL( which, where ) \
do { \
DRM_DEBUG( " pcbase = 0x%08lx vcbase = %p\n", pcbase, vcbase );\
dev_priv->warp_pipe_phys[where] = pcbase; \
memcpy( vcbase, which, sizeof(which) ); \
pcbase += WARP_UCODE_SIZE( which ); \
vcbase += WARP_UCODE_SIZE( which ); \
} while (0)
static const unsigned int mga_warp_g400_microcode_size =
(WARP_UCODE_SIZE(warp_g400_tgz) +
WARP_UCODE_SIZE(warp_g400_tgza) +
WARP_UCODE_SIZE(warp_g400_tgzaf) +
WARP_UCODE_SIZE(warp_g400_tgzf) +
WARP_UCODE_SIZE(warp_g400_tgzs) +
WARP_UCODE_SIZE(warp_g400_tgzsa) +
WARP_UCODE_SIZE(warp_g400_tgzsaf) +
WARP_UCODE_SIZE(warp_g400_tgzsf) +
WARP_UCODE_SIZE(warp_g400_t2gz) +
WARP_UCODE_SIZE(warp_g400_t2gza) +
WARP_UCODE_SIZE(warp_g400_t2gzaf) +
WARP_UCODE_SIZE(warp_g400_t2gzf) +
WARP_UCODE_SIZE(warp_g400_t2gzs) +
WARP_UCODE_SIZE(warp_g400_t2gzsa) +
WARP_UCODE_SIZE(warp_g400_t2gzsaf) + WARP_UCODE_SIZE(warp_g400_t2gzsf));
static const unsigned int mga_warp_g200_microcode_size =
(WARP_UCODE_SIZE(warp_g200_tgz) +
WARP_UCODE_SIZE(warp_g200_tgza) +
WARP_UCODE_SIZE(warp_g200_tgzaf) +
WARP_UCODE_SIZE(warp_g200_tgzf) +
WARP_UCODE_SIZE(warp_g200_tgzs) +
WARP_UCODE_SIZE(warp_g200_tgzsa) +
WARP_UCODE_SIZE(warp_g200_tgzsaf) + WARP_UCODE_SIZE(warp_g200_tgzsf));
unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv)
{ {
unsigned char *vcbase = dev_priv->warp->handle;
unsigned long pcbase = dev_priv->warp->offset;
const char *firmware_name;
struct platform_device *pdev;
const struct firmware *fw = NULL;
const struct ihex_binrec *rec;
unsigned int size;
int n_pipes, where;
int rc = 0;
switch (dev_priv->chipset) { switch (dev_priv->chipset) {
case MGA_CARD_TYPE_G400: case MGA_CARD_TYPE_G400:
case MGA_CARD_TYPE_G550: case MGA_CARD_TYPE_G550:
return PAGE_ALIGN(mga_warp_g400_microcode_size); firmware_name = FIRMWARE_G400;
n_pipes = MGA_MAX_G400_PIPES;
break;
case MGA_CARD_TYPE_G200: case MGA_CARD_TYPE_G200:
return PAGE_ALIGN(mga_warp_g200_microcode_size); firmware_name = FIRMWARE_G200;
n_pipes = MGA_MAX_G200_PIPES;
break;
default: default:
return 0; return -EINVAL;
} }
}
static int mga_warp_install_g400_microcode(drm_mga_private_t * dev_priv)
{
unsigned char *vcbase = dev_priv->warp->handle;
unsigned long pcbase = dev_priv->warp->offset;
memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
WARP_UCODE_INSTALL(warp_g400_tgz, MGA_WARP_TGZ);
WARP_UCODE_INSTALL(warp_g400_tgzf, MGA_WARP_TGZF);
WARP_UCODE_INSTALL(warp_g400_tgza, MGA_WARP_TGZA);
WARP_UCODE_INSTALL(warp_g400_tgzaf, MGA_WARP_TGZAF);
WARP_UCODE_INSTALL(warp_g400_tgzs, MGA_WARP_TGZS);
WARP_UCODE_INSTALL(warp_g400_tgzsf, MGA_WARP_TGZSF);
WARP_UCODE_INSTALL(warp_g400_tgzsa, MGA_WARP_TGZSA);
WARP_UCODE_INSTALL(warp_g400_tgzsaf, MGA_WARP_TGZSAF);
WARP_UCODE_INSTALL(warp_g400_t2gz, MGA_WARP_T2GZ);
WARP_UCODE_INSTALL(warp_g400_t2gzf, MGA_WARP_T2GZF);
WARP_UCODE_INSTALL(warp_g400_t2gza, MGA_WARP_T2GZA);
WARP_UCODE_INSTALL(warp_g400_t2gzaf, MGA_WARP_T2GZAF);
WARP_UCODE_INSTALL(warp_g400_t2gzs, MGA_WARP_T2GZS);
WARP_UCODE_INSTALL(warp_g400_t2gzsf, MGA_WARP_T2GZSF);
WARP_UCODE_INSTALL(warp_g400_t2gzsa, MGA_WARP_T2GZSA);
WARP_UCODE_INSTALL(warp_g400_t2gzsaf, MGA_WARP_T2GZSAF);
return 0;
}
static int mga_warp_install_g200_microcode(drm_mga_private_t * dev_priv) pdev = platform_device_register_simple("mga_warp", 0, NULL, 0);
{ if (IS_ERR(pdev)) {
unsigned char *vcbase = dev_priv->warp->handle; DRM_ERROR("mga: Failed to register microcode\n");
unsigned long pcbase = dev_priv->warp->offset; return PTR_ERR(pdev);
}
memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys)); rc = request_ihex_firmware(&fw, firmware_name, &pdev->dev);
platform_device_unregister(pdev);
WARP_UCODE_INSTALL(warp_g200_tgz, MGA_WARP_TGZ); if (rc) {
WARP_UCODE_INSTALL(warp_g200_tgzf, MGA_WARP_TGZF); DRM_ERROR("mga: Failed to load microcode \"%s\"\n",
WARP_UCODE_INSTALL(warp_g200_tgza, MGA_WARP_TGZA); firmware_name);
WARP_UCODE_INSTALL(warp_g200_tgzaf, MGA_WARP_TGZAF); return rc;
WARP_UCODE_INSTALL(warp_g200_tgzs, MGA_WARP_TGZS); }
WARP_UCODE_INSTALL(warp_g200_tgzsf, MGA_WARP_TGZSF);
WARP_UCODE_INSTALL(warp_g200_tgzsa, MGA_WARP_TGZSA);
WARP_UCODE_INSTALL(warp_g200_tgzsaf, MGA_WARP_TGZSAF);
return 0;
}
int mga_warp_install_microcode(drm_mga_private_t * dev_priv) size = 0;
{ where = 0;
const unsigned int size = mga_warp_microcode_size(dev_priv); for (rec = (const struct ihex_binrec *)fw->data;
rec;
rec = ihex_next_binrec(rec)) {
size += WARP_UCODE_SIZE(be16_to_cpu(rec->len));
where++;
}
if (where != n_pipes) {
DRM_ERROR("mga: Invalid microcode \"%s\"\n", firmware_name);
rc = -EINVAL;
goto out;
}
size = PAGE_ALIGN(size);
DRM_DEBUG("MGA ucode size = %d bytes\n", size); DRM_DEBUG("MGA ucode size = %d bytes\n", size);
if (size > dev_priv->warp->size) { if (size > dev_priv->warp->size) {
DRM_ERROR("microcode too large! (%u > %lu)\n", DRM_ERROR("microcode too large! (%u > %lu)\n",
size, dev_priv->warp->size); size, dev_priv->warp->size);
return -ENOMEM; rc = -ENOMEM;
goto out;
} }
switch (dev_priv->chipset) { memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
case MGA_CARD_TYPE_G400:
case MGA_CARD_TYPE_G550: where = 0;
return mga_warp_install_g400_microcode(dev_priv); for (rec = (const struct ihex_binrec *)fw->data;
case MGA_CARD_TYPE_G200: rec;
return mga_warp_install_g200_microcode(dev_priv); rec = ihex_next_binrec(rec)) {
default: unsigned int src_size, dst_size;
return -EINVAL;
DRM_DEBUG(" pcbase = 0x%08lx vcbase = %p\n", pcbase, vcbase);
dev_priv->warp_pipe_phys[where] = pcbase;
src_size = be16_to_cpu(rec->len);
dst_size = WARP_UCODE_SIZE(src_size);
memcpy(vcbase, rec->data, src_size);
pcbase += dst_size;
vcbase += dst_size;
where++;
} }
out:
release_firmware(fw);
return rc;
} }
#define WMISC_EXPECTED (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE) #define WMISC_EXPECTED (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE)
......
...@@ -42,6 +42,7 @@ fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin ...@@ -42,6 +42,7 @@ fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \ fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
cxgb3/t3c_psram-1.1.0.bin \ cxgb3/t3c_psram-1.1.0.bin \
cxgb3/t3fw-7.4.0.bin cxgb3/t3fw-7.4.0.bin
fw-shipped-$(CONFIG_DRM_MGA) += matrox/g200_warp.fw matrox/g400_warp.fw
fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin
fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \ fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \
......
...@@ -698,3 +698,35 @@ Found in hex form in kernel source, with the following comment: ...@@ -698,3 +698,35 @@ Found in hex form in kernel source, with the following comment:
Copyright (c) 1998-2002 by Paul Davis <pbd@op.net> Copyright (c) 1998-2002 by Paul Davis <pbd@op.net>
-------------------------------------------------------------------------- --------------------------------------------------------------------------
Driver: mga - Matrox G200/G400/G550
File: matrox/g200_warp.fw
File: matrox/g400_warp.fw
Licence:
Copyright 1999 Matrox Graphics 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 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
MATROX GRAPHICS INC., OR ANY OTHER CONTRIBUTORS 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.
Found in hex form in kernel source.
--------------------------------------------------------------------------
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment