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
  #include <linux/ide.h>
  #include <linux/init.h>
bff7832dd   Paul Gortmaker   ide/ata: Add modu...
106
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
  
  #include <asm/io.h>
7ebe5936c   Bartlomiej Zolnierkiewicz   cmd640: manage I/...
109
  #define DRV_NAME "cmd640"
90ab5ee94   Rusty Russell   module_param: mak...
110
  static bool cmd640_vlb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
152
  
  /*
   * 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...
153
  #define   ARTTIM23_IDE23INTR	0x10
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  #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...
177
  static DEFINE_SPINLOCK(cmd640_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
   * 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...
197
  static void put_cmd640_reg_pci1(u16 reg, u8 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
  {
  	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
  	outb_p(val, (reg & 3) | 0xcfc);
  }
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
202
  static u8 get_cmd640_reg_pci1(u16 reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
  {
  	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...
209
  static void put_cmd640_reg_pci2(u16 reg, u8 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
214
  {
  	outb_p(0x10, 0xcf8);
  	outb_p(val, cmd640_key + reg);
  	outb_p(0, 0xcf8);
  }
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
215
  static u8 get_cmd640_reg_pci2(u16 reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
221
222
223
224
225
  {
  	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...
226
  static void put_cmd640_reg_vlb(u16 reg, u8 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
  {
  	outb_p(reg, cmd640_key);
  	outb_p(val, cmd640_key + 4);
  }
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
231
  static u8 get_cmd640_reg_vlb(u16 reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
238
  {
  	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
239
  	unsigned long flags;
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
240
  	u8 b;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241

5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
242
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
  	b = __get_cmd640_reg(reg);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
244
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
248
249
250
  	return b;
  }
  
  static void put_cmd640_reg(u16 reg, u8 val)
  {
  	unsigned long flags;
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
251
  	spin_lock_irqsave(&cmd640_lock, flags);
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
252
  	__put_cmd640_reg(reg, val);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
253
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  }
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
255
  static int __init match_pci_cmd640_device(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  {
  	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...
276
  static int __init probe_for_cmd640_pci1(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  {
  	__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...
292
  static int __init probe_for_cmd640_pci2(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
296
297
298
299
300
301
302
303
304
305
  {
  	__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...
306
  static int __init probe_for_cmd640_vlb(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  {
  	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...
327
  static int __init secondary_port_responding(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
  {
  	unsigned long flags;
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
330
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331

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

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

5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
401
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  	b = __get_cmd640_reg(reg);
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
403
404
  	__set_prefetch_mode(drive, mode);
  	if (mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  		b &= ~prefetch_masks[index];	/* enable prefetch */
