OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [block/] [cmd640.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/*
2
 *  linux/drivers/block/cmd640.c        Version 1.02  Sep 01, 1996
3
 *
4
 *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
5
 */
6
 
7
/*
8
 *  Original author:    abramov@cecmow.enet.dec.com (Igor Abramov)
9
 *
10
 *  Maintained by:      mlord@pobox.com (Mark Lord)
11
 *                      with fanatical support from a legion of hackers!
12
 *
13
 *  This file provides support for the advanced features and bugs
14
 *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
15
 *
16
 *  These chips are basically fucked by design, and getting this driver
17
 *  to work on every motherboard design that uses this screwed chip seems
18
 *  bloody well impossible.  However, we're still trying.
19
 *
20
 *  Version 0.97 worked for everybody.
21
 *
22
 *  User feedback is essential.  Many thanks to the beta test team:
23
 *
24
 *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
25
 *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
26
 *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
27
 *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
28
 *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
29
 *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
30
 *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
31
 *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
32
 *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
33
 *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
34
 *  liug@mama.indstate.edu, and others.
35
 *
36
 *  Version 0.01        Initial version, hacked out of ide.c,
37
 *                      and #include'd rather than compiled separately.
38
 *                      This will get cleaned up in a subsequent release.
39
 *
40
 *  Version 0.02        Fixes for vlb initialization code, enable prefetch
41
 *                      for versions 'B' and 'C' of chip by default,
42
 *                      some code cleanup.
43
 *
44
 *  Version 0.03        Added reset of secondary interface,
45
 *                      and black list for devices which are not compatible
46
 *                      with prefetch mode. Separate function for setting
47
 *                      prefetch is added, possibly it will be called some
48
 *                      day from ioctl processing code.
49
 *
50
 *  Version 0.04        Now configs/compiles separate from ide.c
51
 *
52
 *  Version 0.05        Major rewrite of interface timing code.
53
 *                      Added new function cmd640_set_mode to set PIO mode
54
 *                      from ioctl call. New drives added to black list.
55
 *
56
 *  Version 0.06        More code cleanup. Prefetch is enabled only for
57
 *                      detected hard drives, not included in prefetch
58
 *                      black list.
59
 *
60
 *  Version 0.07        Changed to more conservative drive tuning policy.
61
 *                      Unknown drives, which report PIO < 4 are set to
62
 *                      (reported_PIO - 1) if it is supported, or to PIO0.
63
 *                      List of known drives extended by info provided by
64
 *                      CMD at their ftp site.
65
 *
66
 *  Version 0.08        Added autotune/noautotune support.
67
 *
68
 *  Version 0.09        Try to be smarter about 2nd port enabling.
69
 *  Version 0.10        Be nice and don't reset 2nd port.
70
 *  Version 0.11        Try to handle more wierd situations.
71
 *
72
 *  Version 0.12        Lots of bug fixes from Laszlo Peter
73
 *                      irq unmasking disabled for reliability.
74
 *                      try to be even smarter about the second port.
75
 *                      tidy up source code formatting.
76
 *  Version 0.13        permit irq unmasking again.
77
 *  Version 0.90        massive code cleanup, some bugs fixed.
78
 *                      defaults all drives to PIO mode0, prefetch off.
79
 *                      autotune is OFF by default, with compile time flag.
80
 *                      prefetch can be turned OFF/ON using "hdparm -p8/-p9"
81
 *                       (requires hdparm-3.1 or newer)
82
 *  Version 0.91        first release to linux-kernel list.
83
 *  Version 0.92        move initial reg dump to separate callable function
84
 *                      change "readahead" to "prefetch" to avoid confusion
85
 *  Version 0.95        respect original BIOS timings unless autotuning.
86
 *                      tons of code cleanup and rearrangement.
87
 *                      added CONFIG_BLK_DEV_CMD640_ENHANCED option
88
 *                      prevent use of unmask when prefetch is on
89
 *  Version 0.96        prevent use of io_32bit when prefetch is off
90
 *  Version 0.97        fix VLB secondary interface for sjd@slip.net
91
 *                      other minor tune-ups:  0.96 was very good.
92
 *  Version 0.98        ignore PCI version when disabled by BIOS
93
 *  Version 0.99        display setup/active/recovery clocks with PIO mode
94
 *  Version 1.00        Mmm.. cannot depend on PCMD_ENA in all systems
95
 *  Version 1.01        slow/fast devsel can be selected with "hdparm -p6/-p7"
96
 *                       ("fast" is necessary for 32bit I/O in some systems)
97
 *  Version 1.02        fix bug that resulted in slow "setup times"
98
 *                       (patch courtesy of Zoltan Hidvegi)
99
 */
100
 
101
#undef REALLY_SLOW_IO           /* most systems can safely undef this */
102
#define CMD640_PREFETCH_MASKS 1
103
 
104
#include <linux/config.h>
105
#include <linux/types.h>
106
#include <linux/kernel.h>
107
#include <linux/delay.h>
108
#include <linux/timer.h>
109
#include <linux/mm.h>
110
#include <linux/ioport.h>
111
#include <linux/blkdev.h>
112
#include <linux/hdreg.h>
113
#include <asm/io.h>
114
#include "ide.h"
115
#include "ide_modes.h"
116
 
117
/*
118
 * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
119
 */
120
int cmd640_vlb = 0;
121
 
122
/*
123
 * CMD640 specific registers definition.
124
 */
125
 
126
#define VID             0x00
127
#define DID             0x02
128
#define PCMD            0x04
129
#define   PCMD_ENA      0x01
130
#define PSTTS           0x06
131
#define REVID           0x08
132
#define PROGIF          0x09
133
#define SUBCL           0x0a
134
#define BASCL           0x0b
135
#define BaseA0          0x10
136
#define BaseA1          0x14
137
#define BaseA2          0x18
138
#define BaseA3          0x1c
139
#define INTLINE         0x3c
140
#define INPINE          0x3d
141
 
142
#define CFR             0x50
143
#define   CFR_DEVREV            0x03
144
#define   CFR_IDE01INTR         0x04
145
#define   CFR_DEVID             0x18
146
#define   CFR_AT_VESA_078h      0x20
147
#define   CFR_DSA1              0x40
148
#define   CFR_DSA0              0x80
149
 
150
#define CNTRL           0x51
151
#define   CNTRL_DIS_RA0         0x40
152
#define   CNTRL_DIS_RA1         0x80
153
#define   CNTRL_ENA_2ND         0x08
154
 
155
#define CMDTIM          0x52
156
#define ARTTIM0         0x53
157
#define DRWTIM0         0x54
158
#define ARTTIM1         0x55
159
#define DRWTIM1         0x56
160
#define ARTTIM23        0x57
161
#define   ARTTIM23_DIS_RA2      0x04
162
#define   ARTTIM23_DIS_RA3      0x08
163
#define DRWTIM23        0x58
164
#define BRST            0x59
165
 
166
/*
167
 * Registers and masks for easy access by drive index:
168
 */
169
static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
170
static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
171
 
172
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
173
 
174
static byte arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
175
static byte drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
176
 
177
/*
178
 * Current cmd640 timing values for each drive.
179
 * The defaults for each are the slowest possible timings.
180
 */
181
static byte setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
182
static byte active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
183
static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
184
 
185
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
186
 
187
/*
188
 * These are initialized to point at the devices we control
189
 */
190
static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
191
static ide_drive_t *cmd_drives[4];
192
 
193
/*
194
 * Interface to access cmd640x registers
195
 */
196
static unsigned int cmd640_key;
197
static void (*put_cmd640_reg)(unsigned short reg, byte val);
198
static byte (*get_cmd640_reg)(unsigned short reg);
199
 
200
/*
201
 * This is read from the CFR reg, and is used in several places.
202
 */
203
static unsigned int cmd640_chip_version;
204
 
205
/*
206
 * The CMD640x chip does not support DWORD config write cycles, but some
207
 * of the BIOSes use them to implement the config services.
208
 * Therefore, we must use direct IO instead.
209
 */
210
 
211
/* PCI method 1 access */
212
 
213
static void put_cmd640_reg_pci1 (unsigned short reg, byte val)
214
{
215
        unsigned long flags;
216
 
217
        save_flags(flags);
218
        cli();
219
        outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
220
        outb_p(val, (reg & 3) | 0xcfc);
221
        restore_flags(flags);
222
}
223
 
224
static byte get_cmd640_reg_pci1 (unsigned short reg)
225
{
226
        byte b;
227
        unsigned long flags;
228
 
229
        save_flags(flags);
230
        cli();
231
        outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
232
        b = inb_p((reg & 3) | 0xcfc);
233
        restore_flags(flags);
234
        return b;
235
}
236
 
237
/* PCI method 2 access (from CMD datasheet) */
238
 
239
static void put_cmd640_reg_pci2 (unsigned short reg, byte val)
240
{
241
        unsigned long flags;
242
 
243
        save_flags(flags);
244
        cli();
245
        outb_p(0x10, 0xcf8);
246
        outb_p(val, cmd640_key + reg);
247
        outb_p(0, 0xcf8);
248
        restore_flags(flags);
249
}
250
 
251
static byte get_cmd640_reg_pci2 (unsigned short reg)
252
{
253
        byte b;
254
        unsigned long flags;
255
 
256
        save_flags(flags);
257
        cli();
258
        outb_p(0x10, 0xcf8);
259
        b = inb_p(cmd640_key + reg);
260
        outb_p(0, 0xcf8);
261
        restore_flags(flags);
262
        return b;
263
}
264
 
265
/* VLB access */
266
 
267
static void put_cmd640_reg_vlb (unsigned short reg, byte val)
268
{
269
        unsigned long flags;
270
 
271
        save_flags(flags);
272
        cli();
273
        outb_p(reg, cmd640_key);
274
        outb_p(val, cmd640_key + 4);
275
        restore_flags(flags);
276
}
277
 
278
static byte get_cmd640_reg_vlb (unsigned short reg)
279
{
280
        byte b;
281
        unsigned long flags;
282
 
283
        save_flags(flags);
284
        cli();
285
        outb_p(reg, cmd640_key);
286
        b = inb_p(cmd640_key + 4);
287
        restore_flags(flags);
288
        return b;
289
}
290
 
291
static int match_pci_cmd640_device (void)
292
{
293
        const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
294
        unsigned int i;
295
        for (i = 0; i < 4; i++) {
296
                if (get_cmd640_reg(i) != ven_dev[i])
297
                        return 0;
298
        }
299
#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
300
        if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
301
                printk("ide: cmd640 on PCI disabled by BIOS\n");
302
                return 0;
303
        }
304
#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
305
        return 1; /* success */
306
}
307
 
