via82cxxx.c 16.5 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
Linus Torvalds's avatar
Linus Torvalds committed
2
 * $Id: via82cxxx.c,v 3.26 2001/08/17 12:03:00 vojtech Exp $
Linus Torvalds's avatar
Linus Torvalds committed
3
 *
Linus Torvalds's avatar
Linus Torvalds committed
4
 *  Copyright (c) 2000-2001 Vojtech Pavlik
Linus Torvalds's avatar
Linus Torvalds committed
5 6 7 8 9 10 11 12 13 14
 *
 *  Based on the work of:
 *	Michel Aubry
 *	Jeff Garzik
 *	Andre Hedrick
 *
 *  Sponsored by SuSE
 */

/*
Linus Torvalds's avatar
Linus Torvalds committed
15
 * VIA IDE driver for Linux. Supports
Linus Torvalds's avatar
Linus Torvalds committed
16
 *
Linus Torvalds's avatar
Linus Torvalds committed
17 18
 *   vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
 *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233
Linus Torvalds's avatar
Linus Torvalds committed
19 20 21
 *
 * southbridges, which can be found in
 *
Linus Torvalds's avatar
Linus Torvalds committed
22 23 24 25 26 27 28
 *  VIA Apollo VP, VPX, VPX/97, VP2, VP2/97, VP3, MVP3, MVP4, P6, Pro,
 *  Pro Plus, Pro 133, Pro 133A, ProMedia PM601, ProSavage PM133, PLE133,
 *  Pro 266, KX133, KT133, ProSavage KM133, KT133A, KT266
 *  PC-Chips VXPro, VXPro+, TXPro-III, TXPro-AGP, ViaGra, BXToo, BXTel
 *  AMD 640, 640 AGP, 750 IronGate
 *  ETEQ 6618, 6628, 6638
 *  Micron Samurai
Linus Torvalds's avatar
Linus Torvalds committed
29
 *
Linus Torvalds's avatar
Linus Torvalds committed
30
 * chipsets. Supports
Linus Torvalds's avatar
Linus Torvalds committed
31
 *
Linus Torvalds's avatar
Linus Torvalds committed
32 33 34
 *   PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-5
 *
 * (this includes UDMA33, 66 and 100) modes. UDMA66 and higher modes are
Linus Torvalds's avatar
Linus Torvalds committed
35 36 37
 * autoenabled only in case the BIOS has detected a 80 wire cable. To ignore
 * the BIOS data and assume the cable is present, use 'ide0=ata66' or
 * 'ide1=ata66' on the kernel command line.
Linus Torvalds's avatar
Linus Torvalds committed
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
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <asm/io.h>

Linus Torvalds's avatar
Linus Torvalds committed
69
#include "ide-timing.h"
Linus Torvalds's avatar
Linus Torvalds committed
70 71 72 73 74 75 76 77

#define VIA_IDE_ENABLE		0x40
#define VIA_IDE_CONFIG		0x41
#define VIA_FIFO_CONFIG		0x43
#define VIA_MISC_1		0x44
#define VIA_MISC_2		0x45
#define VIA_MISC_3		0x46
#define VIA_DRIVE_TIMING	0x48
Linus Torvalds's avatar
Linus Torvalds committed
78
#define VIA_8BIT_TIMING		0x4e
Linus Torvalds's avatar
Linus Torvalds committed
79 80
#define VIA_ADDRESS_SETUP	0x4c
#define VIA_UDMA_TIMING		0x50
Linus Torvalds's avatar
Linus Torvalds committed
81

Linus Torvalds's avatar
Linus Torvalds committed
82 83 84 85 86 87 88 89 90
#define VIA_UDMA		0x007
#define VIA_UDMA_NONE		0x000
#define VIA_UDMA_33		0x001
#define VIA_UDMA_66		0x002
#define VIA_UDMA_100		0x003
#define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
#define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
#define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
#define VIA_SET_THRESH		0x080	/* Needs to have FIFO thresholds set */
Linus Torvalds's avatar
Linus Torvalds committed
91 92 93 94 95

/*
 * VIA SouthBridge chips.
 */

