cmd64x.c 13.3 KB
Newer Older
1
/*
Linus Torvalds's avatar
Linus Torvalds committed
2 3 4 5 6 7 8 9
 * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
 *           Due to massive hardware bugs, UltraDMA is only supported
 *           on the 646U2 and not on the 646U.
 *
 * Copyright (C) 1998		Eddie C. Dost  (ecd@skynet.be)
 * Copyright (C) 1998		David S. Miller (davem@redhat.com)
 *
 * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
10
 * Copyright (C) 2007,2009	MontaVista Software, Inc. <source@mvista.com>
Linus Torvalds's avatar
Linus Torvalds committed
11 12 13 14 15 16 17 18 19 20
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/ide.h>
#include <linux/init.h>

#include <asm/io.h>

21 22
#define DRV_NAME "cmd64x"

Linus Torvalds's avatar
Linus Torvalds committed
23 24 25 26 27 28 29 30 31 32 33 34
#define CMD_DEBUG 0

#if CMD_DEBUG
#define cmdprintk(x...)	printk(x)
#else
#define cmdprintk(x...)
#endif

/*
 * CMD64x specific registers definition.
 */
#define CFR		0x50
35
#define   CFR_INTR_CH0		0x04
Linus Torvalds's avatar
Linus Torvalds committed
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

#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
#define   ARTTIM23_INTR_CH1	0x10
#define DRWTIM2		0x58
#define BRST		0x59
#define DRWTIM3		0x5b

#define BMIDECR0	0x70
#define MRDMODE		0x71
#define   MRDMODE_INTR_CH0	0x04
#define   MRDMODE_INTR_CH1	0x08
#define UDIDETCR0	0x73
#define DTPR0		0x74
#define BMIDECR1	0x78
#define BMIDECSR	0x79
#define UDIDETCR1	0x7B
#define DTPR1		0x7C

61 62 63 64 65
static u8 quantize_timing(int timing, int quant)
{
	return (timing + quant - 1) / quant;
}

Linus Torvalds's avatar
Linus Torvalds committed
66
/*
67 68
 * This routine calculates active/recovery counts and then writes them into
 * the chipset registers.
Linus Torvalds's avatar
Linus Torvalds committed
69
 */
70
static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
Linus Torvalds's avatar
Linus Torvalds committed
71
{
72
	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
73
	int clock_time = 1000 / (ide_pci_clk ? ide_pci_clk : 33);
74 75
	u8  cycle_count, active_count, recovery_count, drwtim;
	static const u8 recovery_values[] =
Linus Torvalds's avatar
Linus Torvalds committed
76
		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
77 78 79 80 81 82 83 84 85
	static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};

	cmdprintk("program_cycle_times parameters: total=%d, active=%d\n",
		  cycle_time, active_time);

	cycle_count	= quantize_timing( cycle_time, clock_time);
	active_count	= quantize_timing(active_time, clock_time);
	recovery_count	= cycle_count - active_count;

Linus Torvalds's avatar
Linus Torvalds committed
86
	/*
87 88
	 * In case we've got too long recovery phase, try to lengthen
	 * the active phase
Linus Torvalds's avatar
Linus Torvalds committed
89
	 */
90 91 92
	if (recovery_count > 16) {
		active_count += recovery_count - 16;
		recovery_count = 16;
Linus Torvalds's avatar
Linus Torvalds committed
93
	}
94 95 96 97 98
	if (active_count > 16)		/* shouldn't actually happen... */
	 	active_count = 16;

	cmdprintk("Final counts: total=%d, active=%d, recovery=%d\n",
		  cycle_count, active_count, recovery_count);
Linus Torvalds's avatar
Linus Torvalds committed
99 100 101 102

	/*
	 * Convert values to internal chipset representation
	 */
103 104
	recovery_count = recovery_values[recovery_count];
 	active_count  &= 0x0f;
Linus Torvalds's avatar
Linus Torvalds committed
105

106 107 108 109
	/* Program the active/recovery counts into the DRWTIM register */
	drwtim = (active_count << 4) | recovery_count;
	(void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim);
	cmdprintk("Write 0x%02x to reg 0x%x\n", drwtim, drwtim_regs[drive->dn]);