308
/*
309
 * Probe for CMD640x -- pci method 1
310
 */
311
static int probe_for_cmd640_pci1 (void)
312
{
313
        get_cmd640_reg = get_cmd640_reg_pci1;
314
        put_cmd640_reg = put_cmd640_reg_pci1;
315
        for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) {
316
                if (match_pci_cmd640_device())
317
                        return 1; /* success */
318
        }
319
        return 0;
320
}
321
 
322
/*
323
 * Probe for CMD640x -- pci method 2
324
 */
325
static int probe_for_cmd640_pci2 (void)
326
{
327
        get_cmd640_reg = get_cmd640_reg_pci2;
328
        put_cmd640_reg = put_cmd640_reg_pci2;
329
        for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
330
                if (match_pci_cmd640_device())
331
                        return 1; /* success */
332
        }
333
        return 0;
334
}
335
 
336
/*
337
 * Probe for CMD640x -- vlb
338
 */
339
static int probe_for_cmd640_vlb (void)
340
{
341
        byte b;
342
 
343
        get_cmd640_reg = get_cmd640_reg_vlb;
344
        put_cmd640_reg = put_cmd640_reg_vlb;
345
        cmd640_key = 0x178;
346
        b = get_cmd640_reg(CFR);
347
        if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
348
                cmd640_key = 0x78;
349
                b = get_cmd640_reg(CFR);
350
                if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
351
                        return 0;
352
        }