Linus Torvalds's avatar
Linus Torvalds committed
96
static struct via_isa_bridge {
Linus Torvalds's avatar
Linus Torvalds committed
97 98
	char *name;
	unsigned short id;
Linus Torvalds's avatar
Linus Torvalds committed
99 100
	unsigned char rev_min;
	unsigned char rev_max;
Linus Torvalds's avatar
Linus Torvalds committed
101
	unsigned short flags;
Linus Torvalds's avatar
Linus Torvalds committed
102
} via_isa_bridges[] = {
Linus Torvalds's avatar
Linus Torvalds committed
103
	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
Linus Torvalds's avatar
Linus Torvalds committed
104 105
	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
Linus Torvalds's avatar
Linus Torvalds committed
106
	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
Linus Torvalds's avatar
Linus Torvalds committed
107
	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
Linus Torvalds's avatar
Linus Torvalds committed
108 109 110 111 112 113 114
	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
	{ "vt82c596a",	PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
	{ NULL }
Linus Torvalds's avatar
Linus Torvalds committed
115 116
};

Linus Torvalds's avatar
Linus Torvalds committed
117
static struct via_isa_bridge *via_config;
Linus Torvalds's avatar
Linus Torvalds committed
118
static unsigned char via_enabled;
Linus Torvalds's avatar
Linus Torvalds committed
119 120
static unsigned int via_80w;
static unsigned int via_clock;
Linus Torvalds's avatar
Linus Torvalds committed
121
static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" };
Linus Torvalds's avatar
Linus Torvalds committed
122 123 124 125 126 127 128 129 130 131

/*
 * VIA /proc entry.
 */

#ifdef CONFIG_PROC_FS

#include <linux/stat.h>
#include <linux/proc_fs.h>

Linus Torvalds's avatar
Linus Torvalds committed
132
int via_proc, via_base;
Linus Torvalds's avatar
Linus Torvalds committed
133 134 135 136 137 138 139 140 141 142 143
static struct pci_dev *bmide_dev, *isa_dev;
extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */

static char *via_control3[] = { "No limit", "64", "128", "192" };

#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
#define via_print_drive(name, format, arg...)\
	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");

static int via_get_info(char *buffer, char **addr, off_t offset, int count)
{
Linus Torvalds's avatar
Linus Torvalds committed
144 145
	short speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
Linus Torvalds's avatar
Linus Torvalds committed
146
	struct pci_dev *dev = bmide_dev;
Linus Torvalds's avatar
Linus Torvalds committed
147 148 149
	unsigned int v, u, i;
	unsigned short c, w;
	unsigned char t, x;
Linus Torvalds's avatar
Linus Torvalds committed
150 151 152 153
	char *p = buffer;

	via_print("----------VIA BusMastering IDE Configuration----------------");

Linus Torvalds's avatar
Linus Torvalds committed
154
	via_print("Driver Version:                     3.26");
Linus Torvalds's avatar
Linus Torvalds committed
155
	via_print("South Bridge:                       VIA %s", via_config->name);
Linus Torvalds's avatar
Linus Torvalds committed
156 157

	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
Linus Torvalds's avatar
Linus Torvalds committed
158 159
	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
	via_print("Revision:                           ISA %#x IDE %#x", t, x);
Linus Torvalds's avatar
Linus Torvalds committed
160
	via_print("Highest DMA rate:                   %s", via_dma[via_config->flags & VIA_UDMA]);
Linus Torvalds's avatar
Linus Torvalds committed
161

Linus Torvalds's avatar
Linus Torvalds committed
162 163
	via_print("BM-DMA base:                        %#x", via_base);
	via_print("PCI clock:                          %dMHz", via_clock);
Linus Torvalds's avatar
Linus Torvalds committed
164 165

	pci_read_config_byte(dev, VIA_MISC_1, &t);
Linus Torvalds's avatar
Linus Torvalds committed
166 167 168
	via_print("Master Read  Cycle IRDY:            %dws", (t & 64) >> 6);
	via_print("Master Write Cycle IRDY:            %dws", (t & 32) >> 5);
	via_print("BM IDE Status Register Read Retry:  %s", (t & 8) ? "yes" : "no");
Linus Torvalds's avatar
Linus Torvalds committed
169 170

	pci_read_config_byte(dev, VIA_MISC_3, &t);
Linus Torvalds's avatar
Linus Torvalds committed
171
	via_print("Max DRDY Pulse Width:               %s%s", via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
Linus Torvalds's avatar
Linus Torvalds committed
172 173

	via_print("-----------------------Primary IDE-------Secondary IDE------");
Linus Torvalds's avatar
Linus Torvalds committed
174 175
	via_print("Read DMA FIFO flush:   %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
	via_print("End Sector FIFO flush: %10s%20s", (t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
Linus Torvalds's avatar
Linus Torvalds committed
176 177

	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
Linus Torvalds's avatar
Linus Torvalds committed
178 179
	via_print("Prefetch Buffer:       %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
	via_print("Post Write Buffer:     %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
Linus Torvalds's avatar
Linus Torvalds committed
180

Linus Torvalds's avatar
Linus Torvalds committed
181 182
	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
	via_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
Linus Torvalds's avatar
Linus Torvalds committed
183

Linus Torvalds's avatar
Linus Torvalds committed
184 185
	c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
	via_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
Linus Torvalds's avatar
Linus Torvalds committed
186

Linus Torvalds's avatar
Linus Torvalds committed
187
	via_print("Cable Type:            %10s%20s", (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
Linus Torvalds's avatar
Linus Torvalds committed
188 189 190 191 192

	via_print("-------------------drive0----drive1----drive2----drive3-----");

	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
Linus Torvalds's avatar
Linus Torvalds committed
193 194 195 196 197
	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);

	if (via_config->flags & VIA_UDMA)
		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
	else u = 0;
Linus Torvalds's avatar
Linus Torvalds committed
198 199

	for (i = 0; i < 4; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
200

Linus Torvalds's avatar
Linus Torvalds committed
201 202 203 204 205 206
		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
Linus Torvalds's avatar
Linus Torvalds committed
207 208 209 210 211 212
		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));

		speed[i] = 20 * via_clock / (active[i] + recover[i]);
		cycle[i] = 1000 / via_clock * (active[i] + recover[i]);
Linus Torvalds's avatar
Linus Torvalds committed
213

Linus Torvalds's avatar
Linus Torvalds committed
214
		if (!uen[i] || !den[i])
Linus Torvalds's avatar
Linus Torvalds committed
215 216
			continue;

Linus Torvalds's avatar
Linus Torvalds committed
217 218 219
		switch (via_config->flags & VIA_UDMA) {
			
			case VIA_UDMA_100:
Linus Torvalds's avatar
Linus Torvalds committed
220 221
				speed[i] = 60 * via_clock / udma[i];
				cycle[i] = 333 / via_clock * udma[i];
Linus Torvalds's avatar
Linus Torvalds committed
222 223 224 225 226 227
				break;

			case VIA_UDMA_66:
				speed[i] = 40 * via_clock / (udma[i] * umul[i]);
				cycle[i] = 500 / via_clock * (udma[i] * umul[i]);
				break;
Linus Torvalds's avatar
Linus Torvalds committed
228

Linus Torvalds's avatar
Linus Torvalds committed
229 230 231 232 233
			case VIA_UDMA_33:
				speed[i] = 20 * via_clock / udma[i];
				cycle[i] = 1000 / via_clock * udma[i];
				break;
		}
Linus Torvalds's avatar
Linus Torvalds committed
234 235
	}

Linus Torvalds's avatar
Linus Torvalds committed
236
	via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
Linus Torvalds's avatar
Linus Torvalds committed
237 238 239 240 241 242

	via_print_drive("Address Setup: ", "%8dns", (1000 / via_clock) * setup[i]);
	via_print_drive("Cmd Active:    ", "%8dns", (1000 / via_clock) * active8b[i]);
	via_print_drive("Cmd Recovery:  ", "%8dns", (1000 / via_clock) * recover8b[i]);
	via_print_drive("Data Active:   ", "%8dns", (1000 / via_clock) * active[i]);
	via_print_drive("Data Recovery: ", "%8dns", (1000 / via_clock) * recover[i]);
Linus Torvalds's avatar
Linus Torvalds committed
243 244 245 246 247 248 249 250
	via_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 10, speed[i] % 10);

	return p - buffer;	/* hoping it is less than 4K... */
}

#endif

Linus Torvalds's avatar
Linus Torvalds committed
251 252 253
/*
 * via_set_speed() writes timing values to the chipset registers
 */
Linus Torvalds's avatar
Linus Torvalds committed
254

Linus Torvalds's avatar
Linus Torvalds committed
255
static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
Linus Torvalds's avatar
Linus Torvalds committed
256
{
Linus Torvalds's avatar
Linus Torvalds committed
257
	unsigned char t;
Linus Torvalds's avatar
Linus Torvalds committed
258

Linus Torvalds's avatar
Linus Torvalds committed
259 260 261
	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
	pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
Linus Torvalds's avatar
Linus Torvalds committed
262

Linus Torvalds's avatar
Linus Torvalds committed
263 264
	pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
Linus Torvalds's avatar
Linus Torvalds committed
265

Linus Torvalds's avatar
Linus Torvalds committed
266 267
	pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
Linus Torvalds's avatar
Linus Torvalds committed
268

Linus Torvalds's avatar
Linus Torvalds committed
269 270 271 272 273
	switch (via_config->flags & VIA_UDMA) {
		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
		default: return;
Linus Torvalds's avatar
Linus Torvalds committed
274 275
	}

Linus Torvalds's avatar
Linus Torvalds committed
276 277
	pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
}
Linus Torvalds's avatar
Linus Torvalds committed
278 279

/*
Linus Torvalds's avatar
Linus Torvalds committed
280 281 282
 * via_set_drive() computes timing values configures the drive and
 * the chipset to a desired transfer mode. It also can be called
 * by upper layers.
Linus Torvalds's avatar
Linus Torvalds committed
283 284
 */

Linus Torvalds's avatar
Linus Torvalds committed
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
static int via_set_drive(ide_drive_t *drive, unsigned char speed)
{
	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
	struct ide_timing t, p;
	int T, UT;

	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
		if (ide_config_drive_speed(drive, speed))
			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
				drive->dn >> 1, drive->dn & 1);

	T = 1000 / via_clock;

	switch (via_config->flags & VIA_UDMA) {
		case VIA_UDMA_33:   UT = T;   break;
		case VIA_UDMA_66:   UT = T/2; break;
Linus Torvalds's avatar
Linus Torvalds committed
301
		case VIA_UDMA_100:  UT = T/3; break;
Linus Torvalds's avatar
Linus Torvalds committed
302 303
		default:	    UT = T;   break;
	}
Linus Torvalds's avatar
Linus Torvalds committed
304

Linus Torvalds's avatar
Linus Torvalds committed
305
	ide_timing_compute(drive, speed, &t, T, UT);
Linus Torvalds's avatar
Linus Torvalds committed
306

Linus Torvalds's avatar
Linus Torvalds committed
307 308 309 310
	if (peer->present) {
		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
	}
Linus Torvalds's avatar
Linus Torvalds committed
311

Linus Torvalds's avatar
Linus Torvalds committed
312
	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
Linus Torvalds's avatar
Linus Torvalds committed
313

Linus Torvalds's avatar
Linus Torvalds committed
314 315
	if (!drive->init_speed)
		drive->init_speed = speed;
Linus Torvalds's avatar
Linus Torvalds committed
316 317 318 319 320
	drive->current_speed = speed;

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
321 322 323 324
/*
 * via82cxxx_tune_drive() is a callback from upper layers for
 * PIO-only tuning.
 */
Linus Torvalds's avatar
Linus Torvalds committed
325

Linus Torvalds's avatar
Linus Torvalds committed
326
static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio)
Linus Torvalds's avatar
Linus Torvalds committed
327
{
Linus Torvalds's avatar
Linus Torvalds committed
328 329 330
	if (!((via_enabled >> HWIF(drive)->channel) & 1))
		return;

Linus Torvalds's avatar
Linus Torvalds committed
331
	if (pio == 255) {
Linus Torvalds's avatar
Linus Torvalds committed
332
		via_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
Linus Torvalds's avatar
Linus Torvalds committed
333 334
		return;
	}
Linus Torvalds's avatar
Linus Torvalds committed
335 336

	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
Linus Torvalds's avatar
Linus Torvalds committed
337 338 339 340 341
}

#ifdef CONFIG_BLK_DEV_IDEDMA

/*
Linus Torvalds's avatar
Linus Torvalds committed
342 343 344
 * via82cxxx_dmaproc() is a callback from upper layers that can do
 * a lot, but we use it for DMA/PIO tuning only, delegating everything
 * else to the default ide_dmaproc().
Linus Torvalds's avatar
Linus Torvalds committed
345 346
 */

Linus Torvalds's avatar
Linus Torvalds committed
347
int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
348 349
{

Linus Torvalds's avatar
Linus Torvalds committed
350 351 352 353 354 355 356
	if (func == ide_dma_check) {

		short w80 = HWIF(drive)->udma_four;

		short speed = ide_find_best_mode(drive,
			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
			(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
Linus Torvalds's avatar
Linus Torvalds committed
357 358
			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0));
Linus Torvalds's avatar
Linus Torvalds committed
359 360

		via_set_drive(drive, speed);
Linus Torvalds's avatar
Linus Torvalds committed
361 362 363

		func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
			? ide_dma_on : ide_dma_off_quietly;
Linus Torvalds's avatar
Linus Torvalds committed
364
	}
Linus Torvalds's avatar
Linus Torvalds committed
365 366 367

	return ide_dmaproc(func, drive);
}
Linus Torvalds's avatar
Linus Torvalds committed
368

Linus Torvalds's avatar
Linus Torvalds committed
369 370
#endif /* CONFIG_BLK_DEV_IDEDMA */

Linus Torvalds's avatar
Linus Torvalds committed
371 372 373 374 375
/*
 * The initialization callback. Here we determine the IDE chip type
 * and initialize its drive independent registers.
 */

Linus Torvalds's avatar
Linus Torvalds committed
376 377 378
unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name)
{
	struct pci_dev *isa = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
379 380 381
	unsigned char t, v;
	unsigned int u;
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
382 383

/*
Linus Torvalds's avatar
Linus Torvalds committed
384
 * Find the ISA bridge to see how good the IDE is.
Linus Torvalds's avatar
Linus Torvalds committed
385 386
 */

Linus Torvalds's avatar
Linus Torvalds committed
387 388 389 390 391 392
	for (via_config = via_isa_bridges; via_config->id; via_config++)
		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_config->id, NULL))) {
			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
			if (t >= via_config->rev_min && t <= via_config->rev_max)
				break;
		}
Linus Torvalds's avatar
Linus Torvalds committed
393

Linus Torvalds's avatar
Linus Torvalds committed
394 395 396
	if (!via_config->id) {
		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@suse.cz>\n");
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
397 398 399
	}

/*
Linus Torvalds's avatar
Linus Torvalds committed
400
 * Check 80-wire cable presence and setup Clk66.
Linus Torvalds's avatar
Linus Torvalds committed
401 402
 */

Linus Torvalds's avatar
Linus Torvalds committed
403
	switch (via_config->flags & VIA_UDMA) {
Linus Torvalds's avatar
Linus Torvalds committed
404

Linus Torvalds's avatar
Linus Torvalds committed
405
		case VIA_UDMA_100:
Linus Torvalds's avatar
Linus Torvalds committed
406

Linus Torvalds's avatar
Linus Torvalds committed
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
			for (i = 24; i >= 0; i -= 8)
				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 3)))
					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 50ns/cycle */
			break;

		case VIA_UDMA_66:

			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Enable Clk66 */
			pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008);
			for (i = 24; i >= 0; i -= 8)
				if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2))
					via_80w |= (1 << (1 - (i >> 4)));	/* 2x PCI clock and UDMA w/ < 3T/cycle */
			break;
	}

	if (via_config->flags & VIA_BAD_CLK66) {			/* Disable Clk66 */
		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Would cause trouble on 596a */
		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
	}
