| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * linux/drivers/ide/pci/hpt34x.c		Version 0.40	Sept 10, 2002 | 
 | 3 |  * | 
 | 4 |  * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org> | 
 | 5 |  * May be copied or modified under the terms of the GNU General Public License | 
 | 6 |  * | 
 | 7 |  * | 
 | 8 |  * 00:12.0 Unknown mass storage controller: | 
 | 9 |  * Triones Technologies, Inc. | 
 | 10 |  * Unknown device 0003 (rev 01) | 
 | 11 |  * | 
 | 12 |  * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010) | 
 | 13 |  * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030) | 
 | 14 |  * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010) | 
 | 15 |  * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030) | 
 | 16 |  * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070) | 
 | 17 |  * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0) | 
 | 18 |  * | 
 | 19 |  * ide-pci.c reference | 
 | 20 |  * | 
 | 21 |  * Since there are two cards that report almost identically, | 
 | 22 |  * the only discernable difference is the values reported in pcicmd. | 
 | 23 |  * Booting-BIOS card or HPT363 :: pcicmd == 0x07 | 
 | 24 |  * Non-bootable card or HPT343 :: pcicmd == 0x05 | 
 | 25 |  */ | 
 | 26 |  | 
 | 27 | #include <linux/config.h> | 
 | 28 | #include <linux/module.h> | 
 | 29 | #include <linux/types.h> | 
 | 30 | #include <linux/kernel.h> | 
 | 31 | #include <linux/delay.h> | 
 | 32 | #include <linux/timer.h> | 
 | 33 | #include <linux/mm.h> | 
 | 34 | #include <linux/ioport.h> | 
 | 35 | #include <linux/blkdev.h> | 
 | 36 | #include <linux/hdreg.h> | 
 | 37 | #include <linux/interrupt.h> | 
 | 38 | #include <linux/pci.h> | 
 | 39 | #include <linux/init.h> | 
 | 40 | #include <linux/ide.h> | 
 | 41 |  | 
 | 42 | #include <asm/io.h> | 
 | 43 | #include <asm/irq.h> | 
 | 44 |  | 
 | 45 | #define HPT343_DEBUG_DRIVE_INFO		0 | 
 | 46 |  | 
 | 47 | static u8 hpt34x_ratemask (ide_drive_t *drive) | 
 | 48 | { | 
 | 49 | 	return 1; | 
 | 50 | } | 
 | 51 |  | 
 | 52 | static void hpt34x_clear_chipset (ide_drive_t *drive) | 
 | 53 | { | 
 | 54 | 	struct pci_dev *dev	= HWIF(drive)->pci_dev; | 
 | 55 | 	u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0; | 
 | 56 |  | 
 | 57 | 	pci_read_config_dword(dev, 0x44, ®1); | 
 | 58 | 	pci_read_config_dword(dev, 0x48, ®2); | 
 | 59 | 	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); | 
 | 60 | 	tmp2 = (reg2 & ~(0x11 << drive->dn)); | 
 | 61 | 	pci_write_config_dword(dev, 0x44, tmp1); | 
 | 62 | 	pci_write_config_dword(dev, 0x48, tmp2); | 
 | 63 | } | 
 | 64 |  | 
 | 65 | static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) | 
 | 66 | { | 
 | 67 | 	struct pci_dev *dev	= HWIF(drive)->pci_dev; | 
 | 68 | 	u8 speed	= ide_rate_filter(hpt34x_ratemask(drive), xferspeed); | 
 | 69 | 	u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0; | 
 | 70 | 	u8			hi_speed, lo_speed; | 
 | 71 |  | 
 | 72 | 	hi_speed = speed >> 4; | 
 | 73 | 	lo_speed = speed & 0x0f; | 
 | 74 |  | 
 | 75 | 	if (hi_speed & 7) { | 
 | 76 | 		hi_speed = (hi_speed & 4) ? 0x01 : 0x10; | 
 | 77 | 	} else { | 
 | 78 | 		lo_speed <<= 5; | 
 | 79 | 		lo_speed >>= 5; | 
 | 80 | 	} | 
 | 81 |  | 
 | 82 | 	pci_read_config_dword(dev, 0x44, ®1); | 
 | 83 | 	pci_read_config_dword(dev, 0x48, ®2); | 
 | 84 | 	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); | 
 | 85 | 	tmp2 = ((hi_speed << drive->dn) | reg2); | 
 | 86 | 	pci_write_config_dword(dev, 0x44, tmp1); | 
 | 87 | 	pci_write_config_dword(dev, 0x48, tmp2); | 
 | 88 |  | 
 | 89 | #if HPT343_DEBUG_DRIVE_INFO | 
 | 90 | 	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \ | 
 | 91 | 		" (0x%02x 0x%02x)\n", | 
 | 92 | 		drive->name, ide_xfer_verbose(speed), | 
 | 93 | 		drive->dn, reg1, tmp1, reg2, tmp2, | 
 | 94 | 		hi_speed, lo_speed); | 
 | 95 | #endif /* HPT343_DEBUG_DRIVE_INFO */ | 
 | 96 |  | 
 | 97 | 	return(ide_config_drive_speed(drive, speed)); | 
 | 98 | } | 
 | 99 |  | 
 | 100 | static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio) | 
 | 101 | { | 
 | 102 | 	pio = ide_get_best_pio_mode(drive, pio, 5, NULL); | 
 | 103 | 	hpt34x_clear_chipset(drive); | 
 | 104 | 	(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio)); | 
 | 105 | } | 
 | 106 |  | 
 | 107 | /* | 
 | 108 |  * This allows the configuration of ide_pci chipset registers | 
 | 109 |  * for cards that learn about the drive's UDMA, DMA, PIO capabilities | 
 | 110 |  * after the drive is reported by the OS.  Initially for designed for | 
 | 111 |  * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc. | 
 | 112 |  */ | 
 | 113 |  | 
 | 114 | static int config_chipset_for_dma (ide_drive_t *drive) | 
 | 115 | { | 
 | 116 | 	u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive)); | 
 | 117 |  | 
 | 118 | 	if (!(speed)) | 
 | 119 | 		return 0; | 
 | 120 |  | 
 | 121 | 	hpt34x_clear_chipset(drive); | 
 | 122 | 	(void) hpt34x_tune_chipset(drive, speed); | 
 | 123 | 	return ide_dma_enable(drive); | 
 | 124 | } | 
 | 125 |  | 
 | 126 | static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive) | 
 | 127 | { | 
 | 128 | 	ide_hwif_t *hwif	= HWIF(drive); | 
 | 129 | 	struct hd_driveid *id	= drive->id; | 
 | 130 |  | 
 | 131 | 	drive->init_speed = 0; | 
 | 132 |  | 
 | 133 | 	if (id && (id->capability & 1) && drive->autodma) { | 
 | 134 |  | 
 | 135 | 		if (ide_use_dma(drive)) { | 
 | 136 | 			if (config_chipset_for_dma(drive)) | 
 | 137 | #ifndef CONFIG_HPT34X_AUTODMA | 
 | 138 | 				return hwif->ide_dma_off_quietly(drive); | 
 | 139 | #else | 
 | 140 | 				return hwif->ide_dma_on(drive); | 
 | 141 | #endif | 
 | 142 | 		} | 
 | 143 |  | 
 | 144 | 		goto fast_ata_pio; | 
 | 145 |  | 
 | 146 | 	} else if ((id->capability & 8) || (id->field_valid & 2)) { | 
 | 147 | fast_ata_pio: | 
 | 148 | 		hpt34x_tune_drive(drive, 255); | 
 | 149 | 		return hwif->ide_dma_off_quietly(drive); | 
 | 150 | 	} | 
 | 151 | 	/* IORDY not supported */ | 
 | 152 | 	return 0; | 
 | 153 | } | 
 | 154 |  | 
 | 155 | /* | 
 | 156 |  * If the BIOS does not set the IO base addaress to XX00, 343 will fail. | 
 | 157 |  */ | 
 | 158 | #define	HPT34X_PCI_INIT_REG		0x80 | 
 | 159 |  | 
 | 160 | static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const char *name) | 
 | 161 | { | 
 | 162 | 	int i = 0; | 
 | 163 | 	unsigned long hpt34xIoBase = pci_resource_start(dev, 4); | 
 | 164 | 	unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c }; | 
 | 165 | 	unsigned long hpt_addr_len[4] = { 7, 3, 7, 3 }; | 
 | 166 | 	u16 cmd; | 
 | 167 | 	unsigned long flags; | 
 | 168 |  | 
 | 169 | 	local_irq_save(flags); | 
 | 170 |  | 
 | 171 | 	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00); | 
 | 172 | 	pci_read_config_word(dev, PCI_COMMAND, &cmd); | 
 | 173 |  | 
 | 174 | 	if (cmd & PCI_COMMAND_MEMORY) { | 
 | 175 | 		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) { | 
 | 176 | 			pci_write_config_byte(dev, PCI_ROM_ADDRESS, | 
 | 177 | 				dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); | 
 | 178 | 			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", | 
 | 179 | 				dev->resource[PCI_ROM_RESOURCE].start); | 
 | 180 | 		} | 
 | 181 | 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); | 
 | 182 | 	} else { | 
 | 183 | 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); | 
 | 184 | 	} | 
 | 185 |  | 
 | 186 | 	/* | 
 | 187 | 	 * Since 20-23 can be assigned and are R/W, we correct them. | 
 | 188 | 	 */ | 
 | 189 | 	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); | 
 | 190 | 	for(i=0; i<4; i++) { | 
 | 191 | 		dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]); | 
 | 192 | 		dev->resource[i].end = dev->resource[i].start + hpt_addr_len[i]; | 
 | 193 | 		dev->resource[i].flags = IORESOURCE_IO; | 
 | 194 | 		pci_write_config_dword(dev, | 
 | 195 | 				(PCI_BASE_ADDRESS_0 + (i * 4)), | 
 | 196 | 				dev->resource[i].start); | 
 | 197 | 	} | 
 | 198 | 	pci_write_config_word(dev, PCI_COMMAND, cmd); | 
 | 199 |  | 
 | 200 | 	local_irq_restore(flags); | 
 | 201 |  | 
 | 202 | 	return dev->irq; | 
 | 203 | } | 
 | 204 |  | 
 | 205 | static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) | 
 | 206 | { | 
 | 207 | 	u16 pcicmd = 0; | 
 | 208 |  | 
 | 209 | 	hwif->autodma = 0; | 
 | 210 |  | 
 | 211 | 	hwif->tuneproc = &hpt34x_tune_drive; | 
 | 212 | 	hwif->speedproc = &hpt34x_tune_chipset; | 
 | 213 | 	hwif->no_dsc = 1; | 
 | 214 | 	hwif->drives[0].autotune = 1; | 
 | 215 | 	hwif->drives[1].autotune = 1; | 
 | 216 |  | 
 | 217 | 	pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); | 
 | 218 |  | 
 | 219 | 	if (!hwif->dma_base) | 
 | 220 | 		return; | 
 | 221 |  | 
 | 222 | 	hwif->ultra_mask = 0x07; | 
 | 223 | 	hwif->mwdma_mask = 0x07; | 
 | 224 | 	hwif->swdma_mask = 0x07; | 
 | 225 |  | 
 | 226 | 	hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate; | 
 | 227 | 	if (!noautodma) | 
 | 228 | 		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; | 
 | 229 | 	hwif->drives[0].autodma = hwif->autodma; | 
 | 230 | 	hwif->drives[1].autodma = hwif->autodma; | 
 | 231 | } | 
 | 232 |  | 
 | 233 | static ide_pci_device_t hpt34x_chipset __devinitdata = { | 
 | 234 | 	.name		= "HPT34X", | 
 | 235 | 	.init_chipset	= init_chipset_hpt34x, | 
 | 236 | 	.init_hwif	= init_hwif_hpt34x, | 
 | 237 | 	.channels	= 2, | 
 | 238 | 	.autodma	= NOAUTODMA, | 
 | 239 | 	.bootable	= NEVER_BOARD, | 
 | 240 | 	.extra		= 16 | 
 | 241 | }; | 
 | 242 |  | 
 | 243 | static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id) | 
 | 244 | { | 
 | 245 | 	ide_pci_device_t *d = &hpt34x_chipset; | 
 | 246 | 	static char *chipset_names[] = {"HPT343", "HPT345"}; | 
 | 247 | 	u16 pcicmd = 0; | 
 | 248 |  | 
 | 249 | 	pci_read_config_word(dev, PCI_COMMAND, &pcicmd); | 
 | 250 |  | 
 | 251 | 	d->name = chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]; | 
 | 252 | 	d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; | 
 | 253 |  | 
 | 254 | 	return ide_setup_pci_device(dev, d); | 
 | 255 | } | 
 | 256 |  | 
 | 257 | static struct pci_device_id hpt34x_pci_tbl[] = { | 
 | 258 | 	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 
 | 259 | 	{ 0, }, | 
 | 260 | }; | 
 | 261 | MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl); | 
 | 262 |  | 
 | 263 | static struct pci_driver driver = { | 
 | 264 | 	.name		= "HPT34x_IDE", | 
 | 265 | 	.id_table	= hpt34x_pci_tbl, | 
 | 266 | 	.probe		= hpt34x_init_one, | 
 | 267 | }; | 
 | 268 |  | 
 | 269 | static int hpt34x_ide_init(void) | 
 | 270 | { | 
 | 271 | 	return ide_pci_register_driver(&driver); | 
 | 272 | } | 
 | 273 |  | 
 | 274 | module_init(hpt34x_ide_init); | 
 | 275 |  | 
 | 276 | MODULE_AUTHOR("Andre Hedrick"); | 
 | 277 | MODULE_DESCRIPTION("PCI driver module for Highpoint 34x IDE"); | 
 | 278 | MODULE_LICENSE("GPL"); |