gayle.c 4.27 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2
 *  Amiga Gayle IDE Driver
Linus Torvalds's avatar
Linus Torvalds committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 *     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/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/zorro.h>
Adrian Bunk's avatar
Adrian Bunk committed
18
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32

#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 */

33 34
#define GAYLE_IDEREG_SIZE	0x2000

Linus Torvalds's avatar
Linus Torvalds committed
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
    /*
     *  Offsets from one of the above bases
     */

#define GAYLE_CONTROL	0x101a

    /*
     *  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

#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)
Adrian Bunk's avatar
Adrian Bunk committed
60

61
static int ide_doubler;
62 63
module_param_named(doubler, ide_doubler, bool, 0);
MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
Linus Torvalds's avatar
Linus Torvalds committed
64 65 66 67 68

    /*
     *  Check and acknowledge the interrupt status
     */

69
static int gayle_test_irq(ide_hwif_t *hwif)
Linus Torvalds's avatar
Linus Torvalds committed
70 71 72
{
    unsigned char ch;

73
    ch = z_readb(hwif->io_ports.irq_addr);
Linus Torvalds's avatar
Linus Torvalds committed
74 75 76 77 78
    if (!(ch & GAYLE_IRQ_IDE))
	return 0;
    return 1;
}

79
static void gayle_a1200_clear_irq(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
80
{
81
    ide_hwif_t *hwif = drive->hwif;
Linus Torvalds's avatar
Linus Torvalds committed
82

83 84
    (void)z_readb(hwif->io_ports.status_addr);
    z_writeb(0x7c, hwif->io_ports.irq_addr);
Linus Torvalds's avatar
Linus Torvalds committed
85 86
}

87
static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base,
88
				     unsigned long ctl, unsigned long irq_port)
89 90 91 92 93
{
	int i;

	memset(hw, 0, sizeof(*hw));

94
	hw->io_ports.data_addr = base;
95 96

	for (i = 1; i < 8; i++)
97
		hw->io_ports_array[i] = base + 2 + i * 4;
98

99 100
	hw->io_ports.ctl_addr = ctl;
	hw->io_ports.irq_addr = irq_port;
101 102 103 104

	hw->irq = IRQ_AMIGA_PORTS;
}

105 106 107 108
static const struct ide_port_ops gayle_a4000_port_ops = {
	.test_irq		= gayle_test_irq,
};

109 110
static const struct ide_port_ops gayle_a1200_port_ops = {
	.clear_irq		= gayle_a1200_clear_irq,
111
	.test_irq		= gayle_test_irq,
112 113
};

114
static const struct ide_port_info gayle_port_info = {
115 116
	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
				  IDE_HFLAG_NO_DMA,
117
	.irq_flags		= IRQF_SHARED,
118
	.chipset		= ide_generic,
119 120
};

Linus Torvalds's avatar
Linus Torvalds committed
121 122 123 124
    /*
     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
     */

125
static int __init gayle_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
126
{
127 128
    unsigned long phys_base, res_start, res_n;
    unsigned long base, ctrlport, irqport;
129
    int a4000, i, rc;
130
    struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
131
    struct ide_port_info d = gayle_port_info;
Linus Torvalds's avatar
Linus Torvalds committed
132 133

    if (!MACH_IS_AMIGA)
134
	return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
135 136 137 138 139 140 141 142 143

    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
144
    return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
145 146

found:
147 148
	printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
			 a4000 ? 4000 : 1200,
149
			 ide_doubler ? ", IDE doubler" : "");
150

Linus Torvalds's avatar
Linus Torvalds committed
151 152 153
	if (a4000) {
	    phys_base = GAYLE_BASE_4000;
	    irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_4000);
154
	    d.port_ops = &gayle_a4000_port_ops;
Linus Torvalds's avatar
Linus Torvalds committed
155 156 157
	} else {
	    phys_base = GAYLE_BASE_1200;
	    irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200);
158
	    d.port_ops = &gayle_a1200_port_ops;
Linus Torvalds's avatar
Linus Torvalds committed
159 160 161 162 163 164
	}

	res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
	res_n = GAYLE_IDEREG_SIZE;

	if (!request_mem_region(res_start, res_n, "IDE"))
165
		return -EBUSY;
Linus Torvalds's avatar
Linus Torvalds committed
166

167 168
    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
	base = (unsigned long)ZTWO_VADDR(phys_base + i * GAYLE_NEXT_PORT);
Linus Torvalds's avatar
Linus Torvalds committed
169 170
	ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;

171
	gayle_setup_ports(&hw[i], base, ctrlport, irqport);
Linus Torvalds's avatar
Linus Torvalds committed
172

173
	hws[i] = &hw[i];
Linus Torvalds's avatar
Linus Torvalds committed
174
    }
175

176
    rc = ide_host_add(&d, hws, i, NULL);
177 178 179 180
    if (rc)
	release_mem_region(res_start, res_n);

    return rc;
Linus Torvalds's avatar
Linus Torvalds committed
181
}
182 183

module_init(gayle_init);
184 185

MODULE_LICENSE("GPL");