Linus Torvalds's avatar
Linus Torvalds committed
427 428

/*
Linus Torvalds's avatar
Linus Torvalds committed
429
 * Check whether interfaces are enabled.
Linus Torvalds's avatar
Linus Torvalds committed
430
 */
Linus Torvalds's avatar
Linus Torvalds committed
431 432 433

	pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
	via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
Linus Torvalds's avatar
Linus Torvalds committed
434 435

/*
Linus Torvalds's avatar
Linus Torvalds committed
436
 * Set up FIFO sizes and thresholds.
Linus Torvalds's avatar
Linus Torvalds committed
437 438
 */

Linus Torvalds's avatar
Linus Torvalds committed
439
	pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
Linus Torvalds's avatar
Linus Torvalds committed
440

Linus Torvalds's avatar
Linus Torvalds committed
441 442
	if (via_config->flags & VIA_BAD_PREQ)				/* Disable PREQ# till DDACK# */
		t &= 0x7f;						/* Would crash on 586b rev 41 */
Linus Torvalds's avatar
Linus Torvalds committed
443

Linus Torvalds's avatar
Linus Torvalds committed
444 445 446 447 448 449 450
	if (via_config->flags & VIA_SET_FIFO) {				/* Fix FIFO split between channels */
		t &= (t & 0x9f);
		switch (via_enabled) {
			case 1: t |= 0x00; break;			/* 16 on primary */
			case 2: t |= 0x60; break;			/* 16 on secondary */
			case 3: t |= 0x20; break;			/* 8 pri 8 sec */
		}
Linus Torvalds's avatar
Linus Torvalds committed
451 452
	}