353
        return 1; /* success */
354
}
355
 
356
/*
357
 *  Returns 1 if an IDE interface/drive exists at 0x170,
358
 *  Returns 0 otherwise.
359
 */
360
static int secondary_port_responding (void)
361
{
362
        unsigned long flags;
363
 
364
        save_flags(flags);
365
        cli();
366
 
367
        outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);        /* select drive0 */
368
        udelay(100);
369
        if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
370
                outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
371
                udelay(100);
372
                if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
373
                        restore_flags(flags);
374
                        return 0; /* nothing responded */
375
                }
376
        }
377
        restore_flags(flags);
378
        return 1; /* success */
379
}
380
 
381
#ifdef CMD640_DUMP_REGS
382
/*
383
 * Dump out all cmd640 registers.  May be called from ide.c
384
 */
385
void cmd640_dump_regs (void)
386
{
387
        unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
388
 
389
        /* Dump current state of chip registers */
390
        printk("ide: cmd640 internal register dump:");
391
        for (; reg <= 0x59; reg++) {
392
                if (!(reg & 0x0f))
393
                        printk("\n%04x:", reg);
394
                printk(" %02x", get_cmd640_reg(reg));
395
        }
396
        printk("\n");
397
}
398
#endif
399
 
400
/*
401
 * Check whether prefetch is on for a drive,
402
 * and initialize the unmask flags for safe operation.
403
 */
