1 1.2 riastrad /* $NetBSD: mga_warp.c,v 1.3 2021/12/18 23:45:32 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad /* mga_warp.c -- Matrox G200/G400 WARP engine management -*- linux-c -*- 4 1.1 riastrad * Created: Thu Jan 11 21:29:32 2001 by gareth (at) valinux.com 5 1.1 riastrad * 6 1.1 riastrad * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 7 1.1 riastrad * All Rights Reserved. 8 1.1 riastrad * 9 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 10 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 11 1.1 riastrad * to deal in the Software without restriction, including without limitation 12 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 14 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 15 1.1 riastrad * 16 1.1 riastrad * The above copyright notice and this permission notice (including the next 17 1.1 riastrad * paragraph) shall be included in all copies or substantial portions of the 18 1.1 riastrad * Software. 19 1.1 riastrad * 20 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 1.1 riastrad * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 1.1 riastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25 1.1 riastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 1.1 riastrad * OTHER DEALINGS IN THE SOFTWARE. 27 1.1 riastrad * 28 1.1 riastrad * Authors: 29 1.1 riastrad * Gareth Hughes <gareth (at) valinux.com> 30 1.1 riastrad */ 31 1.1 riastrad 32 1.2 riastrad #include <sys/cdefs.h> 33 1.2 riastrad __KERNEL_RCSID(0, "$NetBSD: mga_warp.c,v 1.3 2021/12/18 23:45:32 riastradh Exp $"); 34 1.2 riastrad 35 1.1 riastrad #include <linux/firmware.h> 36 1.1 riastrad #include <linux/ihex.h> 37 1.3 riastrad #include <linux/module.h> 38 1.1 riastrad #include <linux/platform_device.h> 39 1.1 riastrad 40 1.1 riastrad #include "mga_drv.h" 41 1.1 riastrad 42 1.1 riastrad #define FIRMWARE_G200 "matrox/g200_warp.fw" 43 1.1 riastrad #define FIRMWARE_G400 "matrox/g400_warp.fw" 44 1.1 riastrad 45 1.1 riastrad MODULE_FIRMWARE(FIRMWARE_G200); 46 1.1 riastrad MODULE_FIRMWARE(FIRMWARE_G400); 47 1.1 riastrad 48 1.1 riastrad #define MGA_WARP_CODE_ALIGN 256 /* in bytes */ 49 1.1 riastrad 50 1.1 riastrad #define WARP_UCODE_SIZE(size) ALIGN(size, MGA_WARP_CODE_ALIGN) 51 1.1 riastrad 52 1.1 riastrad int mga_warp_install_microcode(drm_mga_private_t *dev_priv) 53 1.1 riastrad { 54 1.1 riastrad unsigned char *vcbase = dev_priv->warp->handle; 55 1.1 riastrad unsigned long pcbase = dev_priv->warp->offset; 56 1.1 riastrad const char *firmware_name; 57 1.1 riastrad struct platform_device *pdev; 58 1.1 riastrad const struct firmware *fw = NULL; 59 1.1 riastrad const struct ihex_binrec *rec; 60 1.1 riastrad unsigned int size; 61 1.1 riastrad int n_pipes, where; 62 1.1 riastrad int rc = 0; 63 1.1 riastrad 64 1.1 riastrad switch (dev_priv->chipset) { 65 1.1 riastrad case MGA_CARD_TYPE_G400: 66 1.1 riastrad case MGA_CARD_TYPE_G550: 67 1.1 riastrad firmware_name = FIRMWARE_G400; 68 1.1 riastrad n_pipes = MGA_MAX_G400_PIPES; 69 1.1 riastrad break; 70 1.1 riastrad case MGA_CARD_TYPE_G200: 71 1.1 riastrad firmware_name = FIRMWARE_G200; 72 1.1 riastrad n_pipes = MGA_MAX_G200_PIPES; 73 1.1 riastrad break; 74 1.1 riastrad default: 75 1.1 riastrad return -EINVAL; 76 1.1 riastrad } 77 1.1 riastrad 78 1.1 riastrad pdev = platform_device_register_simple("mga_warp", 0, NULL, 0); 79 1.1 riastrad if (IS_ERR(pdev)) { 80 1.1 riastrad DRM_ERROR("mga: Failed to register microcode\n"); 81 1.1 riastrad return PTR_ERR(pdev); 82 1.1 riastrad } 83 1.1 riastrad rc = request_ihex_firmware(&fw, firmware_name, &pdev->dev); 84 1.1 riastrad platform_device_unregister(pdev); 85 1.1 riastrad if (rc) { 86 1.1 riastrad DRM_ERROR("mga: Failed to load microcode \"%s\"\n", 87 1.1 riastrad firmware_name); 88 1.1 riastrad return rc; 89 1.1 riastrad } 90 1.1 riastrad 91 1.1 riastrad size = 0; 92 1.1 riastrad where = 0; 93 1.1 riastrad for (rec = (const struct ihex_binrec *)fw->data; 94 1.1 riastrad rec; 95 1.1 riastrad rec = ihex_next_binrec(rec)) { 96 1.1 riastrad size += WARP_UCODE_SIZE(be16_to_cpu(rec->len)); 97 1.1 riastrad where++; 98 1.1 riastrad } 99 1.1 riastrad 100 1.1 riastrad if (where != n_pipes) { 101 1.1 riastrad DRM_ERROR("mga: Invalid microcode \"%s\"\n", firmware_name); 102 1.1 riastrad rc = -EINVAL; 103 1.1 riastrad goto out; 104 1.1 riastrad } 105 1.1 riastrad size = PAGE_ALIGN(size); 106 1.1 riastrad DRM_DEBUG("MGA ucode size = %d bytes\n", size); 107 1.1 riastrad if (size > dev_priv->warp->size) { 108 1.1 riastrad DRM_ERROR("microcode too large! (%u > %lu)\n", 109 1.1 riastrad size, dev_priv->warp->size); 110 1.1 riastrad rc = -ENOMEM; 111 1.1 riastrad goto out; 112 1.1 riastrad } 113 1.1 riastrad 114 1.1 riastrad memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys)); 115 1.1 riastrad 116 1.1 riastrad where = 0; 117 1.1 riastrad for (rec = (const struct ihex_binrec *)fw->data; 118 1.1 riastrad rec; 119 1.1 riastrad rec = ihex_next_binrec(rec)) { 120 1.1 riastrad unsigned int src_size, dst_size; 121 1.1 riastrad 122 1.1 riastrad DRM_DEBUG(" pcbase = 0x%08lx vcbase = %p\n", pcbase, vcbase); 123 1.1 riastrad dev_priv->warp_pipe_phys[where] = pcbase; 124 1.1 riastrad src_size = be16_to_cpu(rec->len); 125 1.1 riastrad dst_size = WARP_UCODE_SIZE(src_size); 126 1.1 riastrad memcpy(vcbase, rec->data, src_size); 127 1.1 riastrad pcbase += dst_size; 128 1.1 riastrad vcbase += dst_size; 129 1.1 riastrad where++; 130 1.1 riastrad } 131 1.1 riastrad 132 1.1 riastrad out: 133 1.1 riastrad release_firmware(fw); 134 1.1 riastrad return rc; 135 1.1 riastrad } 136 1.1 riastrad 137 1.1 riastrad #define WMISC_EXPECTED (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE) 138 1.1 riastrad 139 1.1 riastrad int mga_warp_init(drm_mga_private_t *dev_priv) 140 1.1 riastrad { 141 1.1 riastrad u32 wmisc; 142 1.1 riastrad 143 1.1 riastrad /* FIXME: Get rid of these damned magic numbers... 144 1.1 riastrad */ 145 1.1 riastrad switch (dev_priv->chipset) { 146 1.1 riastrad case MGA_CARD_TYPE_G400: 147 1.1 riastrad case MGA_CARD_TYPE_G550: 148 1.1 riastrad MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND); 149 1.1 riastrad MGA_WRITE(MGA_WGETMSB, 0x00000E00); 150 1.1 riastrad MGA_WRITE(MGA_WVRTXSZ, 0x00001807); 151 1.1 riastrad MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000); 152 1.1 riastrad break; 153 1.1 riastrad case MGA_CARD_TYPE_G200: 154 1.1 riastrad MGA_WRITE(MGA_WIADDR, MGA_WMODE_SUSPEND); 155 1.1 riastrad MGA_WRITE(MGA_WGETMSB, 0x1606); 156 1.1 riastrad MGA_WRITE(MGA_WVRTXSZ, 7); 157 1.1 riastrad break; 158 1.1 riastrad default: 159 1.1 riastrad return -EINVAL; 160 1.1 riastrad } 161 1.1 riastrad 162 1.1 riastrad MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE | 163 1.1 riastrad MGA_WMASTER_ENABLE | MGA_WCACHEFLUSH_ENABLE)); 164 1.1 riastrad wmisc = MGA_READ(MGA_WMISC); 165 1.1 riastrad if (wmisc != WMISC_EXPECTED) { 166 1.1 riastrad DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n", 167 1.1 riastrad wmisc, WMISC_EXPECTED); 168 1.1 riastrad return -EINVAL; 169 1.1 riastrad } 170 1.1 riastrad 171 1.1 riastrad return 0; 172 1.1 riastrad } 173