Linus Torvalds's avatar
Linus Torvalds committed
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
	if (via_config->flags & VIA_SET_THRESH)				/* 1/2 FIFO full to trigger xmit */
		t = (t & 0xf0) | 0x0a;

	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);

/*
 * Determine system bus clock.
 */

	via_clock = system_bus_clock();
	if (via_clock < 20 || via_clock > 50) {
		printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock);
		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to force UDMA66/UDMA100.\n");
		via_clock = 33;
	}
Linus Torvalds's avatar
Linus Torvalds committed
468 469 470 471 472

/*
 * Print the boot message.
 */

Linus Torvalds's avatar
Linus Torvalds committed
473 474
	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s controller on pci%s\n",
Linus Torvalds's avatar
Linus Torvalds committed
475
		via_config->name, t, via_dma[via_config->flags & VIA_UDMA], dev->slot_name);
Linus Torvalds's avatar
Linus Torvalds committed
476

Linus Torvalds's avatar
Linus Torvalds committed
477
/*
Linus Torvalds's avatar
Linus Torvalds committed
478
 * Setup /proc/ide/via entry.
Linus Torvalds's avatar
Linus Torvalds committed
479 480
 */

Linus Torvalds's avatar
Linus Torvalds committed
481
#ifdef CONFIG_PROC_FS
Linus Torvalds's avatar
Linus Torvalds committed
482
	if (!via_proc) {
Linus Torvalds's avatar
Linus Torvalds committed
483
		via_base = pci_resource_start(dev, 4);
Linus Torvalds's avatar
Linus Torvalds committed
484 485 486
		bmide_dev = dev;
		isa_dev = isa;
		via_display_info = &via_get_info;
Linus Torvalds's avatar
Linus Torvalds committed
487
		via_proc = 1;
Linus Torvalds's avatar
Linus Torvalds committed
488 489 490 491 492 493 494 495
	}