af5dfe8cf   Bartlomiej Zolnierkiewicz   cmd640: add __set...
406
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  		b |= prefetch_masks[index];	/* disable prefetch */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  	__put_cmd640_reg(reg, b);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
409
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
413
414
  }
  
  /*
   * Dump out current drive clocks settings
   */
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
415
  static void display_clocks(unsigned int index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  {
  	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...
435
  static inline u8 pack_nibbles(u8 upper, u8 lower)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
439
440
  {
  	return ((upper & 0x0f) << 4) | (lower & 0x0f);
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
   * 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...
444
  static void program_drive_counts(ide_drive_t *drive, unsigned int index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
451
452
453
454
455
456
457
  {
  	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...
458
  		ide_drive_t *peer = ide_get_pair_dev(drive);
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
459
  		unsigned int mate = index ^ 1;
2b78ff523   Bartlomiej Zolnierkiewicz   cmd640: use ide_g...
460
  		if (peer) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
467
468
469
470
471
472
473
  			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...
474
475
476
477
478
  	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
479
480
481
482
483
  	}
  
  	/*
  	 * Now that everything is ready, program the new timings
  	 */
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
484
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
488
489
490
491
492
  	/*
  	 * 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...
493
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
498
  }
  
  /*
   * Set a specific pio_mode for a drive
   */
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
499
500
  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
501
  {
17b500de0   Bartlomiej Zolnierkiewicz   cmd640: convert t...
502
  	struct ide_timing *t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
  	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...
505
  	int bus_speed;
30e5ee4d1   Bartlomiej Zolnierkiewicz   ide: remove obsol...
506
507
  	if (cmd640_vlb)
  		bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
ebae41a5a   Bartlomiej Zolnierkiewicz   ide: add "vlb|pci...
508
  	else
30e5ee4d1   Bartlomiej Zolnierkiewicz   ide: remove obsol...
509
  		bus_speed = ide_pci_clk ? ide_pci_clk : 33;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
  
  	if (pio_mode > 5)
  		pio_mode = 5;
17b500de0   Bartlomiej Zolnierkiewicz   cmd640: convert t...
513
514
515
516
  
  	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
517
518
  	recovery_time = cycle_time - (setup_time + active_time);
  	clock_time = 1000 / bus_speed;
00fe8b7ac   Julia Lawall   ide: use DIV_ROUN...
519
  	cycle_count = DIV_ROUND_UP(cycle_time, clock_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520

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

00fe8b7ac   Julia Lawall   ide: use DIV_ROUN...
523
  	active_count = DIV_ROUND_UP(active_time, clock_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
  	if (active_count < 2)
  		active_count = 2; /* minimum allowed by cmd640 */
00fe8b7ac   Julia Lawall   ide: use DIV_ROUN...
526
  	recovery_count = DIV_ROUND_UP(recovery_time, clock_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
554
  	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...
555
  	program_drive_counts(drive, index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  }
e085b3cae   Bartlomiej Zolnierkiewicz   ide: change ->set...
557
  static void cmd640_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  {
7dd00083b   Bartlomiej Zolnierkiewicz   ide: add ide_pio_...
559
  	unsigned int index = 0, cycle_time;
e085b3cae   Bartlomiej Zolnierkiewicz   ide: change ->set...
560
  	const u8 pio = drive->pio_mode - XFER_PIO_0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  	u8 b;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562

26bcb879c   Bartlomiej Zolnierkiewicz   ide: add ide_set{...
563
  	switch (pio) {
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  	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
581
  	}
26bcb879c   Bartlomiej Zolnierkiewicz   ide: add ide_set{...
582
  	cycle_time = ide_pio_cycle_time(drive, pio);
9523076ac   Bartlomiej Zolnierkiewicz   cmd640: remove cm...
583
  	cmd640_set_mode(drive, index, pio, cycle_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  	display_clocks(index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  }
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
590
  #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
8495fb1b8   Chris Frey   ide: fixed sectio...
591
  static void __init cmd640_init_dev(ide_drive_t *drive)
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
592
  {
123995b97   Bartlomiej Zolnierkiewicz   ide: use 'drive->...
593
  	unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1);
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
  
  #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...
614
  		i, (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) ? "off" : "on");
b48c89a96   Bartlomiej Zolnierkiewicz   cmd640: add ->ini...
615
616
  #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
  }
87441db22   Sergei Shtylyov   cmd640: implement...
617
618
  static int cmd640_test_irq(ide_hwif_t *hwif)
  {
87441db22   Sergei Shtylyov   cmd640: implement...
619
  	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
a9ddabc52   Sergei Shtylyov   cmd640: fix kerne...
620
  	u8  irq_mask		= hwif->channel ? ARTTIM23_IDE23INTR :
87441db22   Sergei Shtylyov   cmd640: implement...
621
  						  CFR_IDE01INTR;
a9ddabc52   Sergei Shtylyov   cmd640: fix kerne...
622
  	u8  irq_stat		= get_cmd640_reg(irq_reg);
87441db22   Sergei Shtylyov   cmd640: implement...
623
624
625
  
  	return (irq_stat & irq_mask) ? 1 : 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626

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

5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
640
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
  	outb(0x01, 0xCFB);
  	tmp = inl(0xCF8);
  	outl(0x80000000, 0xCF8);
  	if (inl(0xCF8) == 0x80000000) {
  		outl(tmp, 0xCF8);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
646
  		spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
  		return 1;
  	}
  	outl(tmp, 0xCF8);
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
650
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
655
656
  	return 0;
  }
  
  static int pci_conf2(void)
  {
  	unsigned long flags;
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
657
  	spin_lock_irqsave(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
659
660
661
  	outb(0x00, 0xCFB);
  	outb(0x00, 0xCF8);
  	outb(0x00, 0xCFA);
  	if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
662
  		spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
  		return 1;
  	}
5bbcf9242   Bartlomiej Zolnierkiewicz   cmd640: fix deadl...
665
  	spin_unlock_irqrestore(&cmd640_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
667
  	return 0;
  }
c413b9b94   Bartlomiej Zolnierkiewicz   ide: add struct i...
668
669
670
671
  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...
672
673
  				  IDE_HFLAG_ABUSE_PREFETCH |
  				  IDE_HFLAG_ABUSE_FAST_DEVSEL,
ac95beedf   Bartlomiej Zolnierkiewicz   ide: add struct i...
674
  	.port_ops		= &cmd640_port_ops,
c413b9b94   Bartlomiej Zolnierkiewicz   ide: add struct i...
675
  	.pio_mask		= ATA_PIO5,
c413b9b94   Bartlomiej Zolnierkiewicz   ide: add struct i...
676
  };
7ebe5936c   Bartlomiej Zolnierkiewicz   cmd640: manage I/...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
  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
696
  /*
ade2daf9c   Bartlomiej Zolnierkiewicz   ide: make remaini...
697
   * Probe for a cmd640 chipset, and initialize it if found.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
   */
ade2daf9c   Bartlomiej Zolnierkiewicz   ide: make remaini...
699
  static int __init cmd640x_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  {
7ebe5936c   Bartlomiej Zolnierkiewicz   cmd640: manage I/...
701
  	int second_port_cmd640 = 0, rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
  	const char *bus_type, *port2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
  	u8 b, cfr;
9f36d3143   Bartlomiej Zolnierkiewicz   ide: remove hw_re...
704
  	struct ide_hw hw[2], *hws[2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
739
  
  	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...
740
741
  		printk("ide: bad cmd640 revision: %d
  ", cmd640_chip_version);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
  		return 0;
  	}
7ebe5936c   Bartlomiej Zolnierkiewicz   cmd640: manage I/...
744
745
746
747
748
749
750
751
752
753
  	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...
754
755
756
757
758
759
760
761
762
763
764
  	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
765
766
767
  	/*
  	 * Initialize data for primary port
  	 */
48c3c1072   Bartlomiej Zolnierkiewicz   ide: add struct i...
768
  	hws[0] = &hw[0];
8ac4ce742   Bartlomiej Zolnierkiewicz   ide: fix host dri...
769

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
772
773
774
775
776
777
778
  	/*
  	 * 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-...
779
  	b = get_cmd640_reg(CNTRL);
84f05df49   Bartlomiej Zolnierkiewicz   cmd640: use ide_f...
780

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

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

dca398305   Bartlomiej Zolnierkiewicz   ide: pass number ...
817
818
  	return ide_host_add(&cmd640_port_info, hws, second_port_cmd640 ? 2 : 1,
  			    NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
  }
ade2daf9c   Bartlomiej Zolnierkiewicz   ide: make remaini...
820
821
822
823
  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:...
824
825
  
  MODULE_LICENSE("GPL");