linux/drivers/ide/ht6560b.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
   4 */
   5
   6/*
   7 *  HT-6560B EIDE-controller support
   8 *  To activate controller support use kernel parameter "ide0=ht6560b".
   9 *  Use hdparm utility to enable PIO mode support.
  10 *
  11 *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
  12 *             Jan Evert van Grootheest   <j.e.van.grootheest@caiway.nl>
  13 *
  14 */
  15
  16#define DRV_NAME        "ht6560b"
  17#define HT6560B_VERSION "v0.08"
  18
  19#include <linux/module.h>
  20#include <linux/types.h>
  21#include <linux/kernel.h>
  22#include <linux/delay.h>
  23#include <linux/timer.h>
  24#include <linux/mm.h>
  25#include <linux/ioport.h>
  26#include <linux/blkdev.h>
  27#include <linux/ide.h>
  28#include <linux/init.h>
  29
  30#include <asm/io.h>
  31
  32/* #define DEBUG */  /* remove comments for DEBUG messages */
  33
  34/*
  35 * The special i/o-port that HT-6560B uses to configuration:
  36 *    bit0 (0x01): "1" selects secondary interface
  37 *    bit2 (0x04): "1" enables FIFO function
  38 *    bit5 (0x20): "1" enables prefetched data read function  (???)
  39 *
  40 * The special i/o-port that HT-6560A uses to configuration:
  41 *    bit0 (0x01): "1" selects secondary interface
  42 *    bit1 (0x02): "1" enables prefetched data read function
  43 *    bit2 (0x04): "0" enables multi-master system            (?)
  44 *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time         (?)
  45 */
  46#define HT_CONFIG_PORT    0x3e6
  47
  48static inline u8 HT_CONFIG(ide_drive_t *drive)
  49{
  50        return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8;
  51}
  52
  53/*
  54 * FIFO + PREFETCH (both a/b-model)
  55 */
  56#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
  57/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
  58#define HT_SECONDARY_IF   0x01
  59#define HT_PREFETCH_MODE  0x20
  60
  61/*
  62 * ht6560b Timing values:
  63 *
  64 * I reviewed some assembler source listings of htide drivers and found
  65 * out how they setup those cycle time interfacing values, as they at Holtek
  66 * call them. IDESETUP.COM that is supplied with the drivers figures out
  67 * optimal values and fetches those values to drivers. I found out that
  68 * they use Select register to fetch timings to the ide board right after
  69 * interface switching. After that it was quite easy to add code to
  70 * ht6560b.c.
  71 *
  72 * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
  73 * for hda and hdc. But hdb needed higher values to work, so I guess
  74 * that sometimes it is necessary to give higher value than IDESETUP
  75 * gives.   [see cmd640.c for an extreme example of this. -ml]
  76 *
  77 * Perhaps I should explain something about these timing values:
  78 * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
  79 * of the value is the Active Time  (at). Minimum value 2 is the fastest and
  80 * the maximum value 15 is the slowest. Default values should be 15 for both.
  81 * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
  82 * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
  83 * similar. If value is too small there will be all sorts of failures.
  84 *
  85 * Timing byte consists of
  86 *      High nibble:  Recovery Cycle Time  (rt)
  87 *           The valid values range from 2 to 15. The default is 15.
  88 *
  89 *      Low nibble:   Active Cycle Time    (at)
  90 *           The valid values range from 2 to 15. The default is 15.
  91 *
  92 * You can obtain optimized timing values by running Holtek IDESETUP.COM
  93 * for DOS. DOS drivers get their timing values from command line, where
  94 * the first value is the Recovery Time and the second value is the
  95 * Active Time for each drive. Smaller value gives higher speed.
  96 * In case of failures you should probably fall back to a higher value.
  97 */
  98static inline u8 HT_TIMING(ide_drive_t *drive)
  99{
 100        return (unsigned long)ide_get_drivedata(drive) & 0x00ff;
 101}
 102
 103#define HT_TIMING_DEFAULT 0xff
 104
 105/*
 106 * This routine handles interface switching for the peculiar hardware design
 107 * on the F.G.I./Holtek HT-6560B VLB IDE interface.
 108 * The HT-6560B can only enable one IDE port at a time, and requires a
 109 * silly sequence (below) whenever we switch between primary and secondary.
 110 */
 111
 112/*
 113 * This routine is invoked from ide.c to prepare for access to a given drive.
 114 */
 115static void ht6560b_dev_select(ide_drive_t *drive)
 116{
 117        ide_hwif_t *hwif = drive->hwif;
 118        unsigned long flags;
 119        static u8 current_select = 0;
 120        static u8 current_timing = 0;
 121        u8 select, timing;
 122        
 123        local_irq_save(flags);
 124
 125        select = HT_CONFIG(drive);
 126        timing = HT_TIMING(drive);
 127
 128        /*
 129         * Need to enforce prefetch sometimes because otherwise
 130         * it'll hang (hard).
 131         */
 132        if (drive->media != ide_disk ||
 133            (drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
 134                select |= HT_PREFETCH_MODE;
 135
 136        if (select != current_select || timing != current_timing) {
 137                current_select = select;
 138                current_timing = timing;
 139                (void)inb(HT_CONFIG_PORT);
 140                (void)inb(HT_CONFIG_PORT);
 141                (void)inb(HT_CONFIG_PORT);
 142                (void)inb(HT_CONFIG_PORT);
 143                outb(select, HT_CONFIG_PORT);
 144                /*
 145                 * Set timing for this drive:
 146                 */
 147                outb(timing, hwif->io_ports.device_addr);
 148                (void)inb(hwif->io_ports.status_addr);
 149#ifdef DEBUG
 150                printk("ht6560b: %s: select=%#x timing=%#x\n",
 151                        drive->name, select, timing);
 152#endif
 153        }
 154        local_irq_restore(flags);
 155
 156        outb(drive->select | ATA_DEVICE_OBS, hwif->io_ports.device_addr);
 157}
 158
 159/*
 160 * Autodetection and initialization of ht6560b
 161 */
 162static int __init try_to_init_ht6560b(void)
 163{
 164        u8 orig_value;
 165        int i;
 166        
 167        /* Autodetect ht6560b */
 168        if ((orig_value = inb(HT_CONFIG_PORT)) == 0xff)
 169                return 0;
 170        
 171        for (i=3;i>0;i--) {
 172                outb(0x00, HT_CONFIG_PORT);
 173                if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
 174                        outb(orig_value, HT_CONFIG_PORT);
 175                        return 0;
 176                }
 177        }
 178        outb(0x00, HT_CONFIG_PORT);
 179        if ((~inb(HT_CONFIG_PORT))& 0x3f) {
 180                outb(orig_value, HT_CONFIG_PORT);
 181                return 0;
 182        }
 183        /*
 184         * Ht6560b autodetected
 185         */
 186        outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
 187        outb(HT_TIMING_DEFAULT, 0x1f6); /* Select register */
 188        (void)inb(0x1f7);               /* Status register */
 189
 190        printk("ht6560b " HT6560B_VERSION
 191               ": chipset detected and initialized"
 192#ifdef DEBUG
 193               " with debug enabled"
 194#endif
 195               "\n"
 196                );
 197        return 1;
 198}
 199
 200static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio)
 201{
 202        int active_time, recovery_time;
 203        int active_cycles, recovery_cycles;
 204        int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
 205
 206        if (pio) {
 207                unsigned int cycle_time;
 208                struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
 209
 210                cycle_time = ide_pio_cycle_time(drive, pio);
 211
 212                /*
 213                 *  Just like opti621.c we try to calculate the
 214                 *  actual cycle time for recovery and activity
 215                 *  according system bus speed.
 216                 */
 217                active_time = t->active;
 218                recovery_time = cycle_time - active_time - t->setup;
 219                /*
 220                 *  Cycle times should be Vesa bus cycles
 221                 */
 222                active_cycles   = (active_time   * bus_speed + 999) / 1000;
 223                recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
 224                /*
 225                 *  Upper and lower limits
 226                 */
 227                if (active_cycles   < 2)  active_cycles   = 2;
 228                if (recovery_cycles < 2)  recovery_cycles = 2;
 229                if (active_cycles   > 15) active_cycles   = 15;
 230                if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
 231                
 232#ifdef DEBUG
 233                printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
 234#endif
 235                
 236                return (u8)((recovery_cycles << 4) | active_cycles);
 237        } else {
 238                
 239#ifdef DEBUG
 240                printk("ht6560b: drive %s setting pio=0\n", drive->name);
 241#endif
 242                
 243                return HT_TIMING_DEFAULT;    /* default setting */
 244        }
 245}
 246
 247static DEFINE_SPINLOCK(ht6560b_lock);
 248
 249/*
 250 *  Enable/Disable so called prefetch mode
 251 */
 252static void ht_set_prefetch(ide_drive_t *drive, u8 state)
 253{
 254        unsigned long flags, config;
 255        int t = HT_PREFETCH_MODE << 8;
 256
 257        spin_lock_irqsave(&ht6560b_lock, flags);
 258
 259        config = (unsigned long)ide_get_drivedata(drive);
 260
 261        /*
 262         *  Prefetch mode and unmask irq seems to conflict
 263         */
 264        if (state) {
 265                config |= t;   /* enable prefetch mode */
 266                drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
 267                drive->dev_flags &= ~IDE_DFLAG_UNMASK;
 268        } else {
 269                config &= ~t;  /* disable prefetch mode */
 270                drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
 271        }
 272
 273        ide_set_drivedata(drive, (void *)config);
 274
 275        spin_unlock_irqrestore(&ht6560b_lock, flags);
 276
 277#ifdef DEBUG
 278        printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
 279#endif
 280}
 281
 282static void ht6560b_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
 283{
 284        unsigned long flags, config;
 285        const u8 pio = drive->pio_mode - XFER_PIO_0;
 286        u8 timing;
 287        
 288        switch (pio) {
 289        case 8:         /* set prefetch off */
 290        case 9:         /* set prefetch on */
 291                ht_set_prefetch(drive, pio & 1);
 292                return;
 293        }
 294
 295        timing = ht_pio2timings(drive, pio);
 296
 297        spin_lock_irqsave(&ht6560b_lock, flags);
 298        config = (unsigned long)ide_get_drivedata(drive);
 299        config &= 0xff00;
 300        config |= timing;
 301        ide_set_drivedata(drive, (void *)config);
 302        spin_unlock_irqrestore(&ht6560b_lock, flags);
 303
 304#ifdef DEBUG
 305        printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
 306#endif
 307}
 308
 309static void __init ht6560b_init_dev(ide_drive_t *drive)
 310{
 311        ide_hwif_t *hwif = drive->hwif;
 312        /* Setting default configurations for drives. */
 313        int t = (HT_CONFIG_DEFAULT << 8) | HT_TIMING_DEFAULT;
 314
 315        if (hwif->channel)
 316                t |= (HT_SECONDARY_IF << 8);
 317
 318        ide_set_drivedata(drive, (void *)t);
 319}
 320
 321static bool probe_ht6560b;
 322
 323module_param_named(probe, probe_ht6560b, bool, 0);
 324MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
 325
 326static const struct ide_tp_ops ht6560b_tp_ops = {
 327        .exec_command           = ide_exec_command,
 328        .read_status            = ide_read_status,
 329        .read_altstatus         = ide_read_altstatus,
 330        .write_devctl           = ide_write_devctl,
 331
 332        .dev_select             = ht6560b_dev_select,
 333        .tf_load                = ide_tf_load,
 334        .tf_read                = ide_tf_read,
 335
 336        .input_data             = ide_input_data,
 337        .output_data            = ide_output_data,
 338};
 339
 340static const struct ide_port_ops ht6560b_port_ops = {
 341        .init_dev               = ht6560b_init_dev,
 342        .set_pio_mode           = ht6560b_set_pio_mode,
 343};
 344
 345static const struct ide_port_info ht6560b_port_info __initconst = {
 346        .name                   = DRV_NAME,
 347        .chipset                = ide_ht6560b,
 348        .tp_ops                 = &ht6560b_tp_ops,
 349        .port_ops               = &ht6560b_port_ops,
 350        .host_flags             = IDE_HFLAG_SERIALIZE | /* is this needed? */
 351                                  IDE_HFLAG_NO_DMA |
 352                                  IDE_HFLAG_ABUSE_PREFETCH,
 353        .pio_mask               = ATA_PIO4,
 354};
 355
 356static int __init ht6560b_init(void)
 357{
 358        if (probe_ht6560b == 0)
 359                return -ENODEV;
 360
 361        if (!request_region(HT_CONFIG_PORT, 1, DRV_NAME)) {
 362                printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
 363                        __func__);
 364                return -ENODEV;
 365        }
 366
 367        if (!try_to_init_ht6560b()) {
 368                printk(KERN_NOTICE "%s: HBA not found\n", __func__);
 369                goto release_region;
 370        }
 371
 372        return ide_legacy_device_add(&ht6560b_port_info, 0);
 373
 374release_region:
 375        release_region(HT_CONFIG_PORT, 1);
 376        return -ENODEV;
 377}
 378
 379module_init(ht6560b_init);
 380
 381MODULE_AUTHOR("See Local File");
 382MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
 383MODULE_LICENSE("GPL");
 384