| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | *  linux/drivers/ide/legacy/gayle.c -- Amiga Gayle IDE Driver | 
|  | 3 | * | 
|  | 4 | *     Created 9 Jul 1997 by Geert Uytterhoeven | 
|  | 5 | * | 
|  | 6 | *  This file is subject to the terms and conditions of the GNU General Public | 
|  | 7 | *  License.  See the file COPYING in the main directory of this archive for | 
|  | 8 | *  more details. | 
|  | 9 | */ | 
|  | 10 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 11 | #include <linux/types.h> | 
|  | 12 | #include <linux/mm.h> | 
|  | 13 | #include <linux/interrupt.h> | 
|  | 14 | #include <linux/blkdev.h> | 
|  | 15 | #include <linux/hdreg.h> | 
|  | 16 | #include <linux/ide.h> | 
|  | 17 | #include <linux/init.h> | 
|  | 18 | #include <linux/zorro.h> | 
|  | 19 |  | 
|  | 20 | #include <asm/setup.h> | 
|  | 21 | #include <asm/amigahw.h> | 
|  | 22 | #include <asm/amigaints.h> | 
|  | 23 | #include <asm/amigayle.h> | 
|  | 24 |  | 
|  | 25 |  | 
|  | 26 | /* | 
|  | 27 | *  Bases of the IDE interfaces | 
|  | 28 | */ | 
|  | 29 |  | 
|  | 30 | #define GAYLE_BASE_4000	0xdd2020	/* A4000/A4000T */ | 
|  | 31 | #define GAYLE_BASE_1200	0xda0000	/* A1200/A600 and E-Matrix 530 */ | 
|  | 32 |  | 
|  | 33 | /* | 
|  | 34 | *  Offsets from one of the above bases | 
|  | 35 | */ | 
|  | 36 |  | 
|  | 37 | #define GAYLE_DATA	0x00 | 
|  | 38 | #define GAYLE_ERROR	0x06		/* see err-bits */ | 
|  | 39 | #define GAYLE_NSECTOR	0x0a		/* nr of sectors to read/write */ | 
|  | 40 | #define GAYLE_SECTOR	0x0e		/* starting sector */ | 
|  | 41 | #define GAYLE_LCYL	0x12		/* starting cylinder */ | 
|  | 42 | #define GAYLE_HCYL	0x16		/* high byte of starting cyl */ | 
|  | 43 | #define GAYLE_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */ | 
|  | 44 | #define GAYLE_STATUS	0x1e		/* see status-bits */ | 
|  | 45 | #define GAYLE_CONTROL	0x101a | 
|  | 46 |  | 
|  | 47 | static int gayle_offsets[IDE_NR_PORTS] __initdata = { | 
|  | 48 | GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL, | 
|  | 49 | GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1 | 
|  | 50 | }; | 
|  | 51 |  | 
|  | 52 |  | 
|  | 53 | /* | 
|  | 54 | *  These are at different offsets from the base | 
|  | 55 | */ | 
|  | 56 |  | 
|  | 57 | #define GAYLE_IRQ_4000	0xdd3020	/* MSB = 1, Harddisk is source of */ | 
|  | 58 | #define GAYLE_IRQ_1200	0xda9000	/* interrupt */ | 
|  | 59 |  | 
|  | 60 |  | 
|  | 61 | /* | 
|  | 62 | *  Offset of the secondary port for IDE doublers | 
|  | 63 | *  Note that GAYLE_CONTROL is NOT available then! | 
|  | 64 | */ | 
|  | 65 |  | 
|  | 66 | #define GAYLE_NEXT_PORT	0x1000 | 
|  | 67 |  | 
|  | 68 | #ifndef CONFIG_BLK_DEV_IDEDOUBLER | 
|  | 69 | #define GAYLE_NUM_HWIFS		1 | 
|  | 70 | #define GAYLE_NUM_PROBE_HWIFS	GAYLE_NUM_HWIFS | 
|  | 71 | #define GAYLE_HAS_CONTROL_REG	1 | 
|  | 72 | #define GAYLE_IDEREG_SIZE	0x2000 | 
|  | 73 | #else /* CONFIG_BLK_DEV_IDEDOUBLER */ | 
|  | 74 | #define GAYLE_NUM_HWIFS		2 | 
|  | 75 | #define GAYLE_NUM_PROBE_HWIFS	(ide_doubler ? GAYLE_NUM_HWIFS : \ | 
|  | 76 | GAYLE_NUM_HWIFS-1) | 
|  | 77 | #define GAYLE_HAS_CONTROL_REG	(!ide_doubler) | 
|  | 78 | #define GAYLE_IDEREG_SIZE	(ide_doubler ? 0x1000 : 0x2000) | 
|  | 79 | int ide_doubler = 0;	/* support IDE doublers? */ | 
|  | 80 | #endif /* CONFIG_BLK_DEV_IDEDOUBLER */ | 
|  | 81 |  | 
|  | 82 |  | 
|  | 83 | /* | 
|  | 84 | *  Check and acknowledge the interrupt status | 
|  | 85 | */ | 
|  | 86 |  | 
|  | 87 | static int gayle_ack_intr_a4000(ide_hwif_t *hwif) | 
|  | 88 | { | 
|  | 89 | unsigned char ch; | 
|  | 90 |  | 
|  | 91 | ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]); | 
|  | 92 | if (!(ch & GAYLE_IRQ_IDE)) | 
|  | 93 | return 0; | 
|  | 94 | return 1; | 
|  | 95 | } | 
|  | 96 |  | 
|  | 97 | static int gayle_ack_intr_a1200(ide_hwif_t *hwif) | 
|  | 98 | { | 
|  | 99 | unsigned char ch; | 
|  | 100 |  | 
|  | 101 | ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]); | 
|  | 102 | if (!(ch & GAYLE_IRQ_IDE)) | 
|  | 103 | return 0; | 
|  | 104 | (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]); | 
|  | 105 | z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]); | 
|  | 106 | return 1; | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | /* | 
|  | 110 | *  Probe for a Gayle IDE interface (and optionally for an IDE doubler) | 
|  | 111 | */ | 
|  | 112 |  | 
|  | 113 | void __init gayle_init(void) | 
|  | 114 | { | 
|  | 115 | int a4000, i; | 
|  | 116 |  | 
|  | 117 | if (!MACH_IS_AMIGA) | 
|  | 118 | return; | 
|  | 119 |  | 
|  | 120 | if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE)) | 
|  | 121 | goto found; | 
|  | 122 |  | 
|  | 123 | #ifdef CONFIG_ZORRO | 
|  | 124 | if (zorro_find_device(ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE, | 
|  | 125 | NULL)) | 
|  | 126 | goto found; | 
|  | 127 | #endif | 
|  | 128 | return; | 
|  | 129 |  | 
|  | 130 | found: | 
|  | 131 | for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) { | 
|  | 132 | unsigned long base, ctrlport, irqport; | 
|  | 133 | ide_ack_intr_t *ack_intr; | 
|  | 134 | hw_regs_t hw; | 
|  | 135 | ide_hwif_t *hwif; | 
|  | 136 | int index; | 
|  | 137 | unsigned long phys_base, res_start, res_n; | 
|  | 138 |  | 
|  | 139 | if (a4000) { | 
|  | 140 | phys_base = GAYLE_BASE_4000; | 
|  | 141 | irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_4000); | 
|  | 142 | ack_intr = gayle_ack_intr_a4000; | 
|  | 143 | } else { | 
|  | 144 | phys_base = GAYLE_BASE_1200; | 
|  | 145 | irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200); | 
|  | 146 | ack_intr = gayle_ack_intr_a1200; | 
|  | 147 | } | 
|  | 148 | /* | 
|  | 149 | * FIXME: we now have selectable modes between mmio v/s iomio | 
|  | 150 | */ | 
|  | 151 |  | 
|  | 152 | phys_base += i*GAYLE_NEXT_PORT; | 
|  | 153 |  | 
|  | 154 | res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1); | 
|  | 155 | res_n = GAYLE_IDEREG_SIZE; | 
|  | 156 |  | 
|  | 157 | if (!request_mem_region(res_start, res_n, "IDE")) | 
|  | 158 | continue; | 
|  | 159 |  | 
|  | 160 | base = (unsigned long)ZTWO_VADDR(phys_base); | 
|  | 161 | ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0; | 
|  | 162 |  | 
|  | 163 | ide_setup_ports(&hw, base, gayle_offsets, | 
|  | 164 | ctrlport, irqport, ack_intr, | 
|  | 165 | //			&gayle_iops, | 
|  | 166 | IRQ_AMIGA_PORTS); | 
|  | 167 |  | 
|  | 168 | index = ide_register_hw(&hw, &hwif); | 
|  | 169 | if (index != -1) { | 
|  | 170 | hwif->mmio = 2; | 
|  | 171 | switch (i) { | 
|  | 172 | case 0: | 
|  | 173 | printk("ide%d: Gayle IDE interface (A%d style)\n", index, | 
|  | 174 | a4000 ? 4000 : 1200); | 
|  | 175 | break; | 
|  | 176 | #ifdef CONFIG_BLK_DEV_IDEDOUBLER | 
|  | 177 | case 1: | 
|  | 178 | printk("ide%d: IDE doubler\n", index); | 
|  | 179 | break; | 
|  | 180 | #endif /* CONFIG_BLK_DEV_IDEDOUBLER */ | 
|  | 181 | } | 
|  | 182 | } else | 
|  | 183 | release_mem_region(res_start, res_n); | 
|  | 184 | } | 
|  | 185 | } |