.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright 2012 Red Hat |
---|
3 | | - * |
---|
4 | | - * This file is subject to the terms and conditions of the GNU General |
---|
5 | | - * Public License version 2. See the file COPYING in the main |
---|
6 | | - * directory of this archive for more details. |
---|
7 | 4 | * |
---|
8 | 5 | * Authors: Matthew Garrett |
---|
9 | 6 | * Dave Airlie |
---|
10 | 7 | */ |
---|
11 | | -#include <linux/module.h> |
---|
| 8 | + |
---|
12 | 9 | #include <linux/console.h> |
---|
13 | | -#include <drm/drmP.h> |
---|
| 10 | +#include <linux/module.h> |
---|
| 11 | +#include <linux/pci.h> |
---|
| 12 | +#include <linux/vmalloc.h> |
---|
| 13 | + |
---|
| 14 | +#include <drm/drm_drv.h> |
---|
| 15 | +#include <drm/drm_file.h> |
---|
| 16 | +#include <drm/drm_ioctl.h> |
---|
| 17 | +#include <drm/drm_pciids.h> |
---|
14 | 18 | |
---|
15 | 19 | #include "mgag200_drv.h" |
---|
16 | 20 | |
---|
17 | | -#include <drm/drm_pciids.h> |
---|
18 | | - |
---|
19 | | -/* |
---|
20 | | - * This is the generic driver code. This binds the driver to the drm core, |
---|
21 | | - * which then performs further device association and calls our graphics init |
---|
22 | | - * functions |
---|
23 | | - */ |
---|
24 | 21 | int mgag200_modeset = -1; |
---|
25 | | - |
---|
26 | 22 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); |
---|
27 | 23 | module_param_named(modeset, mgag200_modeset, int, 0400); |
---|
28 | 24 | |
---|
29 | | -static struct drm_driver driver; |
---|
| 25 | +/* |
---|
| 26 | + * DRM driver |
---|
| 27 | + */ |
---|
30 | 28 | |
---|
31 | | -static const struct pci_device_id pciidlist[] = { |
---|
32 | | - { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A }, |
---|
| 29 | +DEFINE_DRM_GEM_FOPS(mgag200_driver_fops); |
---|
| 30 | + |
---|
| 31 | +static struct drm_driver mgag200_driver = { |
---|
| 32 | + .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, |
---|
| 33 | + .fops = &mgag200_driver_fops, |
---|
| 34 | + .name = DRIVER_NAME, |
---|
| 35 | + .desc = DRIVER_DESC, |
---|
| 36 | + .date = DRIVER_DATE, |
---|
| 37 | + .major = DRIVER_MAJOR, |
---|
| 38 | + .minor = DRIVER_MINOR, |
---|
| 39 | + .patchlevel = DRIVER_PATCHLEVEL, |
---|
| 40 | + .gem_create_object = drm_gem_shmem_create_object_cached, |
---|
| 41 | + DRM_GEM_SHMEM_DRIVER_OPS, |
---|
| 42 | +}; |
---|
| 43 | + |
---|
| 44 | +/* |
---|
| 45 | + * DRM device |
---|
| 46 | + */ |
---|
| 47 | + |
---|
| 48 | +static bool mgag200_has_sgram(struct mga_device *mdev) |
---|
| 49 | +{ |
---|
| 50 | + struct drm_device *dev = &mdev->base; |
---|
| 51 | + u32 option; |
---|
| 52 | + int ret; |
---|
| 53 | + |
---|
| 54 | + ret = pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option); |
---|
| 55 | + if (drm_WARN(dev, ret, "failed to read PCI config dword: %d\n", ret)) |
---|
| 56 | + return false; |
---|
| 57 | + |
---|
| 58 | + return !!(option & PCI_MGA_OPTION_HARDPWMSK); |
---|
| 59 | +} |
---|
| 60 | + |
---|
| 61 | +static int mgag200_regs_init(struct mga_device *mdev) |
---|
| 62 | +{ |
---|
| 63 | + struct drm_device *dev = &mdev->base; |
---|
| 64 | + u32 option, option2; |
---|
| 65 | + u8 crtcext3; |
---|
| 66 | + |
---|
| 67 | + switch (mdev->type) { |
---|
| 68 | + case G200_PCI: |
---|
| 69 | + case G200_AGP: |
---|
| 70 | + if (mgag200_has_sgram(mdev)) |
---|
| 71 | + option = 0x4049cd21; |
---|
| 72 | + else |
---|
| 73 | + option = 0x40499121; |
---|
| 74 | + option2 = 0x00008000; |
---|
| 75 | + break; |
---|
| 76 | + case G200_SE_A: |
---|
| 77 | + case G200_SE_B: |
---|
| 78 | + option = 0x40049120; |
---|
| 79 | + if (mgag200_has_sgram(mdev)) |
---|
| 80 | + option |= PCI_MGA_OPTION_HARDPWMSK; |
---|
| 81 | + option2 = 0x00008000; |
---|
| 82 | + break; |
---|
| 83 | + case G200_WB: |
---|
| 84 | + case G200_EW3: |
---|
| 85 | + option = 0x41049120; |
---|
| 86 | + option2 = 0x0000b000; |
---|
| 87 | + break; |
---|
| 88 | + case G200_EV: |
---|
| 89 | + option = 0x00000120; |
---|
| 90 | + option2 = 0x0000b000; |
---|
| 91 | + break; |
---|
| 92 | + case G200_EH: |
---|
| 93 | + case G200_EH3: |
---|
| 94 | + option = 0x00000120; |
---|
| 95 | + option2 = 0x0000b000; |
---|
| 96 | + break; |
---|
| 97 | + default: |
---|
| 98 | + option = 0; |
---|
| 99 | + option2 = 0; |
---|
| 100 | + } |
---|
| 101 | + |
---|
| 102 | + if (option) |
---|
| 103 | + pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); |
---|
| 104 | + if (option2) |
---|
| 105 | + pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2); |
---|
| 106 | + |
---|
| 107 | + /* BAR 1 contains registers */ |
---|
| 108 | + mdev->rmmio_base = pci_resource_start(dev->pdev, 1); |
---|
| 109 | + mdev->rmmio_size = pci_resource_len(dev->pdev, 1); |
---|
| 110 | + |
---|
| 111 | + if (!devm_request_mem_region(dev->dev, mdev->rmmio_base, |
---|
| 112 | + mdev->rmmio_size, "mgadrmfb_mmio")) { |
---|
| 113 | + drm_err(dev, "can't reserve mmio registers\n"); |
---|
| 114 | + return -ENOMEM; |
---|
| 115 | + } |
---|
| 116 | + |
---|
| 117 | + mdev->rmmio = pcim_iomap(dev->pdev, 1, 0); |
---|
| 118 | + if (mdev->rmmio == NULL) |
---|
| 119 | + return -ENOMEM; |
---|
| 120 | + |
---|
| 121 | + RREG_ECRT(0x03, crtcext3); |
---|
| 122 | + crtcext3 |= MGAREG_CRTCEXT3_MGAMODE; |
---|
| 123 | + WREG_ECRT(0x03, crtcext3); |
---|
| 124 | + |
---|
| 125 | + return 0; |
---|
| 126 | +} |
---|
| 127 | + |
---|
| 128 | +static void mgag200_g200_interpret_bios(struct mga_device *mdev, |
---|
| 129 | + const unsigned char *bios, |
---|
| 130 | + size_t size) |
---|
| 131 | +{ |
---|
| 132 | + static const char matrox[] = {'M', 'A', 'T', 'R', 'O', 'X'}; |
---|
| 133 | + static const unsigned int expected_length[6] = { |
---|
| 134 | + 0, 64, 64, 64, 128, 128 |
---|
| 135 | + }; |
---|
| 136 | + struct drm_device *dev = &mdev->base; |
---|
| 137 | + const unsigned char *pins; |
---|
| 138 | + unsigned int pins_len, version; |
---|
| 139 | + int offset; |
---|
| 140 | + int tmp; |
---|
| 141 | + |
---|
| 142 | + /* Test for MATROX string. */ |
---|
| 143 | + if (size < 45 + sizeof(matrox)) |
---|
| 144 | + return; |
---|
| 145 | + if (memcmp(&bios[45], matrox, sizeof(matrox)) != 0) |
---|
| 146 | + return; |
---|
| 147 | + |
---|
| 148 | + /* Get the PInS offset. */ |
---|
| 149 | + if (size < MGA_BIOS_OFFSET + 2) |
---|
| 150 | + return; |
---|
| 151 | + offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET]; |
---|
| 152 | + |
---|
| 153 | + /* Get PInS data structure. */ |
---|
| 154 | + |
---|
| 155 | + if (size < offset + 6) |
---|
| 156 | + return; |
---|
| 157 | + pins = bios + offset; |
---|
| 158 | + if (pins[0] == 0x2e && pins[1] == 0x41) { |
---|
| 159 | + version = pins[5]; |
---|
| 160 | + pins_len = pins[2]; |
---|
| 161 | + } else { |
---|
| 162 | + version = 1; |
---|
| 163 | + pins_len = pins[0] + (pins[1] << 8); |
---|
| 164 | + } |
---|
| 165 | + |
---|
| 166 | + if (version < 1 || version > 5) { |
---|
| 167 | + drm_warn(dev, "Unknown BIOS PInS version: %d\n", version); |
---|
| 168 | + return; |
---|
| 169 | + } |
---|
| 170 | + if (pins_len != expected_length[version]) { |
---|
| 171 | + drm_warn(dev, "Unexpected BIOS PInS size: %d expected: %d\n", |
---|
| 172 | + pins_len, expected_length[version]); |
---|
| 173 | + return; |
---|
| 174 | + } |
---|
| 175 | + if (size < offset + pins_len) |
---|
| 176 | + return; |
---|
| 177 | + |
---|
| 178 | + drm_dbg_kms(dev, "MATROX BIOS PInS version %d size: %d found\n", |
---|
| 179 | + version, pins_len); |
---|
| 180 | + |
---|
| 181 | + /* Extract the clock values */ |
---|
| 182 | + |
---|
| 183 | + switch (version) { |
---|
| 184 | + case 1: |
---|
| 185 | + tmp = pins[24] + (pins[25] << 8); |
---|
| 186 | + if (tmp) |
---|
| 187 | + mdev->model.g200.pclk_max = tmp * 10; |
---|
| 188 | + break; |
---|
| 189 | + case 2: |
---|
| 190 | + if (pins[41] != 0xff) |
---|
| 191 | + mdev->model.g200.pclk_max = (pins[41] + 100) * 1000; |
---|
| 192 | + break; |
---|
| 193 | + case 3: |
---|
| 194 | + if (pins[36] != 0xff) |
---|
| 195 | + mdev->model.g200.pclk_max = (pins[36] + 100) * 1000; |
---|
| 196 | + if (pins[52] & 0x20) |
---|
| 197 | + mdev->model.g200.ref_clk = 14318; |
---|
| 198 | + break; |
---|
| 199 | + case 4: |
---|
| 200 | + if (pins[39] != 0xff) |
---|
| 201 | + mdev->model.g200.pclk_max = pins[39] * 4 * 1000; |
---|
| 202 | + if (pins[92] & 0x01) |
---|
| 203 | + mdev->model.g200.ref_clk = 14318; |
---|
| 204 | + break; |
---|
| 205 | + case 5: |
---|
| 206 | + tmp = pins[4] ? 8000 : 6000; |
---|
| 207 | + if (pins[123] != 0xff) |
---|
| 208 | + mdev->model.g200.pclk_min = pins[123] * tmp; |
---|
| 209 | + if (pins[38] != 0xff) |
---|
| 210 | + mdev->model.g200.pclk_max = pins[38] * tmp; |
---|
| 211 | + if (pins[110] & 0x01) |
---|
| 212 | + mdev->model.g200.ref_clk = 14318; |
---|
| 213 | + break; |
---|
| 214 | + default: |
---|
| 215 | + break; |
---|
| 216 | + } |
---|
| 217 | +} |
---|
| 218 | + |
---|
| 219 | +static void mgag200_g200_init_refclk(struct mga_device *mdev) |
---|
| 220 | +{ |
---|
| 221 | + struct drm_device *dev = &mdev->base; |
---|
| 222 | + unsigned char __iomem *rom; |
---|
| 223 | + unsigned char *bios; |
---|
| 224 | + size_t size; |
---|
| 225 | + |
---|
| 226 | + mdev->model.g200.pclk_min = 50000; |
---|
| 227 | + mdev->model.g200.pclk_max = 230000; |
---|
| 228 | + mdev->model.g200.ref_clk = 27050; |
---|
| 229 | + |
---|
| 230 | + rom = pci_map_rom(dev->pdev, &size); |
---|
| 231 | + if (!rom) |
---|
| 232 | + return; |
---|
| 233 | + |
---|
| 234 | + bios = vmalloc(size); |
---|
| 235 | + if (!bios) |
---|
| 236 | + goto out; |
---|
| 237 | + memcpy_fromio(bios, rom, size); |
---|
| 238 | + |
---|
| 239 | + if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa) |
---|
| 240 | + mgag200_g200_interpret_bios(mdev, bios, size); |
---|
| 241 | + |
---|
| 242 | + drm_dbg_kms(dev, "pclk_min: %ld pclk_max: %ld ref_clk: %ld\n", |
---|
| 243 | + mdev->model.g200.pclk_min, mdev->model.g200.pclk_max, |
---|
| 244 | + mdev->model.g200.ref_clk); |
---|
| 245 | + |
---|
| 246 | + vfree(bios); |
---|
| 247 | +out: |
---|
| 248 | + pci_unmap_rom(dev->pdev, rom); |
---|
| 249 | +} |
---|
| 250 | + |
---|
| 251 | +static void mgag200_g200se_init_unique_id(struct mga_device *mdev) |
---|
| 252 | +{ |
---|
| 253 | + struct drm_device *dev = &mdev->base; |
---|
| 254 | + |
---|
| 255 | + /* stash G200 SE model number for later use */ |
---|
| 256 | + mdev->model.g200se.unique_rev_id = RREG32(0x1e24); |
---|
| 257 | + |
---|
| 258 | + drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", |
---|
| 259 | + mdev->model.g200se.unique_rev_id); |
---|
| 260 | +} |
---|
| 261 | + |
---|
| 262 | +static int mgag200_device_init(struct mga_device *mdev, unsigned long flags) |
---|
| 263 | +{ |
---|
| 264 | + struct drm_device *dev = &mdev->base; |
---|
| 265 | + int ret; |
---|
| 266 | + |
---|
| 267 | + mdev->flags = mgag200_flags_from_driver_data(flags); |
---|
| 268 | + mdev->type = mgag200_type_from_driver_data(flags); |
---|
| 269 | + |
---|
| 270 | + ret = mgag200_regs_init(mdev); |
---|
| 271 | + if (ret) |
---|
| 272 | + return ret; |
---|
| 273 | + |
---|
| 274 | + if (mdev->type == G200_PCI || mdev->type == G200_AGP) |
---|
| 275 | + mgag200_g200_init_refclk(mdev); |
---|
| 276 | + else if (IS_G200_SE(mdev)) |
---|
| 277 | + mgag200_g200se_init_unique_id(mdev); |
---|
| 278 | + |
---|
| 279 | + ret = mgag200_mm_init(mdev); |
---|
| 280 | + if (ret) |
---|
| 281 | + return ret; |
---|
| 282 | + |
---|
| 283 | + ret = mgag200_modeset_init(mdev); |
---|
| 284 | + if (ret) { |
---|
| 285 | + drm_err(dev, "Fatal error during modeset init: %d\n", ret); |
---|
| 286 | + return ret; |
---|
| 287 | + } |
---|
| 288 | + |
---|
| 289 | + return 0; |
---|
| 290 | +} |
---|
| 291 | + |
---|
| 292 | +static struct mga_device * |
---|
| 293 | +mgag200_device_create(struct pci_dev *pdev, unsigned long flags) |
---|
| 294 | +{ |
---|
| 295 | + struct drm_device *dev; |
---|
| 296 | + struct mga_device *mdev; |
---|
| 297 | + int ret; |
---|
| 298 | + |
---|
| 299 | + mdev = devm_drm_dev_alloc(&pdev->dev, &mgag200_driver, |
---|
| 300 | + struct mga_device, base); |
---|
| 301 | + if (IS_ERR(mdev)) |
---|
| 302 | + return mdev; |
---|
| 303 | + dev = &mdev->base; |
---|
| 304 | + |
---|
| 305 | + dev->pdev = pdev; |
---|
| 306 | + pci_set_drvdata(pdev, dev); |
---|
| 307 | + |
---|
| 308 | + ret = mgag200_device_init(mdev, flags); |
---|
| 309 | + if (ret) |
---|
| 310 | + return ERR_PTR(ret); |
---|
| 311 | + |
---|
| 312 | + return mdev; |
---|
| 313 | +} |
---|
| 314 | + |
---|
| 315 | +/* |
---|
| 316 | + * PCI driver |
---|
| 317 | + */ |
---|
| 318 | + |
---|
| 319 | +static const struct pci_device_id mgag200_pciidlist[] = { |
---|
| 320 | + { PCI_VENDOR_ID_MATROX, 0x520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_PCI }, |
---|
| 321 | + { PCI_VENDOR_ID_MATROX, 0x521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_AGP }, |
---|
| 322 | + { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
---|
| 323 | + G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD}, |
---|
33 | 324 | { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B }, |
---|
34 | 325 | { PCI_VENDOR_ID_MATROX, 0x530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EV }, |
---|
35 | 326 | { PCI_VENDOR_ID_MATROX, 0x532, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_WB }, |
---|
.. | .. |
---|
40 | 331 | {0,} |
---|
41 | 332 | }; |
---|
42 | 333 | |
---|
43 | | -MODULE_DEVICE_TABLE(pci, pciidlist); |
---|
| 334 | +MODULE_DEVICE_TABLE(pci, mgag200_pciidlist); |
---|
44 | 335 | |
---|
45 | | -static void mgag200_kick_out_firmware_fb(struct pci_dev *pdev) |
---|
| 336 | +static int |
---|
| 337 | +mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
---|
46 | 338 | { |
---|
47 | | - struct apertures_struct *ap; |
---|
48 | | - bool primary = false; |
---|
| 339 | + struct mga_device *mdev; |
---|
| 340 | + struct drm_device *dev; |
---|
| 341 | + int ret; |
---|
49 | 342 | |
---|
50 | | - ap = alloc_apertures(1); |
---|
51 | | - if (!ap) |
---|
52 | | - return; |
---|
| 343 | + drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "mgag200drmfb"); |
---|
53 | 344 | |
---|
54 | | - ap->ranges[0].base = pci_resource_start(pdev, 0); |
---|
55 | | - ap->ranges[0].size = pci_resource_len(pdev, 0); |
---|
| 345 | + ret = pcim_enable_device(pdev); |
---|
| 346 | + if (ret) |
---|
| 347 | + return ret; |
---|
56 | 348 | |
---|
57 | | -#ifdef CONFIG_X86 |
---|
58 | | - primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; |
---|
59 | | -#endif |
---|
60 | | - drm_fb_helper_remove_conflicting_framebuffers(ap, "mgag200drmfb", primary); |
---|
61 | | - kfree(ap); |
---|
| 349 | + mdev = mgag200_device_create(pdev, ent->driver_data); |
---|
| 350 | + if (IS_ERR(mdev)) |
---|
| 351 | + return PTR_ERR(mdev); |
---|
| 352 | + dev = &mdev->base; |
---|
| 353 | + |
---|
| 354 | + ret = drm_dev_register(dev, ent->driver_data); |
---|
| 355 | + if (ret) |
---|
| 356 | + return ret; |
---|
| 357 | + |
---|
| 358 | + drm_fbdev_generic_setup(dev, 0); |
---|
| 359 | + |
---|
| 360 | + return 0; |
---|
62 | 361 | } |
---|
63 | 362 | |
---|
64 | | - |
---|
65 | | -static int mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
---|
66 | | -{ |
---|
67 | | - mgag200_kick_out_firmware_fb(pdev); |
---|
68 | | - |
---|
69 | | - return drm_get_pci_dev(pdev, ent, &driver); |
---|
70 | | -} |
---|
71 | | - |
---|
72 | | -static void mga_pci_remove(struct pci_dev *pdev) |
---|
| 363 | +static void mgag200_pci_remove(struct pci_dev *pdev) |
---|
73 | 364 | { |
---|
74 | 365 | struct drm_device *dev = pci_get_drvdata(pdev); |
---|
75 | 366 | |
---|
76 | | - drm_put_dev(dev); |
---|
| 367 | + drm_dev_unregister(dev); |
---|
77 | 368 | } |
---|
78 | | - |
---|
79 | | -static const struct file_operations mgag200_driver_fops = { |
---|
80 | | - .owner = THIS_MODULE, |
---|
81 | | - .open = drm_open, |
---|
82 | | - .release = drm_release, |
---|
83 | | - .unlocked_ioctl = drm_ioctl, |
---|
84 | | - .mmap = mgag200_mmap, |
---|
85 | | - .poll = drm_poll, |
---|
86 | | - .compat_ioctl = drm_compat_ioctl, |
---|
87 | | - .read = drm_read, |
---|
88 | | -}; |
---|
89 | | - |
---|
90 | | -static struct drm_driver driver = { |
---|
91 | | - .driver_features = DRIVER_GEM | DRIVER_MODESET, |
---|
92 | | - .load = mgag200_driver_load, |
---|
93 | | - .unload = mgag200_driver_unload, |
---|
94 | | - .fops = &mgag200_driver_fops, |
---|
95 | | - .name = DRIVER_NAME, |
---|
96 | | - .desc = DRIVER_DESC, |
---|
97 | | - .date = DRIVER_DATE, |
---|
98 | | - .major = DRIVER_MAJOR, |
---|
99 | | - .minor = DRIVER_MINOR, |
---|
100 | | - .patchlevel = DRIVER_PATCHLEVEL, |
---|
101 | | - |
---|
102 | | - .gem_free_object_unlocked = mgag200_gem_free_object, |
---|
103 | | - .dumb_create = mgag200_dumb_create, |
---|
104 | | - .dumb_map_offset = mgag200_dumb_mmap_offset, |
---|
105 | | -}; |
---|
106 | 369 | |
---|
107 | 370 | static struct pci_driver mgag200_pci_driver = { |
---|
108 | 371 | .name = DRIVER_NAME, |
---|
109 | | - .id_table = pciidlist, |
---|
110 | | - .probe = mga_pci_probe, |
---|
111 | | - .remove = mga_pci_remove, |
---|
| 372 | + .id_table = mgag200_pciidlist, |
---|
| 373 | + .probe = mgag200_pci_probe, |
---|
| 374 | + .remove = mgag200_pci_remove, |
---|
112 | 375 | }; |
---|
113 | 376 | |
---|
114 | 377 | static int __init mgag200_init(void) |
---|