xref: /kernel/linux/linux-5.10/drivers/ide/buddha.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  Amiga Buddha, Catweasel and X-Surf IDE Driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *  This driver was written based on the specifications in README.buddha and
78c2ecf20Sopenharmony_ci *  the X-Surf info from Inside_XSurf.txt available at
88c2ecf20Sopenharmony_ci *  http://www.jschoenfeld.com
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  This file is subject to the terms and conditions of the GNU General Public
118c2ecf20Sopenharmony_ci *  License.  See the file COPYING in the main directory of this archive for
128c2ecf20Sopenharmony_ci *  more details.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *  TODO:
158c2ecf20Sopenharmony_ci *    - test it :-)
168c2ecf20Sopenharmony_ci *    - tune the timings using the speed-register
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/types.h>
208c2ecf20Sopenharmony_ci#include <linux/mm.h>
218c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
228c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
238c2ecf20Sopenharmony_ci#include <linux/zorro.h>
248c2ecf20Sopenharmony_ci#include <linux/ide.h>
258c2ecf20Sopenharmony_ci#include <linux/init.h>
268c2ecf20Sopenharmony_ci#include <linux/module.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <asm/amigahw.h>
298c2ecf20Sopenharmony_ci#include <asm/amigaints.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci    /*
338c2ecf20Sopenharmony_ci     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
348c2ecf20Sopenharmony_ci     */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define BUDDHA_NUM_HWIFS	2
378c2ecf20Sopenharmony_ci#define CATWEASEL_NUM_HWIFS	3
388c2ecf20Sopenharmony_ci#define XSURF_NUM_HWIFS         2
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define MAX_NUM_HWIFS		3
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci    /*
438c2ecf20Sopenharmony_ci     *  Bases of the IDE interfaces (relative to the board address)
448c2ecf20Sopenharmony_ci     */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define BUDDHA_BASE1	0x800
478c2ecf20Sopenharmony_ci#define BUDDHA_BASE2	0xa00
488c2ecf20Sopenharmony_ci#define BUDDHA_BASE3	0xc00
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define XSURF_BASE1     0xb000 /* 2.5" Interface */
518c2ecf20Sopenharmony_ci#define XSURF_BASE2     0xd000 /* 3.5" Interface */
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
548c2ecf20Sopenharmony_ci    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
588c2ecf20Sopenharmony_ci     XSURF_BASE1, XSURF_BASE2
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci    /*
628c2ecf20Sopenharmony_ci     *  Offsets from one of the above bases
638c2ecf20Sopenharmony_ci     */
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define BUDDHA_CONTROL	0x11a
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci    /*
688c2ecf20Sopenharmony_ci     *  Other registers
698c2ecf20Sopenharmony_ci     */
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
728c2ecf20Sopenharmony_ci#define BUDDHA_IRQ2	0xf40		/* interrupt */
738c2ecf20Sopenharmony_ci#define BUDDHA_IRQ3	0xf80
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define XSURF_IRQ1      0x7e
768c2ecf20Sopenharmony_ci#define XSURF_IRQ2      0x7e
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
798c2ecf20Sopenharmony_ci    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
808c2ecf20Sopenharmony_ci};
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
838c2ecf20Sopenharmony_ci    XSURF_IRQ1, XSURF_IRQ2
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci    /*
908c2ecf20Sopenharmony_ci     *  Board information
918c2ecf20Sopenharmony_ci     */
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_citypedef enum BuddhaType_Enum {
948c2ecf20Sopenharmony_ci    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
958c2ecf20Sopenharmony_ci} BuddhaType;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci    /*
1008c2ecf20Sopenharmony_ci     *  Check and acknowledge the interrupt status
1018c2ecf20Sopenharmony_ci     */
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int buddha_test_irq(ide_hwif_t *hwif)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci    unsigned char ch;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci    ch = z_readb(hwif->io_ports.irq_addr);
1088c2ecf20Sopenharmony_ci    if (!(ch & 0x80))
1098c2ecf20Sopenharmony_ci	    return 0;
1108c2ecf20Sopenharmony_ci    return 1;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic void xsurf_clear_irq(ide_drive_t *drive)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci    /*
1168c2ecf20Sopenharmony_ci     * X-Surf needs 0 written to IRQ register to ensure ISA bit A11 stays at 0
1178c2ecf20Sopenharmony_ci     */
1188c2ecf20Sopenharmony_ci    z_writeb(0, drive->hwif->io_ports.irq_addr);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base,
1228c2ecf20Sopenharmony_ci				      unsigned long ctl, unsigned long irq_port)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	int i;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	memset(hw, 0, sizeof(*hw));
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	hw->io_ports.data_addr = base;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	for (i = 1; i < 8; i++)
1318c2ecf20Sopenharmony_ci		hw->io_ports_array[i] = base + 2 + i * 4;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	hw->io_ports.ctl_addr = ctl;
1348c2ecf20Sopenharmony_ci	hw->io_ports.irq_addr = irq_port;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	hw->irq = IRQ_AMIGA_PORTS;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic const struct ide_port_ops buddha_port_ops = {
1408c2ecf20Sopenharmony_ci	.test_irq		= buddha_test_irq,
1418c2ecf20Sopenharmony_ci};
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic const struct ide_port_ops xsurf_port_ops = {
1448c2ecf20Sopenharmony_ci	.clear_irq		= xsurf_clear_irq,
1458c2ecf20Sopenharmony_ci	.test_irq		= buddha_test_irq,
1468c2ecf20Sopenharmony_ci};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic const struct ide_port_info buddha_port_info = {
1498c2ecf20Sopenharmony_ci	.port_ops		= &buddha_port_ops,
1508c2ecf20Sopenharmony_ci	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
1518c2ecf20Sopenharmony_ci	.irq_flags		= IRQF_SHARED,
1528c2ecf20Sopenharmony_ci	.chipset		= ide_generic,
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci    /*
1568c2ecf20Sopenharmony_ci     *  Probe for a Buddha or Catweasel IDE interface
1578c2ecf20Sopenharmony_ci     */
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int __init buddha_init(void)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct zorro_dev *z = NULL;
1628c2ecf20Sopenharmony_ci	u_long buddha_board = 0;
1638c2ecf20Sopenharmony_ci	BuddhaType type;
1648c2ecf20Sopenharmony_ci	int buddha_num_hwifs, i;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
1678c2ecf20Sopenharmony_ci		unsigned long board;
1688c2ecf20Sopenharmony_ci		struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS];
1698c2ecf20Sopenharmony_ci		struct ide_port_info d = buddha_port_info;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
1728c2ecf20Sopenharmony_ci			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
1738c2ecf20Sopenharmony_ci			type=BOARD_BUDDHA;
1748c2ecf20Sopenharmony_ci		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
1758c2ecf20Sopenharmony_ci			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
1768c2ecf20Sopenharmony_ci			type=BOARD_CATWEASEL;
1778c2ecf20Sopenharmony_ci		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
1788c2ecf20Sopenharmony_ci			buddha_num_hwifs = XSURF_NUM_HWIFS;
1798c2ecf20Sopenharmony_ci			type=BOARD_XSURF;
1808c2ecf20Sopenharmony_ci			d.port_ops = &xsurf_port_ops;
1818c2ecf20Sopenharmony_ci		} else
1828c2ecf20Sopenharmony_ci			continue;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		board = z->resource.start;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		if(type != BOARD_XSURF) {
1878c2ecf20Sopenharmony_ci			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
1888c2ecf20Sopenharmony_ci				continue;
1898c2ecf20Sopenharmony_ci		} else {
1908c2ecf20Sopenharmony_ci			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
1918c2ecf20Sopenharmony_ci				continue;
1928c2ecf20Sopenharmony_ci			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
1938c2ecf20Sopenharmony_ci				goto fail_base2;
1948c2ecf20Sopenharmony_ci			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
1958c2ecf20Sopenharmony_ci				release_mem_region(board+XSURF_BASE2, 0x1000);
1968c2ecf20Sopenharmony_cifail_base2:
1978c2ecf20Sopenharmony_ci				release_mem_region(board+XSURF_BASE1, 0x1000);
1988c2ecf20Sopenharmony_ci				continue;
1998c2ecf20Sopenharmony_ci			}
2008c2ecf20Sopenharmony_ci		}
2018c2ecf20Sopenharmony_ci		buddha_board = (unsigned long)ZTWO_VADDR(board);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
2048c2ecf20Sopenharmony_ci		/* X-Surf doesn't have this.  IRQs are always on */
2058c2ecf20Sopenharmony_ci		if (type != BOARD_XSURF)
2068c2ecf20Sopenharmony_ci			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		printk(KERN_INFO "ide: %s IDE controller\n",
2098c2ecf20Sopenharmony_ci				 buddha_board_name[type]);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		for (i = 0; i < buddha_num_hwifs; i++) {
2128c2ecf20Sopenharmony_ci			unsigned long base, ctl, irq_port;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci			if (type != BOARD_XSURF) {
2158c2ecf20Sopenharmony_ci				base = buddha_board + buddha_bases[i];
2168c2ecf20Sopenharmony_ci				ctl = base + BUDDHA_CONTROL;
2178c2ecf20Sopenharmony_ci				irq_port = buddha_board + buddha_irqports[i];
2188c2ecf20Sopenharmony_ci			} else {
2198c2ecf20Sopenharmony_ci				base = buddha_board + xsurf_bases[i];
2208c2ecf20Sopenharmony_ci				/* X-Surf has no CS1* (Control/AltStat) */
2218c2ecf20Sopenharmony_ci				ctl = 0;
2228c2ecf20Sopenharmony_ci				irq_port = buddha_board + xsurf_irqports[i];
2238c2ecf20Sopenharmony_ci			}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci			buddha_setup_ports(&hw[i], base, ctl, irq_port);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci			hws[i] = &hw[i];
2288c2ecf20Sopenharmony_ci		}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		ide_host_add(&d, hws, i, NULL);
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return 0;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cimodule_init(buddha_init);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
239