Blame view

drivers/ide/cmd640.c 22.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
   *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
   */
  
  /*
   *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
7
   *			mlord@pobox.com (Mark Lord)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
   *
   *  See linux/MAINTAINERS for address of current maintainer.
   *
   *  This file provides support for the advanced features and bugs
   *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
   *
   *  These chips are basically fucked by design, and getting this driver
   *  to work on every motherboard design that uses this screwed chip seems
   *  bloody well impossible.  However, we're still trying.
   *
   *  Version 0.97 worked for everybody.
   *
   *  User feedback is essential.  Many thanks to the beta test team:
   *
   *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
   *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
   *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
   *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
   *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
   *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
   *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
   *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
   *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
   *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
   *  liug@mama.indstate.edu, and others.
   *
   *  Version 0.01	Initial version, hacked out of ide.c,
   *			and #include'd rather than compiled separately.
   *			This will get cleaned up in a subsequent release.
   *
   *  Version 0.02	Fixes for vlb initialization code, enable prefetch
   *			for versions 'B' and 'C' of chip by default,
   *			some code cleanup.
   *
   *  Version 0.03	Added reset of secondary interface,
   *			and black list for devices which are not compatible
   *			with prefetch mode. Separate function for setting
   *			prefetch is added, possibly it will be called some
   *			day from ioctl processing code.
   *
   *  Version 0.04	Now configs/compiles separate from ide.c
   *
   *  Version 0.05	Major rewrite of interface timing code.
   *			Added new function cmd640_set_mode to set PIO mode
   *			from ioctl call. New drives added to black list.
   *
   *  Version 0.06	More code cleanup. Prefetch is enabled only for
   *			detected hard drives, not included in prefetch
   *			black list.
   *
   *  Version 0.07	Changed to more conservative drive tuning policy.
   *			Unknown drives, which report PIO < 4 are set to
   *			(reported_PIO - 1) if it is supported, or to PIO0.
   *			List of known drives extended by info provided by
   *			CMD at their ftp site.
   *
   *  Version 0.08	Added autotune/noautotune support.
   *
   *  Version 0.09	Try to be smarter about 2nd port enabling.
   *  Version 0.10	Be nice and don't reset 2nd port.
   *  Version 0.11	Try to handle more weird situations.
   *
   *  Version 0.12	Lots of bug fixes from Laszlo Peter
   *			irq unmasking disabled for reliability.
   *			try to be even smarter about the second port.
   *			tidy up source code formatting.
   *  Version 0.13	permit irq unmasking again.
   *  Version 0.90	massive code cleanup, some bugs fixed.
   *			defaults all drives to PIO mode0, prefetch off.
   *			autotune is OFF by default, with compile time flag.
   *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
   *			 (requires hdparm-3.1 or newer)
   *  Version 0.91	first release to linux-kernel list.
   *  Version 0.92	move initial reg dump to separate callable function
   *			change "readahead" to "prefetch" to avoid confusion
   *  Version 0.95	respect original BIOS timings unless autotuning.
   *			tons of code cleanup and rearrangement.
   *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
   *			prevent use of unmask when prefetch is on
   *  Version 0.96	prevent use of io_32bit when prefetch is off
   *  Version 0.97	fix VLB secondary interface for sjd@slip.net
   *			other minor tune-ups:  0.96 was very good.
   *  Version 0.98	ignore PCI version when disabled by BIOS
   *  Version 0.99	display setup/active/recovery clocks with PIO mode
   *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
   *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
   *			 ("fast" is necessary for 32bit I/O in some systems)
   *  Version 1.02	fix bug that resulted in slow "setup times"
   *			 (patch courtesy of Zoltan Hidvegi)
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  #define CMD640_PREFETCH_MASKS 1
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
99
  /*#define CMD640_DUMP_REGS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/delay.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
  #include <linux/ide.h>
  #include <linux/init.h>
  
  #include <asm/io.h>
7ebe5936c   Bartlomiej Zolnierkiewicz   cmd640: manage I/...
108
  #define DRV_NAME "cmd640"
ef87f8d09   Bartlomiej Zolnierkiewicz   ide: remove obsol...
109
  static int cmd640_vlb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  
  /*
   * CMD640 specific registers definition.
   */
  
  #define VID		0x00
  #define DID		0x02
  #define PCMD		0x04
  #define   PCMD_ENA	0x01
  #define PSTTS		0x06
  #define REVID		0x08
  #define PROGIF		0x09
  #define SUBCL		0x0a
  #define BASCL		0x0b
  #define BaseA0		0x10
  #define BaseA1		0x14
  #define BaseA2		0x18
  #define BaseA3		0x1c
  #define INTLINE		0x3c
  #define INPINE		0x3d
  
  #define	CFR		0x50
  #define   CFR_DEVREV		0x03
  #define   CFR_IDE01INTR		0x04
  #define	  CFR_DEVID		0x18
  #define	  CFR_AT_VESA_078h	0x20
  #define	  CFR_DSA1		0x40
  #define	  CFR_DSA0		0x80
  
  #define CNTRL		0x51
  #define	  CNTRL_DIS_RA0		0x40
  #define   CNTRL_DIS_RA1		0x80
  #define	  CNTRL_ENA_2ND		0x08
  
  #define	CMDTIM		0x52
  #define	ARTTIM0		0x53
  #define	DRWTIM0		0x54
  #define ARTTIM1 	0x55
  #define DRWTIM1		0x56
  #define ARTTIM23	0x57
  #define   ARTTIM23_DIS_RA2	0x04
  #define   ARTTIM23_DIS_RA3	0x08
