18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * generic/default IDE host driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2008-2009 Bartlomiej Zolnierkiewicz
58c2ecf20Sopenharmony_ci * This code was split off from ide.c.  See it for original copyrights.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * May be copied or modified under the terms of the GNU General Public License.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/ide.h>
148c2ecf20Sopenharmony_ci#include <linux/pci_ids.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* FIXME: convert arm to use ide_platform host driver */
178c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM
188c2ecf20Sopenharmony_ci#include <asm/irq.h>
198c2ecf20Sopenharmony_ci#endif
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define DRV_NAME	"ide_generic"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic int probe_mask;
248c2ecf20Sopenharmony_cimodule_param(probe_mask, int, 0);
258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic const struct ide_port_info ide_generic_port_info = {
288c2ecf20Sopenharmony_ci	.host_flags		= IDE_HFLAG_NO_DMA,
298c2ecf20Sopenharmony_ci	.chipset		= ide_generic,
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM
338c2ecf20Sopenharmony_cistatic const u16 legacy_bases[] = { 0x1f0 };
348c2ecf20Sopenharmony_cistatic const int legacy_irqs[]  = { IRQ_HARDDISK };
358c2ecf20Sopenharmony_ci#elif defined(CONFIG_ALPHA)
368c2ecf20Sopenharmony_cistatic const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168 };
378c2ecf20Sopenharmony_cistatic const int legacy_irqs[]  = { 14, 15, 11, 10 };
388c2ecf20Sopenharmony_ci#else
398c2ecf20Sopenharmony_cistatic const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
408c2ecf20Sopenharmony_cistatic const int legacy_irqs[]  = { 14, 15, 11, 10, 8, 12 };
418c2ecf20Sopenharmony_ci#endif
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
468c2ecf20Sopenharmony_ci	struct pci_dev *p = NULL;
478c2ecf20Sopenharmony_ci	u16 val;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	for_each_pci_dev(p) {
508c2ecf20Sopenharmony_ci		if (pci_resource_start(p, 0) == 0x1f0)
518c2ecf20Sopenharmony_ci			*primary = 1;
528c2ecf20Sopenharmony_ci		if (pci_resource_start(p, 2) == 0x170)
538c2ecf20Sopenharmony_ci			*secondary = 1;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci		/* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */
568c2ecf20Sopenharmony_ci		if (p->vendor == PCI_VENDOR_ID_CYRIX &&
578c2ecf20Sopenharmony_ci		    (p->device == PCI_DEVICE_ID_CYRIX_5510 ||
588c2ecf20Sopenharmony_ci		     p->device == PCI_DEVICE_ID_CYRIX_5520))
598c2ecf20Sopenharmony_ci			*primary = *secondary = 1;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		/* Intel MPIIX - PIO ATA on non PCI side of bridge */
628c2ecf20Sopenharmony_ci		if (p->vendor == PCI_VENDOR_ID_INTEL &&
638c2ecf20Sopenharmony_ci		    p->device == PCI_DEVICE_ID_INTEL_82371MX) {
648c2ecf20Sopenharmony_ci			pci_read_config_word(p, 0x6C, &val);
658c2ecf20Sopenharmony_ci			if (val & 0x8000) {
668c2ecf20Sopenharmony_ci				/* ATA port enabled */
678c2ecf20Sopenharmony_ci				if (val & 0x4000)
688c2ecf20Sopenharmony_ci					*secondary = 1;
698c2ecf20Sopenharmony_ci				else
708c2ecf20Sopenharmony_ci					*primary = 1;
718c2ecf20Sopenharmony_ci			}
728c2ecf20Sopenharmony_ci		}
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci#endif
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic int __init ide_generic_init(void)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct ide_hw hw, *hws[] = { &hw };
808c2ecf20Sopenharmony_ci	unsigned long io_addr;
818c2ecf20Sopenharmony_ci	int i, rc = 0, primary = 0, secondary = 0;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	ide_generic_check_pci_legacy_iobases(&primary, &secondary);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (!probe_mask) {
868c2ecf20Sopenharmony_ci		printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" "
878c2ecf20Sopenharmony_ci		     "module parameter for probing all legacy ISA IDE ports\n");
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		if (primary == 0)
908c2ecf20Sopenharmony_ci			probe_mask |= 0x1;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci		if (secondary == 0)
938c2ecf20Sopenharmony_ci			probe_mask |= 0x2;
948c2ecf20Sopenharmony_ci	} else
958c2ecf20Sopenharmony_ci		printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports "
968c2ecf20Sopenharmony_ci			"upon user request\n");
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) {
998c2ecf20Sopenharmony_ci		io_addr = legacy_bases[i];
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci		if ((probe_mask & (1 << i)) && io_addr) {
1028c2ecf20Sopenharmony_ci			if (!request_region(io_addr, 8, DRV_NAME)) {
1038c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
1048c2ecf20Sopenharmony_ci						"not free.\n",
1058c2ecf20Sopenharmony_ci						DRV_NAME, io_addr, io_addr + 7);
1068c2ecf20Sopenharmony_ci				rc = -EBUSY;
1078c2ecf20Sopenharmony_ci				continue;
1088c2ecf20Sopenharmony_ci			}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci			if (!request_region(io_addr + 0x206, 1, DRV_NAME)) {
1118c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: I/O resource 0x%lX "
1128c2ecf20Sopenharmony_ci						"not free.\n",
1138c2ecf20Sopenharmony_ci						DRV_NAME, io_addr + 0x206);
1148c2ecf20Sopenharmony_ci				release_region(io_addr, 8);
1158c2ecf20Sopenharmony_ci				rc = -EBUSY;
1168c2ecf20Sopenharmony_ci				continue;
1178c2ecf20Sopenharmony_ci			}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci			memset(&hw, 0, sizeof(hw));
1208c2ecf20Sopenharmony_ci			ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
1218c2ecf20Sopenharmony_ci#ifdef CONFIG_IA64
1228c2ecf20Sopenharmony_ci			hw.irq = isa_irq_to_vector(legacy_irqs[i]);
1238c2ecf20Sopenharmony_ci#else
1248c2ecf20Sopenharmony_ci			hw.irq = legacy_irqs[i];
1258c2ecf20Sopenharmony_ci#endif
1268c2ecf20Sopenharmony_ci			rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL);
1278c2ecf20Sopenharmony_ci			if (rc) {
1288c2ecf20Sopenharmony_ci				release_region(io_addr + 0x206, 1);
1298c2ecf20Sopenharmony_ci				release_region(io_addr, 8);
1308c2ecf20Sopenharmony_ci			}
1318c2ecf20Sopenharmony_ci		}
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return rc;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cimodule_init(ide_generic_init);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
140