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