Linus Torvalds's avatar
Linus Torvalds committed
110 111 112
}

/*
113 114
 * This routine writes into the chipset registers
 * PIO setup/active/recovery timings.
Linus Torvalds's avatar
Linus Torvalds committed
115
 */
116
static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
Linus Torvalds's avatar
Linus Torvalds committed
117
{
118
	ide_hwif_t *hwif	= drive->hwif;
119
	struct pci_dev *dev	= to_pci_dev(hwif->dev);
120
	struct ide_timing *t	= ide_timing_find_mode(XFER_PIO_0 + pio);
121
	unsigned long setup_count;
122
	unsigned int cycle_time;
123
	u8 arttim = 0;
124

125 126
	static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
	static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
127

128
	cycle_time = ide_pio_cycle_time(drive, pio);
Linus Torvalds's avatar
Linus Torvalds committed
129

130
	program_cycle_times(drive, cycle_time, t->active);
Linus Torvalds's avatar
Linus Torvalds committed
131

132
	setup_count = quantize_timing(t->setup,
133
			1000 / (ide_pci_clk ? ide_pci_clk : 33));
134 135 136 137 138 139 140 141

	/*
	 * The primary channel has individual address setup timing registers
	 * for each drive and the hardware selects the slowest timing itself.
	 * The secondary channel has one common register and we have to select
	 * the slowest address setup timing ourselves.
	 */
	if (hwif->channel) {
142
		ide_drive_t *pair = ide_get_pair_dev(drive);
143

144
		ide_set_drivedata(drive, (void *)setup_count);
145 146

		if (pair)
147 148
			setup_count = max_t(u8, setup_count,
					(unsigned long)ide_get_drivedata(pair));
Linus Torvalds's avatar
Linus Torvalds committed
149 150
	}

151 152 153
	if (setup_count > 5)		/* shouldn't actually happen... */
		setup_count = 5;
	cmdprintk("Final address setup count: %d\n", setup_count);
Linus Torvalds's avatar
Linus Torvalds committed
154

155 156 157 158 159 160 161 162 163 164 165
	/*
	 * Program the address setup clocks into the ARTTIM registers.
	 * Avoid clearing the secondary channel's interrupt bit.
	 */
	(void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim);
	if (hwif->channel)
		arttim &= ~ARTTIM23_INTR_CH1;
	arttim &= ~0xc0;
	arttim |= setup_values[setup_count];
	(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
	cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]);
166 167 168 169
}

/*
 * Attempts to set drive's PIO mode.
170
 * Special cases are 8: prefetch off, 9: prefetch on (both never worked)
171
 */
172 173

static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
174 175 176 177 178 179 180 181
{
	/*
	 * Filter out the prefetch control values
	 * to prevent PIO5 from being programmed
	 */
	if (pio == 8 || pio == 9)
		return;

182
	cmd64x_tune_pio(drive, pio);
Linus Torvalds's avatar
Linus Torvalds committed
183 184
}

185
static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
Linus Torvalds's avatar
Linus Torvalds committed
186
{
187
	ide_hwif_t *hwif	= drive->hwif;
188
	struct pci_dev *dev	= to_pci_dev(hwif->dev);
189 190
	u8 unit			= drive->dn & 0x01;
	u8 regU = 0, pciU	= hwif->channel ? UDIDETCR1 : UDIDETCR0;
Linus Torvalds's avatar
Linus Torvalds committed
191

192
	if (speed >= XFER_SW_DMA_0) {
Linus Torvalds's avatar
Linus Torvalds committed
193 194 195 196 197
		(void) pci_read_config_byte(dev, pciU, &regU);
		regU &= ~(unit ? 0xCA : 0x35);
	}

	switch(speed) {
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
	case XFER_UDMA_5:
		regU |= unit ? 0x0A : 0x05;
		break;
	case XFER_UDMA_4:
		regU |= unit ? 0x4A : 0x15;
		break;
	case XFER_UDMA_3:
		regU |= unit ? 0x8A : 0x25;
		break;
	case XFER_UDMA_2:
		regU |= unit ? 0x42 : 0x11;
		break;
	case XFER_UDMA_1:
		regU |= unit ? 0x82 : 0x21;
		break;
	case XFER_UDMA_0:
		regU |= unit ? 0xC2 : 0x31;
		break;
	case XFER_MW_DMA_2:
		program_cycle_times(drive, 120, 70);
		break;
	case XFER_MW_DMA_1:
		program_cycle_times(drive, 150, 80);
		break;
	case XFER_MW_DMA_0:
		program_cycle_times(drive, 480, 215);
		break;
Linus Torvalds's avatar
Linus Torvalds committed
225 226
	}

227
	if (speed >= XFER_SW_DMA_0)
Linus Torvalds's avatar
Linus Torvalds committed
228 229 230
		(void) pci_write_config_byte(dev, pciU, regU);
}

