root/drivers/ide/qd65xx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. qd65xx_dev_select
  2. qd6500_compute_timing
  3. qd6580_compute_timing
  4. qd_find_disk_type
  5. qd_set_timing
  6. qd6500_set_pio_mode
  7. qd6580_set_pio_mode
  8. qd_testreg
  9. qd6500_init_dev
  10. qd6580_init_dev
  11. qd_probe
  12. qd65xx_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
   4  */
   5 
   6 /*
   7  *  Version 0.03        Cleaned auto-tune, added probe
   8  *  Version 0.04        Added second channel tuning
   9  *  Version 0.05        Enhanced tuning ; added qd6500 support
  10  *  Version 0.06        Added dos driver's list
  11  *  Version 0.07        Second channel bug fix 
  12  *
  13  * QDI QD6500/QD6580 EIDE controller fast support
  14  *
  15  * To activate controller support, use "ide0=qd65xx"
  16  */
  17 
  18 /*
  19  * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
  20  * Samuel Thibault <samuel.thibault@ens-lyon.org>
  21  */
  22 
  23 #include <linux/module.h>
  24 #include <linux/types.h>
  25 #include <linux/kernel.h>
  26 #include <linux/delay.h>
  27 #include <linux/timer.h>
  28 #include <linux/mm.h>
  29 #include <linux/ioport.h>
  30 #include <linux/blkdev.h>
  31 #include <linux/ide.h>
  32 #include <linux/init.h>
  33 #include <asm/io.h>
  34 
  35 #define DRV_NAME "qd65xx"
  36 
  37 #include "qd65xx.h"
  38 
  39 /*
  40  * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
  41  *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
  42  *      -- qd6500 is a single IDE interface
  43  *      -- qd6580 is a dual IDE interface
  44  *
  45  * More research on qd6580 being done by willmore@cig.mot.com (David)
  46  * More Information given by Petr Soucek (petr@ryston.cz)
  47  * http://www.ryston.cz/petr/vlb
  48  */
  49 
  50 /*
  51  * base: Timer1
  52  *
  53  *
  54  * base+0x01: Config (R/O)
  55  *
  56  * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
  57  * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
  58  * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
  59  * bit 3: qd6500: 1 = disabled, 0 = enabled
  60  *        qd6580: 1
  61  * upper nibble:
  62  *        qd6500: 1100
  63  *        qd6580: either 1010 or 0101
  64  *
  65  *
  66  * base+0x02: Timer2 (qd6580 only)
  67  *
  68  *
  69  * base+0x03: Control (qd6580 only)
  70  *
  71  * bits 0-3 must always be set 1
  72  * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
  73  * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
  74  *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
  75  *                                                   channel 1 for hdc & hdd
  76  * bit 1 : 1 = only disks on primary port
  77  *         0 = disks & ATAPI devices on primary port
  78  * bit 2-4 : always 0
  79  * bit 5 : status, but of what ?
  80  * bit 6 : always set 1 by dos driver
  81  * bit 7 : set 1 for non-ATAPI devices on primary port
  82  *      (maybe read-ahead and post-write buffer ?)
  83  */
  84 
  85 static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
  86 
  87 /*
  88  * qd65xx_select:
  89  *
  90  * This routine is invoked to prepare for access to a given drive.
  91  */
  92 
  93 static void qd65xx_dev_select(ide_drive_t *drive)
  94 {
  95         u8 index = ((   (QD_TIMREG(drive)) & 0x80 ) >> 7) |
  96                         (QD_TIMREG(drive) & 0x02);
  97 
  98         if (timings[index] != QD_TIMING(drive))
  99                 outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
 100 
 101         outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
 102 }
 103 
 104 /*
 105  * qd6500_compute_timing
 106  *
 107  * computes the timing value where
 108  *      lower nibble represents active time,   in count of VLB clocks
 109  *      upper nibble represents recovery time, in count of VLB clocks
 110  */
 111 
 112 static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
 113 {
 114         int clk = ide_vlb_clk ? ide_vlb_clk : 50;
 115         u8 act_cyc, rec_cyc;
 116 
 117         if (clk <= 33) {
 118                 act_cyc =  9 - IDE_IN(active_time   * clk / 1000 + 1, 2,  9);
 119                 rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15);
 120         } else {
 121                 act_cyc =  8 - IDE_IN(active_time   * clk / 1000 + 1, 1,  8);
 122                 rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18);
 123         }
 124 
 125         return (rec_cyc << 4) | 0x08 | act_cyc;
 126 }
 127 
 128 /*
 129  * qd6580_compute_timing
 130  *
 131  * idem for qd6580
 132  */
 133 
 134 static u8 qd6580_compute_timing (int active_time, int recovery_time)
 135 {
 136         int clk = ide_vlb_clk ? ide_vlb_clk : 50;
 137         u8 act_cyc, rec_cyc;
 138 
 139         act_cyc = 17 - IDE_IN(active_time   * clk / 1000 + 1, 2, 17);
 140         rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15);
 141 
 142         return (rec_cyc << 4) | act_cyc;
 143 }
 144 
 145 /*
 146  * qd_find_disk_type
 147  *
 148  * tries to find timing from dos driver's table
 149  */
 150 
 151 static int qd_find_disk_type (ide_drive_t *drive,
 152                 int *active_time, int *recovery_time)
 153 {
 154         struct qd65xx_timing_s *p;
 155         char *m = (char *)&drive->id[ATA_ID_PROD];
 156         char model[ATA_ID_PROD_LEN];
 157 
 158         if (*m == 0)
 159                 return 0;
 160 
 161         strncpy(model, m, ATA_ID_PROD_LEN);
 162         ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */
 163 
 164         for (p = qd65xx_timing ; p->offset != -1 ; p++) {
 165                 if (!strncmp(p->model, model+p->offset, 4)) {
 166                         printk(KERN_DEBUG "%s: listed !\n", drive->name);
 167                         *active_time = p->active;
 168                         *recovery_time = p->recovery;
 169                         return 1;
 170                 }
 171         }
 172         return 0;
 173 }
 174 
 175 /*
 176  * qd_set_timing:
 177  *
 178  * records the timing
 179  */
 180 
 181 static void qd_set_timing (ide_drive_t *drive, u8 timing)
 182 {
 183         unsigned long data = (unsigned long)ide_get_drivedata(drive);
 184 
 185         data &= 0xff00;
 186         data |= timing;
 187         ide_set_drivedata(drive, (void *)data);
 188 
 189         printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
 190 }
 191 
 192 static void qd6500_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
 193 {
 194         u16 *id = drive->id;
 195         int active_time   = 175;
 196         int recovery_time = 415; /* worst case values from the dos driver */
 197 
 198         /* FIXME: use drive->pio_mode value */
 199         if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
 200             (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
 201             id[ATA_ID_EIDE_PIO] >= 240) {
 202                 printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
 203                         id[ATA_ID_OLD_PIO_MODES] & 0xff);
 204                 active_time = 110;
 205                 recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120;
 206         }
 207 
 208         qd_set_timing(drive, qd6500_compute_timing(drive->hwif,
 209                                 active_time, recovery_time));
 210 }
 211 
 212 static void qd6580_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
 213 {
 214         const u8 pio = drive->pio_mode - XFER_PIO_0;
 215         struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
 216         unsigned int cycle_time;
 217         int active_time   = 175;
 218         int recovery_time = 415; /* worst case values from the dos driver */
 219         u8 base = (hwif->config_data & 0xff00) >> 8;
 220 
 221         if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
 222                 cycle_time = ide_pio_cycle_time(drive, pio);
 223 
 224                 switch (pio) {
 225                         case 0: break;
 226                         case 3:
 227                                 if (cycle_time >= 110) {
 228                                         active_time = 86;
 229                                         recovery_time = cycle_time - 102;
 230                                 } else
 231                                         printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
 232                                 break;
 233                         case 4:
 234                                 if (cycle_time >= 69) {
 235                                         active_time = 70;
 236                                         recovery_time = cycle_time - 61;
 237                                 } else
 238                                         printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
 239                                 break;
 240                         default:
 241                                 if (cycle_time >= 180) {
 242                                         active_time = 110;
 243                                         recovery_time = cycle_time - 120;
 244                                 } else {
 245                                         active_time = t->active;
 246                                         recovery_time = cycle_time - active_time;
 247                                 }
 248                 }
 249                 printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
 250         }
 251 
 252         if (!hwif->channel && drive->media != ide_disk) {
 253                 outb(0x5f, QD_CONTROL_PORT);
 254                 printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
 255                         "and post-write buffer on %s.\n",
 256                         drive->name, hwif->name);
 257         }
 258 
 259         qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
 260 }
 261 
 262 /*
 263  * qd_testreg
 264  *
 265  * tests if the given port is a register
 266  */
 267 
 268 static int __init qd_testreg(int port)
 269 {
 270         unsigned long flags;
 271         u8 savereg, readreg;
 272 
 273         local_irq_save(flags);
 274         savereg = inb_p(port);
 275         outb_p(QD_TESTVAL, port);       /* safe value */
 276         readreg = inb_p(port);
 277         outb(savereg, port);
 278         local_irq_restore(flags);
 279 
 280         if (savereg == QD_TESTVAL) {
 281                 printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
 282                 printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
 283                 printk(KERN_ERR "Assuming qd65xx is not present.\n");
 284                 return 1;
 285         }
 286 
 287         return (readreg != QD_TESTVAL);
 288 }
 289 
 290 static void __init qd6500_init_dev(ide_drive_t *drive)
 291 {
 292         ide_hwif_t *hwif = drive->hwif;
 293         u8 base = (hwif->config_data & 0xff00) >> 8;
 294         u8 config = QD_CONFIG(hwif);
 295 
 296         ide_set_drivedata(drive, (void *)QD6500_DEF_DATA);
 297 }
 298 
 299 static void __init qd6580_init_dev(ide_drive_t *drive)
 300 {
 301         ide_hwif_t *hwif = drive->hwif;
 302         u16 t1, t2;
 303         u8 base = (hwif->config_data & 0xff00) >> 8;
 304         u8 config = QD_CONFIG(hwif);
 305 
 306         if (hwif->host_flags & IDE_HFLAG_SINGLE) {
 307                 t1 = QD6580_DEF_DATA;
 308                 t2 = QD6580_DEF_DATA2;
 309         } else
 310                 t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
 311 
 312         ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1));
 313 }
 314 
 315 static const struct ide_tp_ops qd65xx_tp_ops = {
 316         .exec_command           = ide_exec_command,
 317         .read_status            = ide_read_status,
 318         .read_altstatus         = ide_read_altstatus,
 319         .write_devctl           = ide_write_devctl,
 320 
 321         .dev_select             = qd65xx_dev_select,
 322         .tf_load                = ide_tf_load,
 323         .tf_read                = ide_tf_read,
 324 
 325         .input_data             = ide_input_data,
 326         .output_data            = ide_output_data,
 327 };
 328 
 329 static const struct ide_port_ops qd6500_port_ops = {
 330         .init_dev               = qd6500_init_dev,
 331         .set_pio_mode           = qd6500_set_pio_mode,
 332 };
 333 
 334 static const struct ide_port_ops qd6580_port_ops = {
 335         .init_dev               = qd6580_init_dev,
 336         .set_pio_mode           = qd6580_set_pio_mode,
 337 };
 338 
 339 static const struct ide_port_info qd65xx_port_info __initconst = {
 340         .name                   = DRV_NAME,
 341         .tp_ops                 = &qd65xx_tp_ops,
 342         .chipset                = ide_qd65xx,
 343         .host_flags             = IDE_HFLAG_IO_32BIT |
 344                                   IDE_HFLAG_NO_DMA,
 345         .pio_mask               = ATA_PIO4,
 346 };
 347 
 348 /*
 349  * qd_probe:
 350  *
 351  * looks at the specified baseport, and if qd found, registers & initialises it
 352  * return 1 if another qd may be probed
 353  */
 354 
 355 static int __init qd_probe(int base)
 356 {
 357         int rc;
 358         u8 config, unit, control;
 359         struct ide_port_info d = qd65xx_port_info;
 360 
 361         config = inb(QD_CONFIG_PORT);
 362 
 363         if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
 364                 return -ENODEV;
 365 
 366         unit = ! (config & QD_CONFIG_IDE_BASEPORT);
 367 
 368         if (unit)
 369                 d.host_flags |= IDE_HFLAG_QD_2ND_PORT;
 370 
 371         switch (config & 0xf0) {
 372         case QD_CONFIG_QD6500:
 373                 if (qd_testreg(base))
 374                          return -ENODEV;        /* bad register */
 375 
 376                 if (config & QD_CONFIG_DISABLED) {
 377                         printk(KERN_WARNING "qd6500 is disabled !\n");
 378                         return -ENODEV;
 379                 }
 380 
 381                 printk(KERN_NOTICE "qd6500 at %#x\n", base);
 382                 printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
 383                         config, QD_ID3);
 384 
 385                 d.port_ops = &qd6500_port_ops;
 386                 d.host_flags |= IDE_HFLAG_SINGLE;
 387                 break;
 388         case QD_CONFIG_QD6580_A:
 389         case QD_CONFIG_QD6580_B:
 390                 if (qd_testreg(base) || qd_testreg(base + 0x02))
 391                         return -ENODEV; /* bad registers */
 392 
 393                 control = inb(QD_CONTROL_PORT);
 394 
 395                 printk(KERN_NOTICE "qd6580 at %#x\n", base);
 396                 printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
 397                         config, control, QD_ID3);
 398 
 399                 outb(QD_DEF_CONTR, QD_CONTROL_PORT);
 400 
 401                 d.port_ops = &qd6580_port_ops;
 402                 if (control & QD_CONTR_SEC_DISABLED)
 403                         d.host_flags |= IDE_HFLAG_SINGLE;
 404 
 405                 printk(KERN_INFO "qd6580: %s IDE board\n",
 406                         (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual");
 407                 break;
 408         default:
 409                 return -ENODEV;
 410         }
 411 
 412         rc = ide_legacy_device_add(&d, (base << 8) | config);
 413 
 414         if (d.host_flags & IDE_HFLAG_SINGLE)
 415                 return (rc == 0) ? 1 : rc;
 416 
 417         return rc;
 418 }
 419 
 420 static bool probe_qd65xx;
 421 
 422 module_param_named(probe, probe_qd65xx, bool, 0);
 423 MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
 424 
 425 static int __init qd65xx_init(void)
 426 {
 427         int rc1, rc2 = -ENODEV;
 428 
 429         if (probe_qd65xx == 0)
 430                 return -ENODEV;
 431 
 432         rc1 = qd_probe(0x30);
 433         if (rc1)
 434                 rc2 = qd_probe(0xb0);
 435 
 436         if (rc1 < 0 && rc2 < 0)
 437                 return -ENODEV;
 438 
 439         return 0;
 440 }
 441 
 442 module_init(qd65xx_init);
 443 
 444 MODULE_AUTHOR("Samuel Thibault");
 445 MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
 446 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */