linux/drivers/ide/gayle.c
<<
>>
Prefs
   1/*
   2 *  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
  11#include <linux/types.h>
  12#include <linux/mm.h>
  13#include <linux/interrupt.h>
  14#include <linux/blkdev.h>
  15#include <linux/ide.h>
  16#include <linux/init.h>
  17#include <linux/zorro.h>
  18#include <linux/module.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#define GAYLE_IDEREG_SIZE       0x2000
  34
  35    /*
  36     *  Offsets from one of the above bases
  37     */
  38
  39#define GAYLE_CONTROL   0x101a
  40
  41    /*
  42     *  These are at different offsets from the base
  43     */
  44
  45#define GAYLE_IRQ_4000  0xdd3020        /* MSB = 1, Harddisk is source of */
  46#define GAYLE_IRQ_1200  0xda9000        /* interrupt */
  47
  48
  49    /*
  50     *  Offset of the secondary port for IDE doublers
  51     *  Note that GAYLE_CONTROL is NOT available then!
  52     */
  53
  54#define GAYLE_NEXT_PORT 0x1000
  55
  56#define GAYLE_NUM_HWIFS         2
  57#define GAYLE_NUM_PROBE_HWIFS   (ide_doubler ? GAYLE_NUM_HWIFS : \
  58                                               GAYLE_NUM_HWIFS-1)
  59#define GAYLE_HAS_CONTROL_REG   (!ide_doubler)
  60
  61static int ide_doubler;
  62module_param_named(doubler, ide_doubler, bool, 0);
  63MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
  64
  65    /*
  66     *  Check and acknowledge the interrupt status
  67     */
  68
  69static int gayle_test_irq(ide_hwif_t *hwif)
  70{
  71    unsigned char ch;
  72
  73    ch = z_readb(hwif->io_ports.irq_addr);
  74    if (!(ch & GAYLE_IRQ_IDE))
  75        return 0;
  76    return 1;
  77}
  78
  79static void gayle_a1200_clear_irq(ide_drive_t *drive)
  80{
  81    ide_hwif_t *hwif = drive->hwif;
  82
  83    (void)z_readb(hwif->io_ports.status_addr);
  84    z_writeb(0x7c, hwif->io_ports.irq_addr);
  85}
  86
  87static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base,
  88                                     unsigned long ctl, unsigned long irq_port)
  89{
  90        int i;
  91
  92        memset(hw, 0, sizeof(*hw));
  93
  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        hw->io_ports.ctl_addr = ctl;
 100        hw->io_ports.irq_addr = irq_port;
 101
 102        hw->irq = IRQ_AMIGA_PORTS;
 103}
 104
 105static const struct ide_port_ops gayle_a4000_port_ops = {
 106        .test_irq               = gayle_test_irq,
 107};
 108
 109static const struct ide_port_ops gayle_a1200_port_ops = {
 110        .clear_irq              = gayle_a1200_clear_irq,
 111        .test_irq               = gayle_test_irq,
 112};
 113
 114static const struct ide_port_info gayle_port_info = {
 115        .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
 116                                  IDE_HFLAG_NO_DMA,
 117        .irq_flags              = IRQF_SHARED,
 118        .chipset                = ide_generic,
 119};
 120
 121    /*
 122     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
 123     */
 124
 125static int __init gayle_init(void)
 126{
 127    unsigned long phys_base, res_start, res_n;
 128    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;
 132
 133    if (!MACH_IS_AMIGA)
 134        return -ENODEV;
 135
 136    if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE))
 137        goto found;
 138
 139#ifdef CONFIG_ZORRO
 140    if (zorro_find_device(ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE,
 141                          NULL))
 142        goto found;
 143#endif
 144    return -ENODEV;
 145
 146found:
 147        printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
 148                         a4000 ? 4000 : 1200,
 149                         ide_doubler ? ", IDE doubler" : "");
 150
 151        if (a4000) {
 152            phys_base = GAYLE_BASE_4000;
 153            irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_4000);
 154            d.port_ops = &gayle_a4000_port_ops;
 155        } else {
 156            phys_base = GAYLE_BASE_1200;
 157            irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200);
 158            d.port_ops = &gayle_a1200_port_ops;
 159        }
 160
 161        res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
 162        res_n = GAYLE_IDEREG_SIZE;
 163
 164        if (!request_mem_region(res_start, res_n, "IDE"))
 165                return -EBUSY;
 166
 167    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
 168        base = (unsigned long)ZTWO_VADDR(phys_base + i * GAYLE_NEXT_PORT);
 169        ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
 170
 171        gayle_setup_ports(&hw[i], base, ctrlport, irqport);
 172
 173        hws[i] = &hw[i];
 174    }
 175
 176    rc = ide_host_add(&d, hws, i, NULL);
 177    if (rc)
 178        release_mem_region(res_start, res_n);
 179
 180    return rc;
 181}
 182
 183module_init(gayle_init);
 184
 185MODULE_LICENSE("GPL");
 186