Blame view

drivers/ide/cmd640.c 22.5 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
   *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
   */
  
  /*
   *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
8
   *			mlord@pobox.com (Mark Lord)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
98
   *
   *  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
99
  #define CMD640_PREFETCH_MASKS 1
4752b5e77   Paolo Ciarrocchi   IDE: Coding Style...
100
  /*#define CMD640_DUMP_REGS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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