blob: 647a908f362a5796bc78d9105bcb8e96747dd7bd [file] [log] [blame]
Nico Huber518350c2026-06-21 19:45:34 +02001/*
2 * This file is part of the flashprog project.
3 *
4 * Copyright (C) 2026 Nico Huber <nico.h@gmx.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <stddef.h>
18#include <stdint.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include "programmer.h"
23#include "platform/pci.h"
24#include "hwaccess_physmap.h"
25#include "programmer/physmap.h"
26
27#define PCI_VENDOR_ID_MATROX 0x102b
28
29static const struct dev_entry gfx_matrox[] = {
30 {PCI_VENDOR_ID_MATROX, 0x051b, OK, "Matrox Electronics Systems Ltd.", "MGA 2164W [Millennium II]" },
31
32 {0},
33};
34
35static const struct par_master par_master_gfxmatrox = {
36 .chip_readb = mmio_chip_readb,
37 .chip_readw = mmio_chip_readw,
38 .chip_readl = mmio_chip_readl,
39 .chip_readn = mmio_chip_readn,
40 .chip_writeb = mmio_chip_writeb,
41 .chip_writew = mmio_chip_writew,
42 .chip_writel = mmio_chip_writel,
43 .chip_writen = fallback_chip_writen,
44 .map_flash = physmap,
45 .unmap_flash = physunmap,
46};
47
48static int gfxmatrox_init(struct flashprog_programmer *const prog)
49{
50 bool borrow_mmio_bar = false;
51 char *const bar_param = extract_programmer_param("bar");
52 if (bar_param) {
53 if (strcmp(bar_param, "no_gfx_driver_running") != 0) {
54 msg_perr("Error: Unknown argument for `bar' parameter: \"%s\".\n", bar_param);
55 free(bar_param);
56 return 1;
57 }
58 borrow_mmio_bar = true;
59 }
60 free(bar_param);
61
62 struct pci_dev *const matrox = pcidev_init(gfx_matrox, PCI_BASE_ADDRESS_1);
63 if (!matrox)
64 return 1;
65
66 const uint16_t command = pci_read_word(matrox, PCI_COMMAND);
67 if (!(command & PCI_COMMAND_MEMORY)) {
68 msg_perr("Error: PCI memory access is disabled.\n");
69 return 1;
70 }
71
72 /* Enable flash + writes. */
73 const uint32_t option = pci_read_long(matrox, 0x40);
74 rpci_write_long(matrox, 0x40, option | (1 << 30) | (1 << 20));
75
76 uint32_t rom_base = pci_read_long(matrox, PCI_ROM_ADDRESS);
77 if (!rom_base) {
78 if (!borrow_mmio_bar) {
79 msg_perr("Error: PCI ROM base is not configured.\n");
80 msg_perr("We can try to work around this if no graphics driver is running. When no driver\n");
81 msg_perr("is running, confirm this by supplying `-p gfxmatrox:bar=no_gfx_driver_running'.\n");
82 return 1;
83 }
84 /* If the ROM BAR isn't enabled, borrow the MMIO BAR. */
85 rom_base = pcidev_readbar(matrox, PCI_BASE_ADDRESS_1);
86 }
87 rpci_write_long(matrox, PCI_ROM_ADDRESS, rom_base | 1);
88
89 return register_par_master(&par_master_gfxmatrox, BUS_PARALLEL, rom_base & ~1u, 64*KiB, NULL);
90}
91
92const struct programmer_entry programmer_gfxmatrox = {
93 .name = "gfxmatrox",
94 .type = PCI,
95 .devs.dev = gfx_matrox,
96 .init = gfxmatrox_init,
97};