404
static void check_prefetch (unsigned int index)
405
{
406
        ide_drive_t *drive = cmd_drives[index];
407
        byte b = get_cmd640_reg(prefetch_regs[index]);
408
 
409
        if (b & prefetch_masks[index]) {        /* is prefetch off? */
410
                drive->no_unmask = 0;
411
                drive->no_io_32bit = 1;
412
                drive->io_32bit = 0;
413
        } else {
414
#if CMD640_PREFETCH_MASKS
415
                drive->no_unmask = 1;
416
                drive->unmask = 0;
417
#endif
418
                drive->no_io_32bit = 0;
419
        }
420
}
421
 
422
/*
423
 * Figure out which devices we control
424
 */
425
static void setup_device_ptrs (void)
426
{
427
        unsigned int i;
428
 
429
        cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
430
        cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
431
        for (i = 0; i < MAX_HWIFS; i++) {
432
                ide_hwif_t *hwif = &ide_hwifs[i];
433
                if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
434
                        if (hwif->io_base == 0x1f0)
435
                                cmd_hwif0 = hwif;
436
                        else if (hwif->io_base == 0x170)
437
                                cmd_hwif1 = hwif;
438
                }
439
        }
440
        cmd_drives[0] = &cmd_hwif0->drives[0];
441
        cmd_drives[1] = &cmd_hwif0->drives[1];
442
        cmd_drives[2] = &cmd_hwif1->drives[0];
443
        cmd_drives[3] = &cmd_hwif1->drives[1];
444
}
445
 
446
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
447
 
448
/*
449
 * Sets prefetch mode for a drive.
450
 */
451
static void set_prefetch_mode (unsigned int index, int mode)
452
{
453
        ide_drive_t *drive = cmd_drives[index];
454
        int reg = prefetch_regs[index];
455
        byte b;
456
        unsigned long flags;
457
 
458
        save_flags(flags);
459
        cli();
460
        b = get_cmd640_reg(reg);
461
        if (mode) {     /* want prefetch on? */
462
#if CMD640_PREFETCH_MASKS
463
                drive->no_unmask = 1;
464
                drive->unmask = 0;
465
#endif
466
                drive->no_io_32bit = 0;
467
                b &= ~prefetch_masks[index];    /* enable prefetch */
468
        } else {
469
                drive->no_unmask = 0;
470
                drive->no_io_32bit = 1;
471
                drive->io_32bit = 0;
472
                b |= prefetch_masks[index];     /* disable prefetch */
473
        }
474
        put_cmd640_reg(reg, b);
475
        restore_flags(flags);
476
}
477
 
478
/*
479
 * Dump out current drive clocks settings
480
 */
481
static void display_clocks (unsigned int index)
482
{
483
        byte active_count, recovery_count;
484
 
485
        active_count = active_counts[index];
486
        if (active_count == 1)
487
                ++active_count;
488
        recovery_count = recovery_counts[index];
489
        if (active_count > 3 && recovery_count == 1)
490
                ++recovery_count;
491
        if (cmd640_chip_version > 1)
492
                recovery_count += 1;  /* cmd640b uses (count + 1)*/
493
        printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
494
}
495
 
