linux/drivers/ide/pci/opti621.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/ide/pci/opti621.c             Version 0.9     Sep 24, 2007
   3 *
   4 *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
   5 */
   6
   7/*
   8 * Authors:
   9 * Jaromir Koutek <miri@punknet.cz>,
  10 * Jan Harkes <jaharkes@cwi.nl>,
  11 * Mark Lord <mlord@pobox.com>
  12 * Some parts of code are from ali14xx.c and from rz1000.c.
  13 *
  14 * OPTi is trademark of OPTi, Octek is trademark of Octek.
  15 *
  16 * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
  17 * and disassembled/traced setupvic.exe (DOS program).
  18 * It increases kernel code about 2 kB.
  19 * I don't have this card no more, but I hope I can get some in case
  20 * of needed development.
  21 * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
  22 * It has a place for a secondary connector in circuit, but nothing
  23 * is there. Also BIOS says no address for
  24 * secondary controller (see bellow in ide_init_opti621).
  25 * I've only tested this on my system, which only has one disk.
  26 * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
  27 * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
  28 * lockups). I tried the OCTEK double speed CD-ROM and
  29 * it does not work! But I can't boot DOS also, so it's probably
  30 * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
  31 * problems) and Seagate 1GB (as slave, WD as master). My experiences
  32 * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
  33 * it slows to about 100kB/s! I don't know why and I have
  34 * not this drive now, so I can't try it again.
  35 * I write this driver because I lost the paper ("manual") with
  36 * settings of jumpers on the card and I have to boot Linux with
  37 * Loadlin except LILO, cause I have to run the setupvic.exe program
  38 * already or I get disk errors (my test: rpm -Vf
  39 * /usr/X11R6/bin/XF86_SVGA - or any big file).
  40 * Some numbers from hdparm -t /dev/hda:
  41 * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
  42 * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
  43 * I have 4 Megs/s before, but I don't know why (maybe changes
  44 * in hdparm test).
  45 * After release of 0.1, I got some successful reports, so it might work.
  46 *
  47 * The main problem with OPTi is that some timings for master
  48 * and slave must be the same. For example, if you have master
  49 * PIO 3 and slave PIO 0, driver have to set some timings of
  50 * master for PIO 0. Second problem is that opti621_set_pio_mode
  51 * got only one drive to set, but have to set both drives.
  52 * This is solved in compute_pios. If you don't set
  53 * the second drive, compute_pios use ide_get_best_pio_mode
  54 * for autoselect mode (you can change it to PIO 0, if you want).
  55 * If you then set the second drive to another PIO, the old value
  56 * (automatically selected) will be overrided by yours.
  57 * There is a 25/33MHz switch in configuration
  58 * register, but driver is written for use at any frequency which get
  59 * (use idebus=xx to select PCI bus speed).
  60 *
  61 * Version 0.1, Nov 8, 1996
  62 * by Jaromir Koutek, for 2.1.8. 
  63 * Initial version of driver.
  64 * 
  65 * Version 0.2
  66 * Number 0.2 skipped.
  67 *
  68 * Version 0.3, Nov 29, 1997
  69 * by Mark Lord (probably), for 2.1.68
  70 * Updates for use with new IDE block driver.
  71 *
  72 * Version 0.4, Dec 14, 1997
  73 * by Jan Harkes
  74 * Fixed some errors and cleaned the code.
  75 *
  76 * Version 0.5, Jan 2, 1998
  77 * by Jaromir Koutek
  78 * Updates for use with (again) new IDE block driver.
  79 * Update of documentation.
  80 * 
  81 * Version 0.6, Jan 2, 1999
  82 * by Jaromir Koutek
  83 * Reversed to version 0.3 of the driver, because
  84 * 0.5 doesn't work.
  85 */
  86
  87#define OPTI621_DEBUG           /* define for debug messages */
  88
  89#include <linux/types.h>
  90#include <linux/module.h>
  91#include <linux/kernel.h>
  92#include <linux/delay.h>
  93#include <linux/timer.h>
  94#include <linux/mm.h>
  95#include <linux/ioport.h>
  96#include <linux/blkdev.h>
  97#include <linux/pci.h>
  98#include <linux/hdreg.h>
  99#include <linux/ide.h>
 100
 101#include <asm/io.h>
 102
 103//#define OPTI621_MAX_PIO 3
 104/* In fact, I do not have any PIO 4 drive
 105 * (address: 25 ns, data: 70 ns, recovery: 35 ns),
 106 * but OPTi 82C621 is programmable and it can do (minimal values):
 107 * on 40MHz PCI bus (pulse 25 ns):
 108 *  address: 25 ns, data: 25 ns, recovery: 50 ns;
 109 * on 20MHz PCI bus (pulse 50 ns):
 110 *  address: 50 ns, data: 50 ns, recovery: 100 ns.
 111 */
 112
 113/* #define READ_PREFETCH 0 */
 114/* Uncomment for disable read prefetch.
 115 * There is some readprefetch capatibility in hdparm,
 116 * but when I type hdparm -P 1 /dev/hda, I got errors
 117 * and till reset drive is inaccessible.
 118 * This (hw) read prefetch is safe on my drive.
 119 */
 120
 121#ifndef READ_PREFETCH
 122#define READ_PREFETCH 0x40 /* read prefetch is enabled */
 123#endif /* else read prefetch is disabled */
 124
 125#define READ_REG 0      /* index of Read cycle timing register */
 126#define WRITE_REG 1     /* index of Write cycle timing register */
 127#define CNTRL_REG 3     /* index of Control register */
 128#define STRAP_REG 5     /* index of Strap register */
 129#define MISC_REG 6      /* index of Miscellaneous register */
 130
 131static int reg_base;
 132
 133#define PIO_NOT_EXIST 254
 134#define PIO_DONT_KNOW 255
 135
 136static DEFINE_SPINLOCK(opti621_lock);
 137
 138/* there are stored pio numbers from other calls of opti621_set_pio_mode */
 139static void compute_pios(ide_drive_t *drive, const u8 pio)
 140/* Store values into drive->drive_data
 141 *      second_contr - 0 for primary controller, 1 for secondary
 142 *      slave_drive - 0 -> pio is for master, 1 -> pio is for slave
 143 *      pio - PIO mode for selected drive (for other we don't know)
 144 */
 145{
 146        int d;
 147        ide_hwif_t *hwif = HWIF(drive);
 148
 149        drive->drive_data = pio;
 150
 151        for (d = 0; d < 2; ++d) {
 152                drive = &hwif->drives[d];
 153                if (drive->present) {
 154                        if (drive->drive_data == PIO_DONT_KNOW)
 155                                drive->drive_data = ide_get_best_pio_mode(drive, 255, 3);
 156#ifdef OPTI621_DEBUG
 157                        printk("%s: Selected PIO mode %d\n",
 158                                drive->name, drive->drive_data);
 159#endif
 160                } else {
 161                        drive->drive_data = PIO_NOT_EXIST;
 162                }
 163        }
 164}
 165
 166static int cmpt_clk(int time, int bus_speed)
 167/* Returns (rounded up) time in clocks for time in ns,
 168 * with bus_speed in MHz.
 169 * Example: bus_speed = 40 MHz, time = 80 ns
 170 * 1000/40 = 25 ns (clk value),
 171 * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
 172 * Use idebus=xx to select right frequency.
 173 */
 174{
 175        return ((time*bus_speed+999)/1000);
 176}
 177
 178/* Write value to register reg, base of register
 179 * is at reg_base (0x1f0 primary, 0x170 secondary,
 180 * if not changed by PCI configuration).
 181 * This is from setupvic.exe program.
 182 */
 183static void write_reg(u8 value, int reg)
 184{
 185        inw(reg_base + 1);
 186        inw(reg_base + 1);
 187        outb(3, reg_base + 2);
 188        outb(value, reg_base + reg);
 189        outb(0x83, reg_base + 2);
 190}
 191
 192/* Read value from register reg, base of register
 193 * is at reg_base (0x1f0 primary, 0x170 secondary,
 194 * if not changed by PCI configuration).
 195 * This is from setupvic.exe program.
 196 */
 197static u8 read_reg(int reg)
 198{
 199        u8 ret = 0;
 200
 201        inw(reg_base + 1);
 202        inw(reg_base + 1);
 203        outb(3, reg_base + 2);
 204        ret = inb(reg_base + reg);
 205        outb(0x83, reg_base + 2);
 206
 207        return ret;
 208}
 209
 210typedef struct pio_clocks_s {
 211        int     address_time;   /* Address setup (clocks) */
 212        int     data_time;      /* Active/data pulse (clocks) */
 213        int     recovery_time;  /* Recovery time (clocks) */
 214} pio_clocks_t;
 215
 216static void compute_clocks(int pio, pio_clocks_t *clks)
 217{
 218        if (pio != PIO_NOT_EXIST) {
 219                int adr_setup, data_pls;
 220                int bus_speed = system_bus_clock();
 221
 222                adr_setup = ide_pio_timings[pio].setup_time;
 223                data_pls = ide_pio_timings[pio].active_time;
 224                clks->address_time = cmpt_clk(adr_setup, bus_speed);
 225                clks->data_time = cmpt_clk(data_pls, bus_speed);
 226                clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
 227                        - adr_setup-data_pls, bus_speed);
 228                if (clks->address_time<1) clks->address_time = 1;
 229                if (clks->address_time>4) clks->address_time = 4;
 230                if (clks->data_time<1) clks->data_time = 1;
 231                if (clks->data_time>16) clks->data_time = 16;
 232                if (clks->recovery_time<2) clks->recovery_time = 2;
 233                if (clks->recovery_time>17) clks->recovery_time = 17;
 234        } else {
 235                clks->address_time = 1;
 236                clks->data_time = 1;
 237                clks->recovery_time = 2;
 238                /* minimal values */
 239        }
 240 
 241}
 242
 243static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
 244{
 245        /* primary and secondary drives share some registers,
 246         * so we have to program both drives
 247         */
 248        unsigned long flags;
 249        u8 pio1 = 0, pio2 = 0;
 250        pio_clocks_t first, second;
 251        int ax, drdy;
 252        u8 cycle1, cycle2, misc;
 253        ide_hwif_t *hwif = HWIF(drive);
 254
 255        /* sets drive->drive_data for both drives */
 256        compute_pios(drive, pio);
 257        pio1 = hwif->drives[0].drive_data;
 258        pio2 = hwif->drives[1].drive_data;
 259
 260        compute_clocks(pio1, &first);
 261        compute_clocks(pio2, &second);
 262
 263        /* ax = max(a1,a2) */
 264        ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
 265
 266        drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
 267
 268        cycle1 = ((first.data_time-1)<<4)  | (first.recovery_time-2);
 269        cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
 270        misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
 271
 272#ifdef OPTI621_DEBUG
 273        printk("%s: master: address: %d, data: %d, "
 274                "recovery: %d, drdy: %d [clk]\n",
 275                hwif->name, ax, first.data_time,
 276                first.recovery_time, drdy);
 277        printk("%s: slave:  address: %d, data: %d, "
 278                "recovery: %d, drdy: %d [clk]\n",
 279                hwif->name, ax, second.data_time,
 280                second.recovery_time, drdy);
 281#endif
 282
 283        spin_lock_irqsave(&opti621_lock, flags);
 284
 285        reg_base = hwif->io_ports[IDE_DATA_OFFSET];
 286
 287        /* allow Register-B */
 288        outb(0xc0, reg_base + CNTRL_REG);
 289        /* hmm, setupvic.exe does this ;-) */
 290        outb(0xff, reg_base + 5);
 291        /* if reads 0xff, adapter not exist? */
 292        (void)inb(reg_base + CNTRL_REG);
 293        /* if reads 0xc0, no interface exist? */
 294        read_reg(CNTRL_REG);
 295        /* read version, probably 0 */
 296        read_reg(STRAP_REG);
 297
 298        /* program primary drive */
 299        /* select Index-0 for Register-A */
 300        write_reg(0, MISC_REG);
 301        /* set read cycle timings */
 302        write_reg(cycle1, READ_REG);
 303        /* set write cycle timings */
 304        write_reg(cycle1, WRITE_REG);
 305
 306        /* program secondary drive */
 307        /* select Index-1 for Register-B */
 308        write_reg(1, MISC_REG);
 309        /* set read cycle timings */
 310        write_reg(cycle2, READ_REG);
 311        /* set write cycle timings */
 312        write_reg(cycle2, WRITE_REG);
 313
 314        /* use Register-A for drive 0 */
 315        /* use Register-B for drive 1 */
 316        write_reg(0x85, CNTRL_REG);
 317
 318        /* set address setup, DRDY timings,   */
 319        /*  and read prefetch for both drives */
 320        write_reg(misc, MISC_REG);
 321
 322        spin_unlock_irqrestore(&opti621_lock, flags);
 323}
 324
 325/*
 326 * init_hwif_opti621() is called once for each hwif found at boot.
 327 */
 328static void __devinit init_hwif_opti621 (ide_hwif_t *hwif)
 329{
 330        hwif->drives[0].drive_data = PIO_DONT_KNOW;
 331        hwif->drives[1].drive_data = PIO_DONT_KNOW;
 332
 333        hwif->set_pio_mode = &opti621_set_pio_mode;
 334}
 335
 336static const struct ide_port_info opti621_chipsets[] __devinitdata = {
 337        {       /* 0 */
 338                .name           = "OPTI621",
 339                .init_hwif      = init_hwif_opti621,
 340                .enablebits     = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
 341                .host_flags     = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
 342                                  IDE_HFLAG_BOOTABLE,
 343                .pio_mask       = ATA_PIO3,
 344                .swdma_mask     = ATA_SWDMA2,
 345                .mwdma_mask     = ATA_MWDMA2,
 346        },{     /* 1 */
 347                .name           = "OPTI621X",
 348                .init_hwif      = init_hwif_opti621,
 349                .enablebits     = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
 350                .host_flags     = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
 351                                  IDE_HFLAG_BOOTABLE,
 352                .pio_mask       = ATA_PIO3,
 353                .swdma_mask     = ATA_SWDMA2,
 354                .mwdma_mask     = ATA_MWDMA2,
 355        }
 356};
 357
 358static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 359{
 360        return ide_setup_pci_device(dev, &opti621_chipsets[id->driver_data]);
 361}
 362
 363static const struct pci_device_id opti621_pci_tbl[] = {
 364        { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
 365        { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
 366        { 0, },
 367};
 368MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
 369
 370static struct pci_driver driver = {
 371        .name           = "Opti621_IDE",
 372        .id_table       = opti621_pci_tbl,
 373        .probe          = opti621_init_one,
 374};
 375
 376static int __init opti621_ide_init(void)
 377{
 378        return ide_pci_register_driver(&driver);
 379}
 380
 381module_init(opti621_ide_init);
 382
 383MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord");
 384MODULE_DESCRIPTION("PCI driver module for Opti621 IDE");
 385MODULE_LICENSE("GPL");
 386
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.