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