496
/*
497
 * Pack active and recovery counts into single byte representation
498
 * used by controller
499
 */
500
inline static byte pack_nibbles (byte upper, byte lower)
501
{
502
        return ((upper & 0x0f) << 4) | (lower & 0x0f);
503
}
504
 
505
/*
506
 * This routine retrieves the initial drive timings from the chipset.
507
 */
508
static void retrieve_drive_counts (unsigned int index)
509
{
510
        byte b;
511
 
512
        /*
513
         * Get the internal setup timing, and convert to clock count
514
         */
515
        b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
516
        switch (b) {
517
                case 0x00: b = 4; break;
518
                case 0x80: b = 3; break;
519
                case 0x40: b = 2; break;
520
                default:   b = 5; break;
521
        }
522
        setup_counts[index] = b;
523
 
524
        /*
525
         * Get the active/recovery counts
526
         */
527
        b = get_cmd640_reg(drwtim_regs[index]);
528
        active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
529
        recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
530
}
531
 
532
 
533
/*
534
 * This routine writes the prepared setup/active/recovery counts
535
 * for a drive into the cmd640 chipset registers to active them.
536
 */
537
static void program_drive_counts (unsigned int index)
538
{
539
        unsigned long flags;
540
        byte setup_count    = setup_counts[index];
541
        byte active_count   = active_counts[index];
542
        byte recovery_count = recovery_counts[index];
543
 
544
        /*
545
         * Set up address setup count and drive read/write timing registers.
546
         * Primary interface has individual count/timing registers for
547
         * each drive.  Secondary interface has one common set of registers,
548
         * so we merge the timings, using the slowest value for each timing.
549
         */
550
        if (index > 1) {
551
                unsigned int mate;
552
                if (cmd_drives[mate = index ^ 1]->present) {
553
                        if (setup_count < setup_counts[mate])
554
                                setup_count = setup_counts[mate];
555
                        if (active_count < active_counts[mate])
556
                                active_count = active_counts[mate];
557
                        if (recovery_count < recovery_counts[mate])
558
                                recovery_count = recovery_counts[mate];
559
                }
560
        }
561
 
562
        /*
563
         * Convert setup_count to internal chipset representation
564
         */
565
        switch (setup_count) {
566
                case 4:  setup_count = 0x00; break;
567
                case 3:  setup_count = 0x80; break;
568
                case 1:
569
                case 2:  setup_count = 0x40; break;
570
                default: setup_count = 0xc0; /* case 5 */
571
        }
572
 
573
        /*
574
         * Now that everything is ready, program the new timings
575
         */
576
        save_flags (flags);
577
        cli();
578
        /*
579
         * Program the address_setup clocks into ARTTIM reg,
580
         * and then the active/recovery counts into the DRWTIM reg
581
         * (this converts counts of 16 into counts of zero -- okay).
582
         */
583
        setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
584
        put_cmd640_reg(arttim_regs[index], setup_count);
585
        put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
586
        restore_flags(flags);
587
}
588
 
589
/*
590
 * Set a specific pio_mode for a drive
591
 */