231
static void cmd648_clear_irq(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
232
{
233
	ide_hwif_t *hwif	= drive->hwif;
234 235
	struct pci_dev *dev	= to_pci_dev(hwif->dev);
	unsigned long base	= pci_resource_start(dev, 4);
236 237
	u8  irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
						  MRDMODE_INTR_CH0;
238
	u8  mrdmode		= inb(base + 1);
239 240

	/* clear the interrupt bit */
241
	outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
242
	     base + 1);
Linus Torvalds's avatar
Linus Torvalds committed
243 244
}

245
static void cmd64x_clear_irq(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
246
{
247
	ide_hwif_t *hwif	= drive->hwif;
248
	struct pci_dev *dev	= to_pci_dev(hwif->dev);
249 250 251 252
	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
	u8  irq_mask		= hwif->channel ? ARTTIM23_INTR_CH1 :
						  CFR_INTR_CH0;
	u8  irq_stat		= 0;
Linus Torvalds's avatar
Linus Torvalds committed
253

254 255 256 257 258
	(void) pci_read_config_byte(dev, irq_reg, &irq_stat);
	/* clear the interrupt bit */
	(void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask);
}

259
static int cmd648_test_irq(ide_hwif_t *hwif)
260
{
261 262
	struct pci_dev *dev	= to_pci_dev(hwif->dev);
	unsigned long base	= pci_resource_start(dev, 4);
263 264
	u8 irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
						  MRDMODE_INTR_CH0;
265
	u8 mrdmode		= inb(base + 1);
266

267 268
	pr_debug("%s: mrdmode: 0x%02x irq_mask: 0x%02x\n",
		 hwif->name, mrdmode, irq_mask);
269

270
	return (mrdmode & irq_mask) ? 1 : 0;
Linus Torvalds's avatar
Linus Torvalds committed
271 272
}

273
static int cmd64x_test_irq(ide_hwif_t *hwif)
Linus Torvalds's avatar
Linus Torvalds committed
274
{
275
	struct pci_dev *dev	= to_pci_dev(hwif->dev);
276 277 278 279
	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
	u8  irq_mask		= hwif->channel ? ARTTIM23_INTR_CH1 :
						  CFR_INTR_CH0;
	u8  irq_stat		= 0;
280 281

	(void) pci_read_config_byte(dev, irq_reg, &irq_stat);
Linus Torvalds's avatar
Linus Torvalds committed
282

283 284
	pr_debug("%s: irq_stat: 0x%02x irq_mask: 0x%02x\n",
		 hwif->name, irq_stat, irq_mask);
Linus Torvalds's avatar
Linus Torvalds committed
285

286
	return (irq_stat & irq_mask) ? 1 : 0;
Linus Torvalds's avatar
Linus Torvalds committed
287 288 289 290 291 292 293
}

/*
 * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
 * event order for DMA transfers.
 */

294
static int cmd646_1_dma_end(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
295
{
296
	ide_hwif_t *hwif = drive->hwif;
Linus Torvalds's avatar
Linus Torvalds committed
297 298 299
	u8 dma_stat = 0, dma_cmd = 0;

	/* get DMA status */
300
	dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
Linus Torvalds's avatar
Linus Torvalds committed
301
	/* read DMA command state */
302
	dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
Linus Torvalds's avatar
Linus Torvalds committed
303
	/* stop DMA */
304
	outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
Linus Torvalds's avatar
Linus Torvalds committed
305
	/* clear the INTR & ERROR bits */
306
	outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
Linus Torvalds's avatar
Linus Torvalds committed
307 308 309 310
	/* verify good DMA status */
	return (dma_stat & 7) != 4;
}

311
static int init_chipset_cmd64x(struct pci_dev *dev)
Linus Torvalds's avatar
Linus Torvalds committed
312 313 314 315 316 317 318
{
	u8 mrdmode = 0;

	/* Set a good latency timer and cache line size value. */
	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
	/* FIXME: pci_set_master() to ensure a good latency timer value */

319 320 321 322 323 324
	/*
	 * Enable interrupts, select MEMORY READ LINE for reads.
	 *
	 * NOTE: although not mentioned in the PCI0646U specs,
	 * bits 0-1 are write only and won't be read back as
	 * set or not -- PCI0646U2 specs clarify this point.
Linus Torvalds's avatar
Linus Torvalds committed
325
	 */
326 327 328
	(void) pci_read_config_byte (dev, MRDMODE, &mrdmode);
	mrdmode &= ~0x30;
	(void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
Linus Torvalds's avatar
Linus Torvalds committed
329 330 331 332

	return 0;
}

333
static u8 cmd64x_cable_detect(ide_hwif_t *hwif)
Linus Torvalds's avatar
Linus Torvalds committed
334
{
335
	struct pci_dev  *dev	= to_pci_dev(hwif->dev);
336
	u8 bmidecsr = 0, mask	= hwif->channel ? 0x02 : 0x01;
Linus Torvalds's avatar
Linus Torvalds committed
337

338 339 340 341
	switch (dev->device) {
	case PCI_DEVICE_ID_CMD_648:
	case PCI_DEVICE_ID_CMD_649:
 		pci_read_config_byte(dev, BMIDECSR, &bmidecsr);
342
		return (bmidecsr & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
343
	default:
344
		return ATA_CBL_PATA40;
Linus Torvalds's avatar
Linus Torvalds committed
345 346 347
	}
}

348 349 350
static const struct ide_port_ops cmd64x_port_ops = {
	.set_pio_mode		= cmd64x_set_pio_mode,
	.set_dma_mode		= cmd64x_set_dma_mode,
351
	.clear_irq		= cmd64x_clear_irq,
352
	.test_irq		= cmd64x_test_irq,
353 354 355 356 357 358 359
	.cable_detect		= cmd64x_cable_detect,
};

static const struct ide_port_ops cmd648_port_ops = {
	.set_pio_mode		= cmd64x_set_pio_mode,
	.set_dma_mode		= cmd64x_set_dma_mode,
	.clear_irq		= cmd648_clear_irq,
360
	.test_irq		= cmd648_test_irq,
361 362 363
	.cable_detect		= cmd64x_cable_detect,
};

364 365 366 367
static const struct ide_dma_ops cmd646_rev1_dma_ops = {
	.dma_host_set		= ide_dma_host_set,
	.dma_setup		= ide_dma_setup,
	.dma_start		= ide_dma_start,
368
	.dma_end		= cmd646_1_dma_end,
369 370
	.dma_test_irq		= ide_dma_test_irq,
	.dma_lost_irq		= ide_dma_lost_irq,
371
	.dma_timer_expiry	= ide_dma_sff_timer_expiry,
372
	.dma_sff_read_status	= ide_dma_sff_read_status,
373 374
};

375
static const struct ide_port_info cmd64x_chipsets[] __devinitdata = {
376 377
	{	/* 0: CMD643 */
		.name		= DRV_NAME,
Linus Torvalds's avatar
Linus Torvalds committed
378
		.init_chipset	= init_chipset_cmd64x,
379
		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
380
		.port_ops	= &cmd64x_port_ops,
381
		.host_flags	= IDE_HFLAG_CLEAR_SIMPLEX |
382
				  IDE_HFLAG_ABUSE_PREFETCH,
383
		.pio_mask	= ATA_PIO5,
384
		.mwdma_mask	= ATA_MWDMA2,
385
		.udma_mask	= 0x00, /* no udma */
386 387 388
	},
	{	/* 1: CMD646 */
		.name		= DRV_NAME,
Linus Torvalds's avatar
Linus Torvalds committed
389
		.init_chipset	= init_chipset_cmd64x,
390
		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
391
		.port_ops	= &cmd648_port_ops,
392
		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH,
393
		.pio_mask	= ATA_PIO5,
394 395
		.mwdma_mask	= ATA_MWDMA2,
		.udma_mask	= ATA_UDMA2,
396 397 398
	},
	{	/* 2: CMD648 */
		.name		= DRV_NAME,
Linus Torvalds's avatar
Linus Torvalds committed
399
		.init_chipset	= init_chipset_cmd64x,
400
		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
401
		.port_ops	= &cmd648_port_ops,
402
		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH,
403
		.pio_mask	= ATA_PIO5,
404 405
		.mwdma_mask	= ATA_MWDMA2,
		.udma_mask	= ATA_UDMA4,
406 407 408
	},
	{	/* 3: CMD649 */
		.name		= DRV_NAME,
Linus Torvalds's avatar
Linus Torvalds committed
409
		.init_chipset	= init_chipset_cmd64x,
410
		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
411
		.port_ops	= &cmd648_port_ops,
412
		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH,
413
		.pio_mask	= ATA_PIO5,
414 415
		.mwdma_mask	= ATA_MWDMA2,
		.udma_mask	= ATA_UDMA5,
Linus Torvalds's avatar
Linus Torvalds committed
416 417 418 419 420
	}
};

static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
421
	struct ide_port_info d;
422 423 424 425
	u8 idx = id->driver_data;

	d = cmd64x_chipsets[idx];

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	if (idx == 1) {
		/*
		 * UltraDMA only supported on PCI646U and PCI646U2, which
		 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
		 * Actually, although the CMD tech support people won't
		 * tell me the details, the 0x03 revision cannot support
		 * UDMA correctly without hardware modifications, and even
		 * then it only works with Quantum disks due to some
		 * hold time assumptions in the 646U part which are fixed
		 * in the 646U2.
		 *
		 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
		 */
		if (dev->revision < 5) {
			d.udma_mask = 0x00;
			/*
			 * The original PCI0646 didn't have the primary
			 * channel enable bit, it appeared starting with
			 * PCI0646U (i.e. revision ID 3).
			 */
			if (dev->revision < 3) {
				d.enablebits[0].reg = 0;
448
				d.port_ops = &cmd64x_port_ops;
449 450 451 452 453
				if (dev->revision == 1)
					d.dma_ops = &cmd646_rev1_dma_ops;
			}
		}
	}
454

455
	return ide_pci_init_one(dev, &d, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
456 457
}

458 459 460 461 462
static const struct pci_device_id cmd64x_pci_tbl[] = {
	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 2 },
	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 3 },
Linus Torvalds's avatar
Linus Torvalds committed
463 464 465 466
	{ 0, },
};
MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);

467
static struct pci_driver cmd64x_pci_driver = {
Linus Torvalds's avatar
Linus Torvalds committed
468 469 470
	.name		= "CMD64x_IDE",
	.id_table	= cmd64x_pci_tbl,
	.probe		= cmd64x_init_one,
471
	.remove		= ide_pci_remove,
472 473
	.suspend	= ide_pci_suspend,
	.resume		= ide_pci_resume,
Linus Torvalds's avatar
Linus Torvalds committed
474 475
};

476
static int __init cmd64x_ide_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
477
{
478
	return ide_pci_register_driver(&cmd64x_pci_driver);
Linus Torvalds's avatar
Linus Torvalds committed
479 480
}

481 482
static void __exit cmd64x_ide_exit(void)
{
483
	pci_unregister_driver(&cmd64x_pci_driver);
484 485
}

Linus Torvalds's avatar
Linus Torvalds committed
486
module_init(cmd64x_ide_init);
487
module_exit(cmd64x_ide_exit);
Linus Torvalds's avatar
Linus Torvalds committed
488 489 490 491

MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick");
MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
MODULE_LICENSE("GPL");