scsilsi: Introduce new programmer driver for LSI SCSI adapters

Supports up to 1MiB parallel flash, but needs external address buffers
and is usually set up for less.

Datasheet used:
https://theretroweb.com/chip/documentation/lsi53c875-data-sheet-4-1-66a3b3913650d154581810.pdf

Change-Id: I23291ae7c98ddd5cab48f96aa5e6a69788796d9b
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/529
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/scsilsi.c b/scsilsi.c
new file mode 100644
index 0000000..c6885f3
--- /dev/null
+++ b/scsilsi.c
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the flashprog project.
+ *
+ * Copyright (C) 2026 Nico Huber <nico.h@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "programmer.h"
+#include "platform/pci.h"
+#include "hwaccess_physmap.h"
+#include "programmer/physmap.h"
+
+#define PCI_VENDOR_ID_LSI	0x1000
+
+static const struct dev_entry scsi_lsi[] = {
+	{PCI_VENDOR_ID_LSI, 0x000f, OK, "LSI", "53c875" },
+
+	{0},
+};
+
+static const struct par_master par_master_scsilsi = {
+	.chip_readb	= mmio_chip_readb,
+	.chip_readw	= mmio_chip_readw,
+	.chip_readl	= mmio_chip_readl,
+	.chip_readn	= mmio_chip_readn,
+	.chip_writeb	= mmio_chip_writeb,
+	.chip_writew	= mmio_chip_writew,
+	.chip_writel	= mmio_chip_writel,
+	.chip_writen	= fallback_chip_writen,
+	.map_flash	= physmap,
+	.unmap_flash	= physunmap,
+};
+
+static int scsilsi_init(struct flashprog_programmer *const prog)
+{
+	struct pci_dev *const lsi = pcidev_init(scsi_lsi, PCI_BASE_ADDRESS_1);
+	if (!lsi)
+		return 1;
+
+	const uint16_t command = pci_read_word(lsi, PCI_COMMAND);
+	if (!(command & PCI_COMMAND_MEMORY)) {
+		msg_perr("Error: PCI memory access is disabled.\n");
+		return 1;
+	}
+
+	const uint32_t rom_base = pci_read_long(lsi, PCI_ROM_ADDRESS);
+	if (!rom_base) {
+		msg_perr("Error: PCI ROM base is not configured.\n");
+		return 1;
+	}
+	rpci_write_long(lsi, PCI_ROM_ADDRESS, rom_base | 1);
+
+	/* TODO: Use ROM BAR size detection. */
+
+	return register_par_master(&par_master_scsilsi, BUS_PARALLEL, rom_base & ~1u, 1*MiB, NULL);
+}
+
+const struct programmer_entry programmer_scsilsi = {
+	.name			= "scsilsi",
+	.type			= PCI,
+	.devs.dev		= scsi_lsi,
+	.init			= scsilsi_init,
+};