592
static void cmd640_set_mode (unsigned int index, byte pio_mode, unsigned int cycle_time)
593
{
594
        int setup_time, active_time, recovery_time, clock_time;
595
        byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
596
        int bus_speed = ide_system_bus_speed();
597
 
598
        if (pio_mode > 5)
599
                pio_mode = 5;
600
        setup_time  = ide_pio_timings[pio_mode].setup_time;
601
        active_time = ide_pio_timings[pio_mode].active_time;
602
        recovery_time = cycle_time - (setup_time + active_time);
603
        clock_time = 1000 / bus_speed;
604
        cycle_count = (cycle_time + clock_time - 1) / clock_time;
605
 
606
        setup_count = (setup_time + clock_time - 1) / clock_time;
607
 
608
        active_count = (active_time + clock_time - 1) / clock_time;
609
        if (active_count < 2)
610
                active_count = 2; /* minimum allowed by cmd640 */
611
 
612
        recovery_count = (recovery_time + clock_time - 1) / clock_time;
613
        recovery_count2 = cycle_count - (setup_count + active_count);
614
        if (recovery_count2 > recovery_count)
615
                recovery_count = recovery_count2;
616
        if (recovery_count < 2)
617
                recovery_count = 2; /* minimum allowed by cmd640 */
618
        if (recovery_count > 17) {
619
                active_count += recovery_count - 17;
620
                recovery_count = 17;
621
        }
622
        if (active_count > 16)
623
                active_count = 16; /* maximum allowed by cmd640 */
624
        if (cmd640_chip_version > 1)
625
                recovery_count -= 1;  /* cmd640b uses (count + 1)*/
626
        if (recovery_count > 16)
627
                recovery_count = 16; /* maximum allowed by cmd640 */
628
 
629
        setup_counts[index]    = setup_count;
630
        active_counts[index]   = active_count;
631
        recovery_counts[index] = recovery_count;
632
 
633
        /*
634
         * In a perfect world, we might set the drive pio mode here
635
         * (using WIN_SETFEATURE) before continuing.
636
         *
637
         * But we do not, because:
638
         *      1) this is the wrong place to do it (proper is do_special() in ide.c)
639
         *      2) in practice this is rarely, if ever, necessary
640
         */
641
        program_drive_counts (index);
642
}
643
 
644
/*
645
 * Drive PIO mode selection:
646
 */