87441db22   Sergei Shtylyov   cmd640: implement...
152
  #define   ARTTIM23_IDE23INTR	0x10
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  #define DRWTIM23	0x58
  #define BRST		0x59
  
  /*
   * Registers and masks for easy access by drive index:
   */
  static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
  static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
  
  #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
  
  static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
  static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
  
  /*
   * Current cmd640 timing values for each drive.
   * The defaults for each are the slowest possible timings.
   */
  static u8 setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
  static u8 active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
  static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
  
  #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
176
  static DEFINE_SPINLOCK(cmd640_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
   * Interface to access cmd640x registers
   */
  static unsigned int cmd640_key;
  static void (*__put_cmd640_reg)(u16 reg, u8 val);
  static u8 (*__get_cmd640_reg)(u16 reg);
  
  /*
   * This is read from the CFR reg, and is used in several places.
   */
  static unsigned int cmd640_chip_version;
  
  /*
   * The CMD640x chip does not support DWORD config write cycles, but some
   * of the BIOSes use them to implement the config services.
   * Therefore, we must use direct IO instead.
   */
  
  /* PCI method 1 access */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
196
  static void put_cmd640_reg_pci1(u16 reg, u8 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
200
  {
  	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
  	outb_p(val, (reg & 3) | 0xcfc);
  }
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
201
  static u8 get_cmd640_reg_pci1(u16 reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
  {
  	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
  	return inb_p((reg & 3) | 0xcfc);
  }
  
  /* PCI method 2 access (from CMD datasheet) */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
208
  static void put_cmd640_reg_pci2(u16 reg, u8 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
  {
  	outb_p(0x10, 0xcf8);
  	outb_p(val, cmd640_key + reg);
  	outb_p(0, 0xcf8);
  }
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
214
  static u8 get_cmd640_reg_pci2(u16 reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
220
221
222
223
224
  {
  	u8 b;
  
  	outb_p(0x10, 0xcf8);
  	b = inb_p(cmd640_key + reg);
  	outb_p(0, 0xcf8);
  	return b;
  }
  
  /* VLB access */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
225
  static void put_cmd640_reg_vlb(u16 reg, u8 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
  {
  	outb_p(reg, cmd640_key);
  	outb_p(val, cmd640_key + 4);
  }
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
230
  static u8 get_cmd640_reg_vlb(u16 reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
234
235
236
237
  {
  	outb_p(reg, cmd640_key);
  	return inb_p(cmd640_key + 4);
  }
  
  static u8 get_cmd640_reg(u16 reg)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  	unsigned long flags;
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
239
  	u8 b;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
241
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  	b = __get_cmd640_reg(reg);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
243
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
248
249
  	return b;
  }
  
  static void put_cmd640_reg(u16 reg, u8 val)
  {
  	unsigned long flags;
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
250
  	spin_lock_irqsave(&cmd640_lock, flags);
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
251
  	__put_cmd640_reg(reg, val);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
252
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  }
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
254
  static int __init match_pci_cmd640_device(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  {
  	const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
  	unsigned int i;
  	for (i = 0; i < 4; i++) {
  		if (get_cmd640_reg(i) != ven_dev[i])
  			return 0;
  	}
  #ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
  	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
  		printk("ide: cmd640 on PCI disabled by BIOS
  ");
  		return 0;
  	}
  #endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
  	return 1; /* success */
  }
  
  /*
   * Probe for CMD640x -- pci method 1
   */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
275
  static int __init probe_for_cmd640_pci1(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  {
  	__get_cmd640_reg = get_cmd640_reg_pci1;
  	__put_cmd640_reg = put_cmd640_reg_pci1;
  	for (cmd640_key = 0x80000000;
  	     cmd640_key <= 0x8000f800;
  	     cmd640_key += 0x800) {
  		if (match_pci_cmd640_device())
  			return 1; /* success */
  	}
  	return 0;
  }
  
  /*
   * Probe for CMD640x -- pci method 2
   */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
291
  static int __init probe_for_cmd640_pci2(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
301
302
303
304
  {
  	__get_cmd640_reg = get_cmd640_reg_pci2;
  	__put_cmd640_reg = put_cmd640_reg_pci2;
  	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
  		if (match_pci_cmd640_device())
  			return 1; /* success */
  	}
  	return 0;
  }
  
  /*
   * Probe for CMD640x -- vlb
   */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
305
  static int __init probe_for_cmd640_vlb(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  {
  	u8 b;
  
  	__get_cmd640_reg = get_cmd640_reg_vlb;
  	__put_cmd640_reg = put_cmd640_reg_vlb;
  	cmd640_key = 0x178;
  	b = get_cmd640_reg(CFR);
  	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
  		cmd640_key = 0x78;
  		b = get_cmd640_reg(CFR);
  		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
  			return 0;
  	}
  	return 1; /* success */
  }
  
  /*
   *  Returns 1 if an IDE interface/drive exists at 0x170,
   *  Returns 0 otherwise.
   */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
326
  static int __init secondary_port_responding(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  {
  	unsigned long flags;
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
329
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330

4c3032d8a   Bartlomiej Zolnierkiewicz   ide: add struct i...
331
  	outb_p(0x0a, 0x176);	/* select drive0 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  	udelay(100);
4c3032d8a   Bartlomiej Zolnierkiewicz   ide: add struct i...
333
334
  	if ((inb_p(0x176) & 0x1f) != 0x0a) {
  		outb_p(0x1a, 0x176); /* select drive1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  		udelay(100);
4c3032d8a   Bartlomiej Zolnierkiewicz   ide: add struct i...
336
  		if ((inb_p(0x176) & 0x1f) != 0x1a) {
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
337
  			spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
  			return 0; /* nothing responded */
  		}
  	}
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
341
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
345
346
347
348
  	return 1; /* success */
  }
  
  #ifdef CMD640_DUMP_REGS
  /*
   * Dump out all cmd640 registers.  May be called from ide.c
   */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
349
  static void cmd640_dump_regs(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  {
  	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
  
  	/* Dump current state of chip registers */
  	printk("ide: cmd640 internal register dump:");
  	for (; reg <= 0x59; reg++) {
  		if (!(reg & 0x0f))
  			printk("
  %04x:", reg);
  		printk(" %02x", get_cmd640_reg(reg));
  	}
  	printk("
  ");
  }
  #endif
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
365
366
367
368
  static void __set_prefetch_mode(ide_drive_t *drive, int mode)
  {
  	if (mode) {	/* want prefetch on? */
  #if CMD640_PREFETCH_MASKS
97100fc81   Bartlomiej Zolnierkiewicz   ide: add device f...
369
370
  		drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
  		drive->dev_flags &= ~IDE_DFLAG_UNMASK;
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
371
  #endif
97100fc81   Bartlomiej Zolnierkiewicz   ide: add device f...
372
  		drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
373
  	} else {
97100fc81   Bartlomiej Zolnierkiewicz   ide: add device f...
374
375
  		drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
  		drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
376
377
378
  		drive->io_32bit = 0;
  	}
  }
bdffe5d27   Bartlomiej Zolnierkiewicz   cmd640: always au...
379
  #ifndef CONFIG_BLK_DEV_CMD640_ENHANCED
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
  /*
   * Check whether prefetch is on for a drive,
   * and initialize the unmask flags for safe operation.
   */
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
384
  static void __init check_prefetch(ide_drive_t *drive, unsigned int index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  	u8 b = get_cmd640_reg(prefetch_regs[index]);
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
387
  	__set_prefetch_mode(drive, (b & prefetch_masks[index]) ? 0 : 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  }
bdffe5d27   Bartlomiej Zolnierkiewicz   cmd640: always au...
389
  #else
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
390

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
  /*
   * Sets prefetch mode for a drive.
   */
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
394
  static void set_prefetch_mode(ide_drive_t *drive, unsigned int index, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
  {
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
396
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
  	int reg = prefetch_regs[index];
  	u8 b;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399

5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
400
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  	b = __get_cmd640_reg(reg);
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
402
403
  	__set_prefetch_mode(drive, mode);
  	if (mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  		b &= ~prefetch_masks[index];	/* enable prefetch */
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
405
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
  		b |= prefetch_masks[index];	/* disable prefetch */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  	__put_cmd640_reg(reg, b);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
408
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
413
  }
  
  /*
   * Dump out current drive clocks settings
   */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
414
  static void display_clocks(unsigned int index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  {
  	u8 active_count, recovery_count;
  
  	active_count = active_counts[index];
  	if (active_count == 1)
  		++active_count;
  	recovery_count = recovery_counts[index];
  	if (active_count > 3 && recovery_count == 1)
  		++recovery_count;
  	if (cmd640_chip_version > 1)
  		recovery_count += 1;  /* cmd640b uses (count + 1)*/
  	printk(", clocks=%d/%d/%d
  ", setup_counts[index], active_count, recovery_count);
  }
  
  /*
   * Pack active and recovery counts into single byte representation
   * used by controller
   */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
434
  static inline u8 pack_nibbles(u8 upper, u8 lower)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
438
439
  {
  	return ((upper & 0x0f) << 4) | (lower & 0x0f);
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
442
   * This routine writes the prepared setup/active/recovery counts
   * for a drive into the cmd640 chipset registers to active them.
   */
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
443
  static void program_drive_counts(ide_drive_t *drive, unsigned int index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
446
447
448
449
450
451
452
453
454
455
456
  {
  	unsigned long flags;
  	u8 setup_count    = setup_counts[index];
  	u8 active_count   = active_counts[index];
  	u8 recovery_count = recovery_counts[index];
  
  	/*
  	 * Set up address setup count and drive read/write timing registers.
  	 * Primary interface has individual count/timing registers for
  	 * each drive.  Secondary interface has one common set of registers,
  	 * so we merge the timings, using the slowest value for each timing.
  	 */
  	if (index > 1) {
2b78ff523   Bartlomiej Zolnierkiewicz   cmd640: use ide_g...
457
  		ide_drive_t *peer = ide_get_pair_dev(drive);
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
458
  		unsigned int mate = index ^ 1;
2b78ff523   Bartlomiej Zolnierkiewicz   cmd640: use ide_g...
459
  		if (peer) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
462
463
464
465
466
467
468
469
470
471
472
  			if (setup_count < setup_counts[mate])
  				setup_count = setup_counts[mate];
  			if (active_count < active_counts[mate])
  				active_count = active_counts[mate];
  			if (recovery_count < recovery_counts[mate])
  				recovery_count = recovery_counts[mate];
  		}
  	}
  
  	/*
  	 * Convert setup_count to internal chipset representation
  	 */
  	switch (setup_count) {
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
473
474
475
476
477
  	case 4:	 setup_count = 0x00; break;
  	case 3:	 setup_count = 0x80; break;
  	case 1:
  	case 2:	 setup_count = 0x40; break;
  	default: setup_count = 0xc0; /* case 5 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
480
481
482
  	}
  
  	/*
  	 * Now that everything is ready, program the new timings
  	 */
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
483
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
488
489
490
491
  	/*
  	 * Program the address_setup clocks into ARTTIM reg,
  	 * and then the active/recovery counts into the DRWTIM reg
  	 * (this converts counts of 16 into counts of zero -- okay).
  	 */
  	setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f;
  	__put_cmd640_reg(arttim_regs[index], setup_count);
  	__put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
492
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
497
  }
  
  /*
   * Set a specific pio_mode for a drive
   */
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
498
499
  static void cmd640_set_mode(ide_drive_t *drive, unsigned int index,
  			    u8 pio_mode, unsigned int cycle_time)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  {
17b500de0   Bartlomiej Zolnierkiewicz   cmd640: convert t...
501
  	struct ide_timing *t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
  	int setup_time, active_time, recovery_time, clock_time;
  	u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
ebae41a5a   Bartlomiej Zolnierkiewicz   ide: add "vlb|pci...
504
  	int bus_speed;
30e5ee4d1   Bartlomiej Zolnierkiewicz   ide: remove obsol...
505
506
  	if (cmd640_vlb)
  		bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
ebae41a5a   Bartlomiej Zolnierkiewicz   ide: add "vlb|pci...
507
  	else
30e5ee4d1   Bartlomiej Zolnierkiewicz   ide: remove obsol...
508
  		bus_speed = ide_pci_clk ? ide_pci_clk : 33;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
  
  	if (pio_mode > 5)
  		pio_mode = 5;
17b500de0   Bartlomiej Zolnierkiewicz   cmd640: convert t...
512
513
514
515
  
  	t = ide_timing_find_mode(XFER_PIO_0 + pio_mode);
  	setup_time  = t->setup;
  	active_time = t->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  	recovery_time = cycle_time - (setup_time + active_time);
  	clock_time = 1000 / bus_speed;
00fe8b7ac   Julia Lawall   ide: use DIV_ROUN...
518
  	cycle_count = DIV_ROUND_UP(cycle_time, clock_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519

00fe8b7ac   Julia Lawall   ide: use DIV_ROUN...
520
  	setup_count = DIV_ROUND_UP(setup_time, clock_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521

00fe8b7ac   Julia Lawall   ide: use DIV_ROUN...
522
  	active_count = DIV_ROUND_UP(active_time, clock_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
  	if (active_count < 2)
  		active_count = 2; /* minimum allowed by cmd640 */
00fe8b7ac   Julia Lawall   ide: use DIV_ROUN...
525
  	recovery_count = DIV_ROUND_UP(recovery_time, clock_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
  	recovery_count2 = cycle_count - (setup_count + active_count);
  	if (recovery_count2 > recovery_count)
  		recovery_count = recovery_count2;
  	if (recovery_count < 2)
  		recovery_count = 2; /* minimum allowed by cmd640 */
  	if (recovery_count > 17) {
  		active_count += recovery_count - 17;
  		recovery_count = 17;
  	}
  	if (active_count > 16)
  		active_count = 16; /* maximum allowed by cmd640 */
  	if (cmd640_chip_version > 1)
  		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
  	if (recovery_count > 16)
  		recovery_count = 16; /* maximum allowed by cmd640 */
  
  	setup_counts[index]    = setup_count;
  	active_counts[index]   = active_count;
  	recovery_counts[index] = recovery_count;
  
  	/*
  	 * In a perfect world, we might set the drive pio mode here
  	 * (using WIN_SETFEATURE) before continuing.
  	 *
  	 * But we do not, because:
  	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
  	 * 	2) in practice this is rarely, if ever, necessary
  	 */
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
554
  	program_drive_counts(drive, index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  }
e085b3cae   Bartlomiej Zolnierkiewicz   ide: change ->set...
556
  static void cmd640_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  {
7dd00083b   Bartlomiej Zolnierkiewicz   ide: add ide_pio_...
558
  	unsigned int index = 0, cycle_time;
e085b3cae   Bartlomiej Zolnierkiewicz   ide: change ->set...
559
  	const u8 pio = drive->pio_mode - XFER_PIO_0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
  	u8 b;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561

26bcb879c   Bartlomiej Zolnierkiewicz   ide: add ide_set{...
562
  	switch (pio) {
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
  	case 6: /* set fast-devsel off */
  	case 7: /* set fast-devsel on */
  		b = get_cmd640_reg(CNTRL) & ~0x27;
  		if (pio & 1)
  			b |= 0x27;
  		put_cmd640_reg(CNTRL, b);
  		printk("%s: %sabled cmd640 fast host timing (devsel)
  ",
  			drive->name, (pio & 1) ? "en" : "dis");
  		return;
  	case 8: /* set prefetch off */
  	case 9: /* set prefetch on */
  		set_prefetch_mode(drive, index, pio & 1);
  		printk("%s: %sabled cmd640 prefetch
  ",
  			drive->name, (pio & 1) ? "en" : "dis");
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	}
26bcb879c   Bartlomiej Zolnierkiewicz   ide: add ide_set{...
581
  	cycle_time = ide_pio_cycle_time(drive, pio);
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
582
  	cmd640_set_mode(drive, index, pio, cycle_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583

342cdb6d4   Bartlomiej Zolnierkiewicz   ide: make ide_get...
584
  	printk("%s: selected cmd640 PIO mode%d (%dns)",
26bcb879c   Bartlomiej Zolnierkiewicz   ide: add ide_set{...
585
  		drive->name, pio, cycle_time);
342cdb6d4   Bartlomiej Zolnierkiewicz   ide: make ide_get...
586

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  	display_clocks(index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  }
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
589
  #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
8495fb1b8   Chris Frey   ide: fixed sectio...
590
  static void __init cmd640_init_dev(ide_drive_t *drive)
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
591
  {
123995b97   Bartlomiej Zolnierkiewicz   ide: use 'drive->...
592
  	unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1);
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  
  #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
  	/*
  	 * Reset timing to the slowest speed and turn off prefetch.
  	 * This way, the drive identify code has a better chance.
  	 */
  	setup_counts[i]    =  4;	/* max possible */
  	active_counts[i]   = 16;	/* max possible */
  	recovery_counts[i] = 16;	/* max possible */
  	program_drive_counts(drive, i);
  	set_prefetch_mode(drive, i, 0);
  	printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch cleared
  ", i);
  #else
  	/*
  	 * Set the drive unmask flags to match the prefetch setting.
  	 */
  	check_prefetch(drive, i);
  	printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch(%s) preserved
  ",
97100fc81   Bartlomiej Zolnierkiewicz   ide: add device f...
613
  		i, (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) ? "off" : "on");
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
614
615
  #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
  }
87441db22   Sergei Shtylyov   cmd640: implement...
616
617
  static int cmd640_test_irq(ide_hwif_t *hwif)
  {
87441db22   Sergei Shtylyov   cmd640: implement...
618
  	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
a9ddabc52   Sergei Shtylyov   cmd640: fix kerne...
619
  	u8  irq_mask		= hwif->channel ? ARTTIM23_IDE23INTR :
87441db22   Sergei Shtylyov   cmd640: implement...
620
  						  CFR_IDE01INTR;
a9ddabc52   Sergei Shtylyov   cmd640: fix kerne...
621
  	u8  irq_stat		= get_cmd640_reg(irq_reg);
87441db22   Sergei Shtylyov   cmd640: implement...
622
623
624
  
  	return (irq_stat & irq_mask) ? 1 : 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625

ac95beedf   Bartlomiej Zolnierkiewicz   ide: add struct i...
626
  static const struct ide_port_ops cmd640_port_ops = {
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
627
628
  	.init_dev		= cmd640_init_dev,
  #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
ac95beedf   Bartlomiej Zolnierkiewicz   ide: add struct i...
629
  	.set_pio_mode		= cmd640_set_pio_mode,
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
630
  #endif
87441db22   Sergei Shtylyov   cmd640: implement...
631
  	.test_irq		= cmd640_test_irq,
ac95beedf   Bartlomiej Zolnierkiewicz   ide: add struct i...
632
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
635
  
  static int pci_conf1(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  	unsigned long flags;
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
637
  	u32 tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638

5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
639
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
644
  	outb(0x01, 0xCFB);
  	tmp = inl(0xCF8);
  	outl(0x80000000, 0xCF8);
  	if (inl(0xCF8) == 0x80000000) {
  		outl(tmp, 0xCF8);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
645
  		spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
  		return 1;
  	}
  	outl(tmp, 0xCF8);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
649
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
654
655
  	return 0;
  }
  
  static int pci_conf2(void)
  {
  	unsigned long flags;
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
656
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
659
660
  	outb(0x00, 0xCFB);
  	outb(0x00, 0xCF8);
  	outb(0x00, 0xCFA);
  	if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
661
  		spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
  		return 1;
  	}
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
664
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
  	return 0;
  }
c413b9b94   Bartlomiej Zolnierkiewicz   ide: add struct i...
667
668
669
670
  static const struct ide_port_info cmd640_port_info __initdata = {
  	.chipset		= ide_cmd640,
  	.host_flags		= IDE_HFLAG_SERIALIZE |
  				  IDE_HFLAG_NO_DMA |
c413b9b94   Bartlomiej Zolnierkiewicz   ide: add struct i...
671
672
  				  IDE_HFLAG_ABUSE_PREFETCH |
  				  IDE_HFLAG_ABUSE_FAST_DEVSEL,
ac95beedf   Bartlomiej Zolnierkiewicz   ide: add struct i...
673
  	.port_ops		= &cmd640_port_ops,
c413b9b94   Bartlomiej Zolnierkiewicz   ide: add struct i...
674
  	.pio_mask		= ATA_PIO5,
c413b9b94   Bartlomiej Zolnierkiewicz   ide: add struct i...
675
  };
7ebe5936c   Bartlomiej Zolnierkiewicz   cmd640: manage I/...
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
  static int cmd640x_init_one(unsigned long base, unsigned long ctl)
  {
  	if (!request_region(base, 8, DRV_NAME)) {
  		printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.
  ",
  				DRV_NAME, base, base + 7);
  		return -EBUSY;
  	}
  
  	if (!request_region(ctl, 1, DRV_NAME)) {
  		printk(KERN_ERR "%s: I/O resource 0x%lX not free.
  ",
  				DRV_NAME, ctl);
  		release_region(base, 8);
  		return -EBUSY;
  	}
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  /*
ade2daf9c   Bartlomiej Zolnierkiewicz   ide: make remaini...
696
   * Probe for a cmd640 chipset, and initialize it if found.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
   */
ade2daf9c   Bartlomiej Zolnierkiewicz   ide: make remaini...
698
  static int __init cmd640x_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
  {
7ebe5936c   Bartlomiej Zolnierkiewicz   cmd640: manage I/...
700
  	int second_port_cmd640 = 0, rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
  	const char *bus_type, *port2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
  	u8 b, cfr;
9f36d3143   Bartlomiej Zolnierkiewicz   ide: remove hw_re...
703
  	struct ide_hw hw[2], *hws[2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
  
  	if (cmd640_vlb && probe_for_cmd640_vlb()) {
  		bus_type = "VLB";
  	} else {
  		cmd640_vlb = 0;
  		/* Find out what kind of PCI probing is supported otherwise
  		   Justin Gibbs will sulk.. */
  		if (pci_conf1() && probe_for_cmd640_pci1())
  			bus_type = "PCI (type1)";
  		else if (pci_conf2() && probe_for_cmd640_pci2())
  			bus_type = "PCI (type2)";
  		else
  			return 0;
  	}
  	/*
  	 * Undocumented magic (there is no 0x5b reg in specs)
  	 */
  	put_cmd640_reg(0x5b, 0xbd);
  	if (get_cmd640_reg(0x5b) != 0xbd) {
  		printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b
  ");
  		return 0;
  	}
  	put_cmd640_reg(0x5b, 0);
  
  #ifdef CMD640_DUMP_REGS
  	cmd640_dump_regs();
  #endif
  
  	/*
  	 * Documented magic begins here
  	 */
  	cfr = get_cmd640_reg(CFR);
  	cmd640_chip_version = cfr & CFR_DEVREV;
  	if (cmd640_chip_version == 0) {
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
739
740
  		printk("ide: bad cmd640 revision: %d
  ", cmd640_chip_version);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
  		return 0;
  	}
7ebe5936c   Bartlomiej Zolnierkiewicz   cmd640: manage I/...
743
744
745
746
747
748
749
750
751
752
  	rc = cmd640x_init_one(0x1f0, 0x3f6);
  	if (rc)
  		return rc;
  
  	rc = cmd640x_init_one(0x170, 0x376);
  	if (rc) {
  		release_region(0x3f6, 1);
  		release_region(0x1f0, 8);
  		return rc;
  	}
6d3803b68   Bartlomiej Zolnierkiewicz   cmd640: init hwif...
753
754
755
756
757
758
759
760
761
762
763
  	memset(&hw, 0, sizeof(hw));
  
  	ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
  	hw[0].irq = 14;
  
  	ide_std_init_ports(&hw[1], 0x170, 0x376);
  	hw[1].irq = 15;
  
  	printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x"
  			 "
  ", 'a' + cmd640_chip_version - 1, bus_type, cfr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
766
  	/*
  	 * Initialize data for primary port
  	 */
48c3c1072   Bartlomiej Zolnierkiewicz   ide: add struct i...
767
  	hws[0] = &hw[0];
8ac4ce742   Bartlomiej Zolnierkiewicz   ide: fix host dri...
768

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
771
772
773
774
775
776
777
  	/*
  	 * Ensure compatibility by always using the slowest timings
  	 * for access to the drive's command register block,
  	 * and reset the prefetch burstsize to default (512 bytes).
  	 *
  	 * Maybe we need a way to NOT do these on *some* systems?
  	 */
  	put_cmd640_reg(CMDTIM, 0);
  	put_cmd640_reg(BRST, 0x40);
a698400a1   Bartlomiej Zolnierkiewicz   cmd640: fix warm-...
778
  	b = get_cmd640_reg(CNTRL);
84f05df49   Bartlomiej Zolnierkiewicz   cmd640: use ide_f...
779

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
  	/*
  	 * Try to enable the secondary interface, if not already enabled
  	 */
a698400a1   Bartlomiej Zolnierkiewicz   cmd640: fix warm-...
783
784
785
786
787
788
789
790
791
  	if (secondary_port_responding()) {
  		if ((b & CNTRL_ENA_2ND)) {
  			second_port_cmd640 = 1;
  			port2 = "okay";
  		} else if (cmd640_vlb) {
  			second_port_cmd640 = 1;
  			port2 = "alive";
  		} else
  			port2 = "not cmd640";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
  	} else {
a698400a1   Bartlomiej Zolnierkiewicz   cmd640: fix warm-...
793
  		put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  		if (secondary_port_responding()) {
a698400a1   Bartlomiej Zolnierkiewicz   cmd640: fix warm-...
795
796
  			second_port_cmd640 = 1;
  			port2 = "enabled";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
  		} else {
a698400a1   Bartlomiej Zolnierkiewicz   cmd640: fix warm-...
798
799
  			put_cmd640_reg(CNTRL, b); /* restore original setting */
  			port2 = "not responding";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
802
803
804
805
  		}
  	}
  
  	/*
  	 * Initialize data for secondary cmd640 port, if enabled
  	 */
48c3c1072   Bartlomiej Zolnierkiewicz   ide: add struct i...
806
807
  	if (second_port_cmd640)
  		hws[1] = &hw[1];
84f05df49   Bartlomiej Zolnierkiewicz   cmd640: use ide_f...
808
809
  	printk(KERN_INFO "cmd640: %sserialized, secondary interface %s
  ",
c413b9b94   Bartlomiej Zolnierkiewicz   ide: add struct i...
810
  			 second_port_cmd640 ? "" : "not ", port2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
813
814
  #ifdef CMD640_DUMP_REGS
  	cmd640_dump_regs();
  #endif
8ac4ce742   Bartlomiej Zolnierkiewicz   ide: fix host dri...
815

dca398305   Bartlomiej Zolnierkiewicz   ide: pass number ...
816
817
  	return ide_host_add(&cmd640_port_info, hws, second_port_cmd640 ? 2 : 1,
  			    NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
  }
ade2daf9c   Bartlomiej Zolnierkiewicz   ide: make remaini...
819
820
821
822
  module_param_named(probe_vlb, cmd640_vlb, bool, 0);
  MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset");
  
  module_init(cmd640x_init);
776c0bcee   Adrian Bunk   ide/pci/cmd640.c:...
823
824
  
  MODULE_LICENSE("GPL");