#endif

	return 0;
}

unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif)
{
Linus Torvalds's avatar
Linus Torvalds committed
496
	return ((via_enabled & via_80w) >> hwif->channel) & 1;
Linus Torvalds's avatar
Linus Torvalds committed
497 498 499 500
}

void __init ide_init_via82cxxx(ide_hwif_t *hwif)
{
Linus Torvalds's avatar
Linus Torvalds committed
501 502
	int i;

Linus Torvalds's avatar
Linus Torvalds committed
503
	hwif->tuneproc = &via82cxxx_tune_drive;
Linus Torvalds's avatar
Linus Torvalds committed
504
	hwif->speedproc = &via_set_drive;
Linus Torvalds's avatar
Linus Torvalds committed
505 506
	hwif->autodma = 0;

Linus Torvalds's avatar
Linus Torvalds committed
507 508 509 510 511 512 513
	for (i = 0; i < 2; i++) {
		hwif->drives[i].io_32bit = 1;
		hwif->drives[i].unmask = 1;
		hwif->drives[i].autotune = 1;
		hwif->drives[i].dn = hwif->channel * 2 + i;
	}

Linus Torvalds's avatar
Linus Torvalds committed
514 515 516
#ifdef CONFIG_BLK_DEV_IDEDMA
	if (hwif->dma_base) {
		hwif->dmaproc = &via82cxxx_dmaproc;
Linus Torvalds's avatar
Linus Torvalds committed
517
#ifdef CONFIG_IDEDMA_AUTO
Linus Torvalds's avatar
Linus Torvalds committed
518 519
		if (!noautodma)
			hwif->autodma = 1;
Linus Torvalds's avatar
Linus Torvalds committed
520
#endif
Linus Torvalds's avatar
Linus Torvalds committed
521 522 523 524 525
	}
#endif /* CONFIG_BLK_DEV_IDEDMA */
}

/*
Linus Torvalds's avatar
Linus Torvalds committed
526
 * We allow the BM-DMA driver to only work on enabled interfaces.
Linus Torvalds's avatar
Linus Torvalds committed
527 528 529 530 531 532 533
 */

void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
{
	if ((via_enabled >> hwif->channel) & 1)
		ide_setup_dma(hwif, dmabase, 8);
}