Back to home page

OSCL-LXR

 
 

    


0001 /* mga_warp.c -- Matrox G200/G400 WARP engine management -*- linux-c -*-
0002  * Created: Thu Jan 11 21:29:32 2001 by gareth@valinux.com
0003  *
0004  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
0005  * All Rights Reserved.
0006  *
0007  * Permission is hereby granted, free of charge, to any person obtaining a
0008  * copy of this software and associated documentation files (the "Software"),
0009  * to deal in the Software without restriction, including without limitation
0010  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0011  * and/or sell copies of the Software, and to permit persons to whom the
0012  * Software is furnished to do so, subject to the following conditions:
0013  *
0014  * The above copyright notice and this permission notice (including the next
0015  * paragraph) shall be included in all copies or substantial portions of the
0016  * Software.
0017  *
0018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0019  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0020  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0021  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
0022  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0023  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0024  * OTHER DEALINGS IN THE SOFTWARE.
0025  *
0026  * Authors:
0027  *    Gareth Hughes <gareth@valinux.com>
0028  */
0029 
0030 #include <linux/firmware.h>
0031 #include <linux/ihex.h>
0032 #include <linux/module.h>
0033 #include <linux/platform_device.h>
0034 
0035 #include "mga_drv.h"
0036 
0037 #define FIRMWARE_G200 "matrox/g200_warp.fw"
0038 #define FIRMWARE_G400 "matrox/g400_warp.fw"
0039 
0040 MODULE_FIRMWARE(FIRMWARE_G200);
0041 MODULE_FIRMWARE(FIRMWARE_G400);
0042 
0043 #define MGA_WARP_CODE_ALIGN     256 /* in bytes */
0044 
0045 #define WARP_UCODE_SIZE(size)       ALIGN(size, MGA_WARP_CODE_ALIGN)
0046 
0047 int mga_warp_install_microcode(drm_mga_private_t *dev_priv)
0048 {
0049     unsigned char *vcbase = dev_priv->warp->handle;
0050     unsigned long pcbase = dev_priv->warp->offset;
0051     const char *firmware_name;
0052     struct platform_device *pdev;
0053     const struct firmware *fw = NULL;
0054     const struct ihex_binrec *rec;
0055     unsigned int size;
0056     int n_pipes, where;
0057     int rc = 0;
0058 
0059     switch (dev_priv->chipset) {
0060     case MGA_CARD_TYPE_G400:
0061     case MGA_CARD_TYPE_G550:
0062         firmware_name = FIRMWARE_G400;
0063         n_pipes = MGA_MAX_G400_PIPES;
0064         break;
0065     case MGA_CARD_TYPE_G200:
0066         firmware_name = FIRMWARE_G200;
0067         n_pipes = MGA_MAX_G200_PIPES;
0068         break;
0069     default:
0070         return -EINVAL;
0071     }
0072 
0073     pdev = platform_device_register_simple("mga_warp", 0, NULL, 0);
0074     if (IS_ERR(pdev)) {
0075         DRM_ERROR("mga: Failed to register microcode\n");
0076         return PTR_ERR(pdev);
0077     }
0078     rc = request_ihex_firmware(&fw, firmware_name, &pdev->dev);
0079     platform_device_unregister(pdev);
0080     if (rc) {
0081         DRM_ERROR("mga: Failed to load microcode \"%s\"\n",
0082               firmware_name);
0083         return rc;
0084     }
0085 
0086     size = 0;
0087     where = 0;
0088     for (rec = (const struct ihex_binrec *)fw->data;
0089          rec;
0090          rec = ihex_next_binrec(rec)) {
0091         size += WARP_UCODE_SIZE(be16_to_cpu(rec->len));
0092         where++;
0093     }
0094 
0095     if (where != n_pipes) {
0096         DRM_ERROR("mga: Invalid microcode \"%s\"\n", firmware_name);
0097         rc = -EINVAL;
0098         goto out;
0099     }
0100     size = PAGE_ALIGN(size);
0101     DRM_DEBUG("MGA ucode size = %d bytes\n", size);
0102     if (size > dev_priv->warp->size) {
0103         DRM_ERROR("microcode too large! (%u > %lu)\n",
0104               size, dev_priv->warp->size);
0105         rc = -ENOMEM;
0106         goto out;
0107     }
0108 
0109     memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
0110 
0111     where = 0;
0112     for (rec = (const struct ihex_binrec *)fw->data;
0113          rec;
0114          rec = ihex_next_binrec(rec)) {
0115         unsigned int src_size, dst_size;
0116 
0117         DRM_DEBUG(" pcbase = 0x%08lx  vcbase = %p\n", pcbase, vcbase);
0118         dev_priv->warp_pipe_phys[where] = pcbase;
0119         src_size = be16_to_cpu(rec->len);
0120         dst_size = WARP_UCODE_SIZE(src_size);
0121         memcpy(vcbase, rec->data, src_size);
0122         pcbase += dst_size;
0123         vcbase += dst_size;
0124         where++;
0125     }
0126 
0127 out:
0128     release_firmware(fw);
0129     return rc;
0130 }
0131 
0132 #define WMISC_EXPECTED      (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE)
0133 
0134 int mga_warp_init(drm_mga_private_t *dev_priv)
0135 {
0136     u32 wmisc;
0137 
0138     /* FIXME: Get rid of these damned magic numbers...
0139      */
0140     switch (dev_priv->chipset) {
0141     case MGA_CARD_TYPE_G400:
0142     case MGA_CARD_TYPE_G550:
0143         MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND);
0144         MGA_WRITE(MGA_WGETMSB, 0x00000E00);
0145         MGA_WRITE(MGA_WVRTXSZ, 0x00001807);
0146         MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000);
0147         break;
0148     case MGA_CARD_TYPE_G200:
0149         MGA_WRITE(MGA_WIADDR, MGA_WMODE_SUSPEND);
0150         MGA_WRITE(MGA_WGETMSB, 0x1606);
0151         MGA_WRITE(MGA_WVRTXSZ, 7);
0152         break;
0153     default:
0154         return -EINVAL;
0155     }
0156 
0157     MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE |
0158                   MGA_WMASTER_ENABLE | MGA_WCACHEFLUSH_ENABLE));
0159     wmisc = MGA_READ(MGA_WMISC);
0160     if (wmisc != WMISC_EXPECTED) {
0161         DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n",
0162               wmisc, WMISC_EXPECTED);
0163         return -EINVAL;
0164     }
0165 
0166     return 0;
0167 }