gayle.c 4.5 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *  Amiga Gayle IDE Driver
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 *     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/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/zorro.h>
A
Adrian Bunk 已提交
19
#include <linux/module.h>
L
Linus Torvalds 已提交
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

#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_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

#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)
A
Adrian Bunk 已提交
66

67
static int ide_doubler;
68 69
module_param_named(doubler, ide_doubler, bool, 0);
MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
L
Linus Torvalds 已提交
70 71 72 73 74 75 76 77 78 79 80
#endif /* CONFIG_BLK_DEV_IDEDOUBLER */


    /*
     *  Check and acknowledge the interrupt status
     */

static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
{
    unsigned char ch;

81
    ch = z_readb(hwif->io_ports.irq_addr);
L
Linus Torvalds 已提交
82 83 84 85 86 87 88 89 90
    if (!(ch & GAYLE_IRQ_IDE))
	return 0;
    return 1;
}

static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
{
    unsigned char ch;

91
    ch = z_readb(hwif->io_ports.irq_addr);
L
Linus Torvalds 已提交
92 93
    if (!(ch & GAYLE_IRQ_IDE))
	return 0;
94 95
    (void)z_readb(hwif->io_ports.status_addr);
    z_writeb(0x7c, hwif->io_ports.irq_addr);
L
Linus Torvalds 已提交
96 97 98
    return 1;
}

99 100
static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
				     unsigned long ctl, unsigned long irq_port,
101
				     ide_ack_intr_t *ack_intr)
102 103 104 105 106
{
	int i;

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

107
	hw->io_ports.data_addr = base;
108 109

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

112 113
	hw->io_ports.ctl_addr = ctl;
	hw->io_ports.irq_addr = irq_port;
114 115 116

	hw->irq = IRQ_AMIGA_PORTS;
	hw->ack_intr = ack_intr;
117 118

	hw->chipset = ide_generic;
119 120
}

L
Linus Torvalds 已提交
121 122 123 124
    /*
     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
     */

125
static int __init gayle_init(void)
L
Linus Torvalds 已提交
126 127
{
    int a4000, i;
128
    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
L
Linus Torvalds 已提交
129 130

    if (!MACH_IS_AMIGA)
131
	return -ENODEV;
L
Linus Torvalds 已提交
132 133 134 135 136 137 138 139 140

    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
141
    return -ENODEV;
L
Linus Torvalds 已提交
142 143

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

L
Linus Torvalds 已提交
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
    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;
	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;

182
	gayle_setup_ports(&hw, base, ctrlport, irqport, ack_intr);
L
Linus Torvalds 已提交
183

184
	hwif = ide_find_port();
185 186 187 188 189
	if (hwif) {
	    u8 index = hwif->index;

	    ide_init_port_hw(hwif, &hw);

190
	    idx[i] = index;
L
Linus Torvalds 已提交
191 192 193
	} else
	    release_mem_region(res_start, res_n);
    }
194

195
    ide_device_add(idx, NULL);
196 197

    return 0;
L
Linus Torvalds 已提交
198
}
199 200

module_init(gayle_init);
201 202

MODULE_LICENSE("GPL");