linux/drivers/ide/legacy/ali14xx.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/ide/legacy/ali14xx.c          Version 0.03    Feb 09, 1996
   3 *
   4 *  Copyright (C) 1996  Linus Torvalds & author (see below)
   5 */
   6
   7/*
   8 * ALI M14xx chipset EIDE controller
   9 *
  10 * Works for ALI M1439/1443/1445/1487/1489 chipsets.
  11 *
  12 * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
  13 * Derek's notes follow:
  14 *
  15 * I think the code should be pretty understandable,
  16 * but I'll be happy to (try to) answer questions.
  17 *
  18 * The critical part is in the setupDrive function.  The initRegisters
  19 * function doesn't seem to be necessary, but the DOS driver does it, so
  20 * I threw it in.
  21 *
  22 * I've only tested this on my system, which only has one disk.  I posted
  23 * it to comp.sys.linux.hardware, so maybe some other people will try it
  24 * out.
  25 *
  26 * Derek Noonburg  (derekn@ece.cmu.edu)
  27 * 95-sep-26
  28 *
  29 * Update 96-jul-13:
  30 *
  31 * I've since upgraded to two disks and a CD-ROM, with no trouble, and
  32 * I've also heard from several others who have used it successfully.
  33 * This driver appears to work with both the 1443/1445 and the 1487/1489
  34 * chipsets.  I've added support for PIO mode 4 for the 1487.  This
  35 * seems to work just fine on the 1443 also, although I'm not sure it's
  36 * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
  37 * mode 4 for a while now with no trouble.)  -Derek
  38 */
  39
  40#include <linux/module.h>
  41#include <linux/types.h>
  42#include <linux/kernel.h>
  43#include <linux/delay.h>
  44#include <linux/timer.h>
  45#include <linux/mm.h>
  46#include <linux/ioport.h>
  47#include <linux/blkdev.h>
  48#include <linux/hdreg.h>
  49#include <linux/ide.h>
  50#include <linux/init.h>
  51
  52#include <asm/io.h>
  53
  54/* port addresses for auto-detection */
  55#define ALI_NUM_PORTS 4
  56static const int ports[ALI_NUM_PORTS] __initdata =
  57        { 0x074, 0x0f4, 0x034, 0x0e4 };
  58
  59/* register initialization data */
  60typedef struct { u8 reg, data; } RegInitializer;
  61
  62static const RegInitializer initData[] __initdata = {
  63        {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
  64        {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
  65        {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
  66        {0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
  67        {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
  68        {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
  69        {0x35, 0x03}, {0x00, 0x00}
  70};
  71
  72/* timing parameter registers for each drive */
  73static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
  74        {0x03, 0x26, 0x04, 0x27},     /* drive 0 */
  75        {0x05, 0x28, 0x06, 0x29},     /* drive 1 */
  76        {0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
  77        {0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
  78};
  79
  80static int basePort;    /* base port address */
  81static int regPort;     /* port for register number */
  82static int dataPort;    /* port for register data */
  83static u8 regOn;        /* output to base port to access registers */
  84static u8 regOff;       /* output to base port to close registers */
  85
  86/*------------------------------------------------------------------------*/
  87
  88/*
  89 * Read a controller register.
  90 */
  91static inline u8 inReg (u8 reg)
  92{
  93        outb_p(reg, regPort);
  94        return inb(dataPort);
  95}
  96
  97/*
  98 * Write a controller register.
  99 */
 100static void outReg (u8 data, u8 reg)
 101{
 102        outb_p(reg, regPort);
 103        outb_p(data, dataPort);
 104}
 105
 106static DEFINE_SPINLOCK(ali14xx_lock);
 107
 108/*
 109 * Set PIO mode for the specified drive.
 110 * This function computes timing parameters
 111 * and sets controller registers accordingly.
 112 */
 113static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 114{
 115        int driveNum;
 116        int time1, time2;
 117        u8 param1, param2, param3, param4;
 118        unsigned long flags;
 119        int bus_speed = system_bus_clock();
 120
 121        /* calculate timing, according to PIO mode */
 122        time1 = ide_pio_cycle_time(drive, pio);
 123        time2 = ide_pio_timings[pio].active_time;
 124        param3 = param1 = (time2 * bus_speed + 999) / 1000;
 125        param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
 126        if (pio < 3) {
 127                param3 += 8;
 128                param4 += 8;
 129        }
 130        printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
 131                drive->name, pio, time1, time2, param1, param2, param3, param4);
 132
 133        /* stuff timing parameters into controller registers */
 134        driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
 135        spin_lock_irqsave(&ali14xx_lock, flags);
 136        outb_p(regOn, basePort);
 137        outReg(param1, regTab[driveNum].reg1);
 138        outReg(param2, regTab[driveNum].reg2);
 139        outReg(param3, regTab[driveNum].reg3);
 140        outReg(param4, regTab[driveNum].reg4);
 141        outb_p(regOff, basePort);
 142        spin_unlock_irqrestore(&ali14xx_lock, flags);
 143}
 144
 145/*
 146 * Auto-detect the IDE controller port.
 147 */
 148static int __init findPort (void)
 149{
 150        int i;
 151        u8 t;
 152        unsigned long flags;
 153
 154        local_irq_save(flags);
 155        for (i = 0; i < ALI_NUM_PORTS; ++i) {
 156                basePort = ports[i];
 157                regOff = inb(basePort);
 158                for (regOn = 0x30; regOn <= 0x33; ++regOn) {
 159                        outb_p(regOn, basePort);
 160                        if (inb(basePort) == regOn) {
 161                                regPort = basePort + 4;
 162                                dataPort = basePort + 8;
 163                                t = inReg(0) & 0xf0;
 164                                outb_p(regOff, basePort);
 165                                local_irq_restore(flags);
 166                                if (t != 0x50)
 167                                        return 0;
 168                                return 1;  /* success */
 169                        }
 170                }
 171                outb_p(regOff, basePort);
 172        }
 173        local_irq_restore(flags);
 174        return 0;
 175}
 176
 177/*
 178 * Initialize controller registers with default values.
 179 */
 180static int __init initRegisters (void) {
 181        const RegInitializer *p;
 182        u8 t;
 183        unsigned long flags;
 184
 185        local_irq_save(flags);
 186        outb_p(regOn, basePort);
 187        for (p = initData; p->reg != 0; ++p)
 188                outReg(p->data, p->reg);
 189        outb_p(0x01, regPort);
 190        t = inb(regPort) & 0x01;
 191        outb_p(regOff, basePort);
 192        local_irq_restore(flags);
 193        return t;
 194}
 195
 196static int __init ali14xx_probe(void)
 197{
 198        ide_hwif_t *hwif, *mate;
 199        static u8 idx[4] = { 0, 1, 0xff, 0xff };
 200
 201        printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
 202                          basePort, regOn);
 203
 204        /* initialize controller registers */
 205        if (!initRegisters()) {
 206                printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
 207                return 1;
 208        }
 209
 210        hwif = &ide_hwifs[0];
 211        mate = &ide_hwifs[1];
 212
 213        hwif->chipset = ide_ali14xx;
 214        hwif->pio_mask = ATA_PIO4;
 215        hwif->set_pio_mode = &ali14xx_set_pio_mode;
 216        hwif->mate = mate;
 217
 218        mate->chipset = ide_ali14xx;
 219        mate->pio_mask = ATA_PIO4;
 220        mate->set_pio_mode = &ali14xx_set_pio_mode;
 221        mate->mate = hwif;
 222        mate->channel = 1;
 223
 224        ide_device_add(idx);
 225
 226        return 0;
 227}
 228
 229int probe_ali14xx = 0;
 230
 231module_param_named(probe, probe_ali14xx, bool, 0);
 232MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
 233
 234/* Can be called directly from ide.c. */
 235int __init ali14xx_init(void)
 236{
 237        if (probe_ali14xx == 0)
 238                goto out;
 239
 240        /* auto-detect IDE controller port */
 241        if (findPort()) {
 242                if (ali14xx_probe())
 243                        return -ENODEV;
 244                return 0;
 245        }
 246        printk(KERN_ERR "ali14xx: not found.\n");
 247out:
 248        return -ENODEV;
 249}
 250
 251#ifdef MODULE
 252module_init(ali14xx_init);
 253#endif
 254
 255MODULE_AUTHOR("see local file");
 256MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
 257MODULE_LICENSE("GPL");
 258
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.