647
static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
648
{
649
        byte b;
650
        ide_pio_data_t  d;
651
        unsigned int index = 0;
652
 
653
        while (drive != cmd_drives[index]) {
654
                if (++index > 3) {
655
                        printk("%s: bad news in cmd640_tune_drive\n", drive->name);
656
                        return;
657
                }
658
        }
659
        switch (mode_wanted) {
660
                case 6: /* set fast-devsel off */
661
                case 7: /* set fast-devsel on */
662
                        mode_wanted &= 1;
663
                        b = get_cmd640_reg(CNTRL) & ~0x27;
664
                        if (mode_wanted)
665
                                b |= 0x27;
666
                        put_cmd640_reg(CNTRL, b);
667
                        printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
668
                        return;
669
 
670
                case 8: /* set prefetch off */
671
                case 9: /* set prefetch on */
672
                        mode_wanted &= 1;
673
                        set_prefetch_mode(index, mode_wanted);
674
                        printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
675
                        return;
676
        }
677
 
678
        (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
679
        cmd640_set_mode (index, d.pio_mode, d.cycle_time);
680
 
681
        printk ("%s: selected cmd640 PIO mode%d (%dns) %s/IORDY%s",
682
                drive->name,
683
                d.pio_mode,
684
                d.cycle_time,
685
                d.use_iordy ? "w" : "wo",
686
                d.overridden ? " (overriding vendor mode)" : "");
687
        display_clocks(index);
688
}
689
 
690
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
691
 
692
/*
693
 * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
694
 */
695
int ide_probe_for_cmd640x (void)
696
{
697
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
698
        int second_port_toggled = 0;
699
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
700
        int second_port_cmd640 = 0;
701
        const char *bus_type, *port2;
702
        unsigned int index;
703
        byte b, cfr;
704
 
705
        if (cmd640_vlb && probe_for_cmd640_vlb()) {
706
                bus_type = "VLB";
707
        } else {
708
                cmd640_vlb = 0;
709
                if (probe_for_cmd640_pci1())
710
                        bus_type = "PCI (type1)";
711
                else if (probe_for_cmd640_pci2())
712
                        bus_type = "PCI (type2)";
713
                else
714
                        return 0;
715
        }
716
        /*
717
         * Undocumented magic (there is no 0x5b reg in specs)
718
         */
719
        put_cmd640_reg(0x5b, 0xbd);
720
        if (get_cmd640_reg(0x5b) != 0xbd) {
721
                printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
722
                return 0;
723
        }
724
        put_cmd640_reg(0x5b, 0);
725
 
726
#ifdef CMD640_DUMP_REGS
727
        CMD640_DUMP_REGS;
728
#endif
729
 
730
        /*
731
         * Documented magic begins here
732
         */
733
        cfr = get_cmd640_reg(CFR);
734
        cmd640_chip_version = cfr & CFR_DEVREV;
735
        if (cmd640_chip_version == 0) {
736
                printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
737
                return 0;
738
        }
739
 
740
        /*
741
         * Initialize data for primary port
742
         */
743
        setup_device_ptrs ();
744
        printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
745
               cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
746
        cmd_hwif0->chipset = ide_cmd640;
747
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
748
        cmd_hwif0->tuneproc = &cmd640_tune_drive;
749
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
750
 
751
        /*
752
         * Ensure compatibility by always using the slowest timings
753
         * for access to the drive's command register block,
754
         * and reset the prefetch burstsize to default (512 bytes).
755
         *
756
         * Maybe we need a way to NOT do these on *some* systems?
757
         */
758
        put_cmd640_reg(CMDTIM, 0);
759
        put_cmd640_reg(BRST, 0x40);
760
 
761
        /*
762
         * Try to enable the secondary interface, if not already enabled
763
         */
764
        if (cmd_hwif1->noprobe) {
765
                port2 = "not probed";
766
        } else {
767
                b = get_cmd640_reg(CNTRL);
768
                if (secondary_port_responding()) {
769
                        if ((b & CNTRL_ENA_2ND)) {
770
                                second_port_cmd640 = 1;
771
                                port2 = "okay";
772
                        } else if (cmd640_vlb) {
773
                                second_port_cmd640 = 1;
774
                                port2 = "alive";
775
                        } else
776
                                port2 = "not cmd640";
777
                } else {
778
                        put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
779
                        if (secondary_port_responding()) {
780
                                second_port_cmd640 = 1;
781
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
782
                                second_port_toggled = 1;
783
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
784
                                port2 = "enabled";
785
                        } else {
786
                                put_cmd640_reg(CNTRL, b); /* restore original setting */
787
                                port2 = "not responding";
788
                        }
789
                }
790
        }
791
 
792
        /*
793
         * Initialize data for secondary cmd640 port, if enabled
794
         */
795
        if (second_port_cmd640) {
796
                cmd_hwif0->serialized = 1;
797
                cmd_hwif1->serialized = 1;
798
                cmd_hwif1->chipset = ide_cmd640;
799
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
800
                cmd_hwif1->tuneproc = &cmd640_tune_drive;
801
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
802
        }
803
        printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
804
                cmd_hwif0->serialized ? "" : "not ", port2);
805
 
806
        /*
807
         * Establish initial timings/prefetch for all drives.
808
         * Do not unnecessarily disturb any prior BIOS setup of these.
809
         */
810
        for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
811
                ide_drive_t *drive = cmd_drives[index];
812
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
813
                if (drive->autotune || ((index > 1) && second_port_toggled)) {
814
                        /*
815
                         * Reset timing to the slowest speed and turn off prefetch.
816
                         * This way, the drive identify code has a better chance.
817
                         */
818
                        setup_counts    [index] = 4;    /* max possible */
819
                        active_counts   [index] = 16;   /* max possible */
820
                        recovery_counts [index] = 16;   /* max possible */
821
                        program_drive_counts (index);
822
                        set_prefetch_mode (index, 0);
823
                        printk("cmd640: drive%d timings/prefetch cleared\n", index);
824
                } else {
825
                        /*
826
                         * Record timings/prefetch without changing them.
827
                         * This preserves any prior BIOS setup.
828
                         */
829
                        retrieve_drive_counts (index);
830
                        check_prefetch (index);
831
                        printk("cmd640: drive%d timings/prefetch(%s) preserved",
832
                                index, drive->no_io_32bit ? "off" : "on");
833
                        display_clocks(index);
834
                }
835
#else
836
                /*
837
                 * Set the drive unmask flags to match the prefetch setting
838
                 */
839
                check_prefetch (index);
840
                printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
841
                        index, drive->no_io_32bit ? "off" : "on");
842
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
843
        }
844
 
845
#ifdef CMD640_DUMP_REGS
846
        CMD640_DUMP_REGS;
847
#endif
848
        return 1;
849
}
850
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.