162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * pata-legacy.c - Legacy port PATA/SATA controller driver. 462306a36Sopenharmony_ci * Copyright 2005/2006 Red Hat, all rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * An ATA driver for the legacy ATA ports. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Data Sources: 962306a36Sopenharmony_ci * Opti 82C465/82C611 support: Data sheets at opti-inc.com 1062306a36Sopenharmony_ci * HT6560 series: 1162306a36Sopenharmony_ci * Promise 20230/20620: 1262306a36Sopenharmony_ci * http://www.ryston.cz/petr/vlb/pdc20230b.html 1362306a36Sopenharmony_ci * http://www.ryston.cz/petr/vlb/pdc20230c.html 1462306a36Sopenharmony_ci * http://www.ryston.cz/petr/vlb/pdc20630.html 1562306a36Sopenharmony_ci * QDI65x0: 1662306a36Sopenharmony_ci * http://www.ryston.cz/petr/vlb/qd6500.html 1762306a36Sopenharmony_ci * http://www.ryston.cz/petr/vlb/qd6580.html 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * QDI65x0 probe code based on drivers/ide/legacy/qd65xx.c 2062306a36Sopenharmony_ci * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by 2162306a36Sopenharmony_ci * Samuel Thibault <samuel.thibault@ens-lyon.org> 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Unsupported but docs exist: 2462306a36Sopenharmony_ci * Appian/Adaptec AIC25VL01/Cirrus Logic PD7220 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * This driver handles legacy (that is "ISA/VLB side") IDE ports found 2762306a36Sopenharmony_ci * on PC class systems. There are three hybrid devices that are exceptions 2862306a36Sopenharmony_ci * The Cyrix 5510/5520 where a pre SFF ATA device is on the bridge and 2962306a36Sopenharmony_ci * the MPIIX where the tuning is PCI side but the IDE is "ISA side". 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * Specific support is included for the ht6560a/ht6560b/opti82c611a/ 3262306a36Sopenharmony_ci * opti82c465mv/promise 20230c/20630/qdi65x0/winbond83759A 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * Support for the Winbond 83759A when operating in advanced mode. 3562306a36Sopenharmony_ci * Multichip mode is not currently supported. 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * Use the autospeed and pio_mask options with: 3862306a36Sopenharmony_ci * Appian ADI/2 aka CLPD7220 or AIC25VL01. 3962306a36Sopenharmony_ci * Use the jumpers, autospeed and set pio_mask to the mode on the jumpers with 4062306a36Sopenharmony_ci * Goldstar GM82C711, PIC-1288A-125, UMC 82C871F, Winbond W83759, 4162306a36Sopenharmony_ci * Winbond W83759A, Promise PDC20230-B 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * For now use autospeed and pio_mask as above with the W83759A. This may 4462306a36Sopenharmony_ci * change. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include <linux/async.h> 4862306a36Sopenharmony_ci#include <linux/kernel.h> 4962306a36Sopenharmony_ci#include <linux/module.h> 5062306a36Sopenharmony_ci#include <linux/pci.h> 5162306a36Sopenharmony_ci#include <linux/init.h> 5262306a36Sopenharmony_ci#include <linux/blkdev.h> 5362306a36Sopenharmony_ci#include <linux/delay.h> 5462306a36Sopenharmony_ci#include <scsi/scsi_host.h> 5562306a36Sopenharmony_ci#include <linux/ata.h> 5662306a36Sopenharmony_ci#include <linux/libata.h> 5762306a36Sopenharmony_ci#include <linux/platform_device.h> 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define DRV_NAME "pata_legacy" 6062306a36Sopenharmony_ci#define DRV_VERSION "0.6.5" 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define NR_HOST 6 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int all; 6562306a36Sopenharmony_cimodule_param(all, int, 0444); 6662306a36Sopenharmony_ciMODULE_PARM_DESC(all, 6762306a36Sopenharmony_ci "Set to probe unclaimed pri/sec ISA port ranges even if PCI"); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int probe_all; 7062306a36Sopenharmony_cimodule_param(probe_all, int, 0); 7162306a36Sopenharmony_ciMODULE_PARM_DESC(probe_all, 7262306a36Sopenharmony_ci "Set to probe tertiary+ ISA port ranges even if PCI"); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int probe_mask = ~0; 7562306a36Sopenharmony_cimodule_param(probe_mask, int, 0); 7662306a36Sopenharmony_ciMODULE_PARM_DESC(probe_mask, "Probe mask for legacy ISA PATA ports"); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int autospeed; 7962306a36Sopenharmony_cimodule_param(autospeed, int, 0); 8062306a36Sopenharmony_ciMODULE_PARM_DESC(autospeed, "Chip present that snoops speed changes"); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int pio_mask = ATA_PIO4; 8362306a36Sopenharmony_cimodule_param(pio_mask, int, 0); 8462306a36Sopenharmony_ciMODULE_PARM_DESC(pio_mask, "PIO range for autospeed devices"); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic int iordy_mask = 0xFFFFFFFF; 8762306a36Sopenharmony_cimodule_param(iordy_mask, int, 0); 8862306a36Sopenharmony_ciMODULE_PARM_DESC(iordy_mask, "Use IORDY if available"); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int ht6560a; 9162306a36Sopenharmony_cimodule_param(ht6560a, int, 0); 9262306a36Sopenharmony_ciMODULE_PARM_DESC(ht6560a, "HT 6560A on primary 1, second 2, both 3"); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int ht6560b; 9562306a36Sopenharmony_cimodule_param(ht6560b, int, 0); 9662306a36Sopenharmony_ciMODULE_PARM_DESC(ht6560b, "HT 6560B on primary 1, secondary 2, both 3"); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int opti82c611a; 9962306a36Sopenharmony_cimodule_param(opti82c611a, int, 0); 10062306a36Sopenharmony_ciMODULE_PARM_DESC(opti82c611a, 10162306a36Sopenharmony_ci "Opti 82c611A on primary 1, secondary 2, both 3"); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int opti82c46x; 10462306a36Sopenharmony_cimodule_param(opti82c46x, int, 0); 10562306a36Sopenharmony_ciMODULE_PARM_DESC(opti82c46x, 10662306a36Sopenharmony_ci "Opti 82c465MV on primary 1, secondary 2, both 3"); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#ifdef CONFIG_PATA_QDI_MODULE 10962306a36Sopenharmony_cistatic int qdi = 1; 11062306a36Sopenharmony_ci#else 11162306a36Sopenharmony_cistatic int qdi; 11262306a36Sopenharmony_ci#endif 11362306a36Sopenharmony_cimodule_param(qdi, int, 0); 11462306a36Sopenharmony_ciMODULE_PARM_DESC(qdi, "Set to probe QDI controllers"); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#ifdef CONFIG_PATA_WINBOND_VLB_MODULE 11762306a36Sopenharmony_cistatic int winbond = 1; 11862306a36Sopenharmony_ci#else 11962306a36Sopenharmony_cistatic int winbond; 12062306a36Sopenharmony_ci#endif 12162306a36Sopenharmony_cimodule_param(winbond, int, 0); 12262306a36Sopenharmony_ciMODULE_PARM_DESC(winbond, 12362306a36Sopenharmony_ci "Set to probe Winbond controllers, " 12462306a36Sopenharmony_ci "give I/O port if non standard"); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cienum controller { 12862306a36Sopenharmony_ci BIOS = 0, 12962306a36Sopenharmony_ci SNOOP = 1, 13062306a36Sopenharmony_ci PDC20230 = 2, 13162306a36Sopenharmony_ci HT6560A = 3, 13262306a36Sopenharmony_ci HT6560B = 4, 13362306a36Sopenharmony_ci OPTI611A = 5, 13462306a36Sopenharmony_ci OPTI46X = 6, 13562306a36Sopenharmony_ci QDI6500 = 7, 13662306a36Sopenharmony_ci QDI6580 = 8, 13762306a36Sopenharmony_ci QDI6580DP = 9, /* Dual channel mode is different */ 13862306a36Sopenharmony_ci W83759A = 10, 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci UNKNOWN = -1 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistruct legacy_data { 14462306a36Sopenharmony_ci unsigned long timing; 14562306a36Sopenharmony_ci u8 clock[2]; 14662306a36Sopenharmony_ci u8 last; 14762306a36Sopenharmony_ci int fast; 14862306a36Sopenharmony_ci enum controller type; 14962306a36Sopenharmony_ci struct platform_device *platform_dev; 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistruct legacy_probe { 15362306a36Sopenharmony_ci unsigned char *name; 15462306a36Sopenharmony_ci unsigned long port; 15562306a36Sopenharmony_ci unsigned int irq; 15662306a36Sopenharmony_ci unsigned int slot; 15762306a36Sopenharmony_ci enum controller type; 15862306a36Sopenharmony_ci unsigned long private; 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistruct legacy_controller { 16262306a36Sopenharmony_ci const char *name; 16362306a36Sopenharmony_ci struct ata_port_operations *ops; 16462306a36Sopenharmony_ci unsigned int pio_mask; 16562306a36Sopenharmony_ci unsigned int flags; 16662306a36Sopenharmony_ci unsigned int pflags; 16762306a36Sopenharmony_ci int (*setup)(struct platform_device *, struct legacy_probe *probe, 16862306a36Sopenharmony_ci struct legacy_data *data); 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic struct legacy_probe probe_list[NR_HOST]; 17462306a36Sopenharmony_cistatic struct legacy_data legacy_data[NR_HOST]; 17562306a36Sopenharmony_cistatic struct ata_host *legacy_host[NR_HOST]; 17662306a36Sopenharmony_cistatic int nr_legacy_host; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/** 18062306a36Sopenharmony_ci * legacy_probe_add - Add interface to probe list 18162306a36Sopenharmony_ci * @port: Controller port 18262306a36Sopenharmony_ci * @irq: IRQ number 18362306a36Sopenharmony_ci * @type: Controller type 18462306a36Sopenharmony_ci * @private: Controller specific info 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * Add an entry into the probe list for ATA controllers. This is used 18762306a36Sopenharmony_ci * to add the default ISA slots and then to build up the table 18862306a36Sopenharmony_ci * further according to other ISA/VLB/Weird device scans 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * An I/O port list is used to keep ordering stable and sane, as we 19162306a36Sopenharmony_ci * don't have any good way to talk about ordering otherwise 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int legacy_probe_add(unsigned long port, unsigned int irq, 19562306a36Sopenharmony_ci enum controller type, unsigned long private) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct legacy_probe *lp = &probe_list[0]; 19862306a36Sopenharmony_ci int i; 19962306a36Sopenharmony_ci struct legacy_probe *free = NULL; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci for (i = 0; i < NR_HOST; i++) { 20262306a36Sopenharmony_ci if (lp->port == 0 && free == NULL) 20362306a36Sopenharmony_ci free = lp; 20462306a36Sopenharmony_ci /* Matching port, or the correct slot for ordering */ 20562306a36Sopenharmony_ci if (lp->port == port || legacy_port[i] == port) { 20662306a36Sopenharmony_ci if (!(probe_mask & 1 << i)) 20762306a36Sopenharmony_ci return -1; 20862306a36Sopenharmony_ci free = lp; 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci lp++; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci if (free == NULL) { 21462306a36Sopenharmony_ci printk(KERN_ERR "pata_legacy: Too many interfaces.\n"); 21562306a36Sopenharmony_ci return -1; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci /* Fill in the entry for later probing */ 21862306a36Sopenharmony_ci free->port = port; 21962306a36Sopenharmony_ci free->irq = irq; 22062306a36Sopenharmony_ci free->type = type; 22162306a36Sopenharmony_ci free->private = private; 22262306a36Sopenharmony_ci return 0; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/** 22762306a36Sopenharmony_ci * legacy_set_mode - mode setting 22862306a36Sopenharmony_ci * @link: IDE link 22962306a36Sopenharmony_ci * @unused: Device that failed when error is returned 23062306a36Sopenharmony_ci * 23162306a36Sopenharmony_ci * Use a non standard set_mode function. We don't want to be tuned. 23262306a36Sopenharmony_ci * 23362306a36Sopenharmony_ci * The BIOS configured everything. Our job is not to fiddle. Just use 23462306a36Sopenharmony_ci * whatever PIO the hardware is using and leave it at that. When we 23562306a36Sopenharmony_ci * get some kind of nice user driven API for control then we can 23662306a36Sopenharmony_ci * expand on this as per hdparm in the base kernel. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int legacy_set_mode(struct ata_link *link, struct ata_device **unused) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct ata_device *dev; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ata_for_each_dev(dev, link, ENABLED) { 24462306a36Sopenharmony_ci ata_dev_info(dev, "configured for PIO\n"); 24562306a36Sopenharmony_ci dev->pio_mode = XFER_PIO_0; 24662306a36Sopenharmony_ci dev->xfer_mode = XFER_PIO_0; 24762306a36Sopenharmony_ci dev->xfer_shift = ATA_SHIFT_PIO; 24862306a36Sopenharmony_ci dev->flags |= ATA_DFLAG_PIO; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic const struct scsi_host_template legacy_sht = { 25462306a36Sopenharmony_ci ATA_PIO_SHT(DRV_NAME), 25562306a36Sopenharmony_ci}; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic const struct ata_port_operations legacy_base_port_ops = { 25862306a36Sopenharmony_ci .inherits = &ata_sff_port_ops, 25962306a36Sopenharmony_ci .cable_detect = ata_cable_40wire, 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/* 26362306a36Sopenharmony_ci * These ops are used if the user indicates the hardware 26462306a36Sopenharmony_ci * snoops the commands to decide on the mode and handles the 26562306a36Sopenharmony_ci * mode selection "magically" itself. Several legacy controllers 26662306a36Sopenharmony_ci * do this. The mode range can be set if it is not 0x1F by setting 26762306a36Sopenharmony_ci * pio_mask as well. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic struct ata_port_operations simple_port_ops = { 27162306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 27262306a36Sopenharmony_ci .sff_data_xfer = ata_sff_data_xfer32, 27362306a36Sopenharmony_ci}; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic struct ata_port_operations legacy_port_ops = { 27662306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 27762306a36Sopenharmony_ci .sff_data_xfer = ata_sff_data_xfer32, 27862306a36Sopenharmony_ci .set_mode = legacy_set_mode, 27962306a36Sopenharmony_ci}; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/* 28262306a36Sopenharmony_ci * Promise 20230C and 20620 support 28362306a36Sopenharmony_ci * 28462306a36Sopenharmony_ci * This controller supports PIO0 to PIO2. We set PIO timings 28562306a36Sopenharmony_ci * conservatively to allow for 50MHz Vesa Local Bus. The 20620 DMA 28662306a36Sopenharmony_ci * support is weird being DMA to controller and PIO'd to the host 28762306a36Sopenharmony_ci * and not supported. 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci int tries = 5; 29362306a36Sopenharmony_ci int pio = adev->pio_mode - XFER_PIO_0; 29462306a36Sopenharmony_ci u8 rt; 29562306a36Sopenharmony_ci unsigned long flags; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* Safe as UP only. Force I/Os to occur together */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci local_irq_save(flags); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Unlock the control interface */ 30262306a36Sopenharmony_ci do { 30362306a36Sopenharmony_ci inb(0x1F5); 30462306a36Sopenharmony_ci outb(inb(0x1F2) | 0x80, 0x1F2); 30562306a36Sopenharmony_ci inb(0x1F2); 30662306a36Sopenharmony_ci inb(0x3F6); 30762306a36Sopenharmony_ci inb(0x3F6); 30862306a36Sopenharmony_ci inb(0x1F2); 30962306a36Sopenharmony_ci inb(0x1F2); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci while ((inb(0x1F2) & 0x80) && --tries); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci local_irq_restore(flags); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci outb(inb(0x1F4) & 0x07, 0x1F4); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci rt = inb(0x1F3); 31862306a36Sopenharmony_ci rt &= ~(0x07 << (3 * !adev->devno)); 31962306a36Sopenharmony_ci if (pio) 32062306a36Sopenharmony_ci rt |= (1 + 3 * pio) << (3 * !adev->devno); 32162306a36Sopenharmony_ci outb(rt, 0x1F3); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci udelay(100); 32462306a36Sopenharmony_ci outb(inb(0x1F2) | 0x01, 0x1F2); 32562306a36Sopenharmony_ci udelay(100); 32662306a36Sopenharmony_ci inb(0x1F5); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic unsigned int pdc_data_xfer_vlb(struct ata_queued_cmd *qc, 33162306a36Sopenharmony_ci unsigned char *buf, unsigned int buflen, int rw) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct ata_device *dev = qc->dev; 33462306a36Sopenharmony_ci struct ata_port *ap = dev->link->ap; 33562306a36Sopenharmony_ci int slop = buflen & 3; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* 32bit I/O capable *and* we need to write a whole number of dwords */ 33862306a36Sopenharmony_ci if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3) 33962306a36Sopenharmony_ci && (ap->pflags & ATA_PFLAG_PIO32)) { 34062306a36Sopenharmony_ci unsigned long flags; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci local_irq_save(flags); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* Perform the 32bit I/O synchronization sequence */ 34562306a36Sopenharmony_ci ioread8(ap->ioaddr.nsect_addr); 34662306a36Sopenharmony_ci ioread8(ap->ioaddr.nsect_addr); 34762306a36Sopenharmony_ci ioread8(ap->ioaddr.nsect_addr); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Now the data */ 35062306a36Sopenharmony_ci if (rw == READ) 35162306a36Sopenharmony_ci ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); 35262306a36Sopenharmony_ci else 35362306a36Sopenharmony_ci iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (unlikely(slop)) { 35662306a36Sopenharmony_ci __le32 pad = 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (rw == READ) { 35962306a36Sopenharmony_ci pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); 36062306a36Sopenharmony_ci memcpy(buf + buflen - slop, &pad, slop); 36162306a36Sopenharmony_ci } else { 36262306a36Sopenharmony_ci memcpy(&pad, buf + buflen - slop, slop); 36362306a36Sopenharmony_ci iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci buflen += 4 - slop; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci local_irq_restore(flags); 36862306a36Sopenharmony_ci } else 36962306a36Sopenharmony_ci buflen = ata_sff_data_xfer32(qc, buf, buflen, rw); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return buflen; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic struct ata_port_operations pdc20230_port_ops = { 37562306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 37662306a36Sopenharmony_ci .set_piomode = pdc20230_set_piomode, 37762306a36Sopenharmony_ci .sff_data_xfer = pdc_data_xfer_vlb, 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci/* 38162306a36Sopenharmony_ci * Holtek 6560A support 38262306a36Sopenharmony_ci * 38362306a36Sopenharmony_ci * This controller supports PIO0 to PIO2 (no IORDY even though higher 38462306a36Sopenharmony_ci * timings can be loaded). 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci u8 active, recover; 39062306a36Sopenharmony_ci struct ata_timing t; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Get the timing data in cycles. For now play safe at 50Mhz */ 39362306a36Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci active = clamp_val(t.active, 2, 15); 39662306a36Sopenharmony_ci recover = clamp_val(t.recover, 4, 15); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci inb(0x3E6); 39962306a36Sopenharmony_ci inb(0x3E6); 40062306a36Sopenharmony_ci inb(0x3E6); 40162306a36Sopenharmony_ci inb(0x3E6); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci iowrite8(recover << 4 | active, ap->ioaddr.device_addr); 40462306a36Sopenharmony_ci ioread8(ap->ioaddr.status_addr); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic struct ata_port_operations ht6560a_port_ops = { 40862306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 40962306a36Sopenharmony_ci .set_piomode = ht6560a_set_piomode, 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci/* 41362306a36Sopenharmony_ci * Holtek 6560B support 41462306a36Sopenharmony_ci * 41562306a36Sopenharmony_ci * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO 41662306a36Sopenharmony_ci * setting unless we see an ATAPI device in which case we force it off. 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * FIXME: need to implement 2nd channel support. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci u8 active, recover; 42462306a36Sopenharmony_ci struct ata_timing t; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* Get the timing data in cycles. For now play safe at 50Mhz */ 42762306a36Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci active = clamp_val(t.active, 2, 15); 43062306a36Sopenharmony_ci recover = clamp_val(t.recover, 2, 16) & 0x0F; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci inb(0x3E6); 43362306a36Sopenharmony_ci inb(0x3E6); 43462306a36Sopenharmony_ci inb(0x3E6); 43562306a36Sopenharmony_ci inb(0x3E6); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci iowrite8(recover << 4 | active, ap->ioaddr.device_addr); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (adev->class != ATA_DEV_ATA) { 44062306a36Sopenharmony_ci u8 rconf = inb(0x3E6); 44162306a36Sopenharmony_ci if (rconf & 0x24) { 44262306a36Sopenharmony_ci rconf &= ~0x24; 44362306a36Sopenharmony_ci outb(rconf, 0x3E6); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci ioread8(ap->ioaddr.status_addr); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic struct ata_port_operations ht6560b_port_ops = { 45062306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 45162306a36Sopenharmony_ci .set_piomode = ht6560b_set_piomode, 45262306a36Sopenharmony_ci}; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci/* 45562306a36Sopenharmony_ci * Opti core chipset helpers 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/** 45962306a36Sopenharmony_ci * opti_syscfg - read OPTI chipset configuration 46062306a36Sopenharmony_ci * @reg: Configuration register to read 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * Returns the value of an OPTI system board configuration register. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic u8 opti_syscfg(u8 reg) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci unsigned long flags; 46862306a36Sopenharmony_ci u8 r; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* Uniprocessor chipset and must force cycles adjancent */ 47162306a36Sopenharmony_ci local_irq_save(flags); 47262306a36Sopenharmony_ci outb(reg, 0x22); 47362306a36Sopenharmony_ci r = inb(0x24); 47462306a36Sopenharmony_ci local_irq_restore(flags); 47562306a36Sopenharmony_ci return r; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci/* 47962306a36Sopenharmony_ci * Opti 82C611A 48062306a36Sopenharmony_ci * 48162306a36Sopenharmony_ci * This controller supports PIO0 to PIO3. 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic void opti82c611a_set_piomode(struct ata_port *ap, 48562306a36Sopenharmony_ci struct ata_device *adev) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci u8 active, recover, setup; 48862306a36Sopenharmony_ci struct ata_timing t; 48962306a36Sopenharmony_ci struct ata_device *pair = ata_dev_pair(adev); 49062306a36Sopenharmony_ci int clock; 49162306a36Sopenharmony_ci int khz[4] = { 50000, 40000, 33000, 25000 }; 49262306a36Sopenharmony_ci u8 rc; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* Enter configuration mode */ 49562306a36Sopenharmony_ci ioread16(ap->ioaddr.error_addr); 49662306a36Sopenharmony_ci ioread16(ap->ioaddr.error_addr); 49762306a36Sopenharmony_ci iowrite8(3, ap->ioaddr.nsect_addr); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* Read VLB clock strapping */ 50062306a36Sopenharmony_ci clock = 1000000000 / khz[ioread8(ap->ioaddr.lbah_addr) & 0x03]; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Get the timing data in cycles */ 50362306a36Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* Setup timing is shared */ 50662306a36Sopenharmony_ci if (pair) { 50762306a36Sopenharmony_ci struct ata_timing tp; 50862306a36Sopenharmony_ci ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci active = clamp_val(t.active, 2, 17) - 2; 51462306a36Sopenharmony_ci recover = clamp_val(t.recover, 1, 16) - 1; 51562306a36Sopenharmony_ci setup = clamp_val(t.setup, 1, 4) - 1; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* Select the right timing bank for write timing */ 51862306a36Sopenharmony_ci rc = ioread8(ap->ioaddr.lbal_addr); 51962306a36Sopenharmony_ci rc &= 0x7F; 52062306a36Sopenharmony_ci rc |= (adev->devno << 7); 52162306a36Sopenharmony_ci iowrite8(rc, ap->ioaddr.lbal_addr); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* Write the timings */ 52462306a36Sopenharmony_ci iowrite8(active << 4 | recover, ap->ioaddr.error_addr); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* Select the right bank for read timings, also 52762306a36Sopenharmony_ci load the shared timings for address */ 52862306a36Sopenharmony_ci rc = ioread8(ap->ioaddr.device_addr); 52962306a36Sopenharmony_ci rc &= 0xC0; 53062306a36Sopenharmony_ci rc |= adev->devno; /* Index select */ 53162306a36Sopenharmony_ci rc |= (setup << 4) | 0x04; 53262306a36Sopenharmony_ci iowrite8(rc, ap->ioaddr.device_addr); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* Load the read timings */ 53562306a36Sopenharmony_ci iowrite8(active << 4 | recover, ap->ioaddr.data_addr); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* Ensure the timing register mode is right */ 53862306a36Sopenharmony_ci rc = ioread8(ap->ioaddr.lbal_addr); 53962306a36Sopenharmony_ci rc &= 0x73; 54062306a36Sopenharmony_ci rc |= 0x84; 54162306a36Sopenharmony_ci iowrite8(rc, ap->ioaddr.lbal_addr); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* Exit command mode */ 54462306a36Sopenharmony_ci iowrite8(0x83, ap->ioaddr.nsect_addr); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic struct ata_port_operations opti82c611a_port_ops = { 54962306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 55062306a36Sopenharmony_ci .set_piomode = opti82c611a_set_piomode, 55162306a36Sopenharmony_ci}; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/* 55462306a36Sopenharmony_ci * Opti 82C465MV 55562306a36Sopenharmony_ci * 55662306a36Sopenharmony_ci * This controller supports PIO0 to PIO3. Unlike the 611A the MVB 55762306a36Sopenharmony_ci * version is dual channel but doesn't have a lot of unique registers. 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci u8 active, recover, setup; 56362306a36Sopenharmony_ci struct ata_timing t; 56462306a36Sopenharmony_ci struct ata_device *pair = ata_dev_pair(adev); 56562306a36Sopenharmony_ci int clock; 56662306a36Sopenharmony_ci int khz[4] = { 50000, 40000, 33000, 25000 }; 56762306a36Sopenharmony_ci u8 rc; 56862306a36Sopenharmony_ci u8 sysclk; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* Get the clock */ 57162306a36Sopenharmony_ci sysclk = (opti_syscfg(0xAC) & 0xC0) >> 6; /* BIOS set */ 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* Enter configuration mode */ 57462306a36Sopenharmony_ci ioread16(ap->ioaddr.error_addr); 57562306a36Sopenharmony_ci ioread16(ap->ioaddr.error_addr); 57662306a36Sopenharmony_ci iowrite8(3, ap->ioaddr.nsect_addr); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* Read VLB clock strapping */ 57962306a36Sopenharmony_ci clock = 1000000000 / khz[sysclk]; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* Get the timing data in cycles */ 58262306a36Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Setup timing is shared */ 58562306a36Sopenharmony_ci if (pair) { 58662306a36Sopenharmony_ci struct ata_timing tp; 58762306a36Sopenharmony_ci ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci active = clamp_val(t.active, 2, 17) - 2; 59362306a36Sopenharmony_ci recover = clamp_val(t.recover, 1, 16) - 1; 59462306a36Sopenharmony_ci setup = clamp_val(t.setup, 1, 4) - 1; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* Select the right timing bank for write timing */ 59762306a36Sopenharmony_ci rc = ioread8(ap->ioaddr.lbal_addr); 59862306a36Sopenharmony_ci rc &= 0x7F; 59962306a36Sopenharmony_ci rc |= (adev->devno << 7); 60062306a36Sopenharmony_ci iowrite8(rc, ap->ioaddr.lbal_addr); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* Write the timings */ 60362306a36Sopenharmony_ci iowrite8(active << 4 | recover, ap->ioaddr.error_addr); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* Select the right bank for read timings, also 60662306a36Sopenharmony_ci load the shared timings for address */ 60762306a36Sopenharmony_ci rc = ioread8(ap->ioaddr.device_addr); 60862306a36Sopenharmony_ci rc &= 0xC0; 60962306a36Sopenharmony_ci rc |= adev->devno; /* Index select */ 61062306a36Sopenharmony_ci rc |= (setup << 4) | 0x04; 61162306a36Sopenharmony_ci iowrite8(rc, ap->ioaddr.device_addr); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* Load the read timings */ 61462306a36Sopenharmony_ci iowrite8(active << 4 | recover, ap->ioaddr.data_addr); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* Ensure the timing register mode is right */ 61762306a36Sopenharmony_ci rc = ioread8(ap->ioaddr.lbal_addr); 61862306a36Sopenharmony_ci rc &= 0x73; 61962306a36Sopenharmony_ci rc |= 0x84; 62062306a36Sopenharmony_ci iowrite8(rc, ap->ioaddr.lbal_addr); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Exit command mode */ 62362306a36Sopenharmony_ci iowrite8(0x83, ap->ioaddr.nsect_addr); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* We need to know this for quad device on the MVB */ 62662306a36Sopenharmony_ci ap->host->private_data = ap; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci/** 63062306a36Sopenharmony_ci * opti82c46x_qc_issue - command issue 63162306a36Sopenharmony_ci * @qc: command pending 63262306a36Sopenharmony_ci * 63362306a36Sopenharmony_ci * Called when the libata layer is about to issue a command. We wrap 63462306a36Sopenharmony_ci * this interface so that we can load the correct ATA timings. The 63562306a36Sopenharmony_ci * MVB has a single set of timing registers and these are shared 63662306a36Sopenharmony_ci * across channels. As there are two registers we really ought to 63762306a36Sopenharmony_ci * track the last two used values as a sort of register window. For 63862306a36Sopenharmony_ci * now we just reload on a channel switch. On the single channel 63962306a36Sopenharmony_ci * setup this condition never fires so we do nothing extra. 64062306a36Sopenharmony_ci * 64162306a36Sopenharmony_ci * FIXME: dual channel needs ->serialize support 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic unsigned int opti82c46x_qc_issue(struct ata_queued_cmd *qc) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct ata_port *ap = qc->ap; 64762306a36Sopenharmony_ci struct ata_device *adev = qc->dev; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* If timings are set and for the wrong channel (2nd test is 65062306a36Sopenharmony_ci due to a libata shortcoming and will eventually go I hope) */ 65162306a36Sopenharmony_ci if (ap->host->private_data != ap->host 65262306a36Sopenharmony_ci && ap->host->private_data != NULL) 65362306a36Sopenharmony_ci opti82c46x_set_piomode(ap, adev); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return ata_sff_qc_issue(qc); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic struct ata_port_operations opti82c46x_port_ops = { 65962306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 66062306a36Sopenharmony_ci .set_piomode = opti82c46x_set_piomode, 66162306a36Sopenharmony_ci .qc_issue = opti82c46x_qc_issue, 66262306a36Sopenharmony_ci}; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci/** 66562306a36Sopenharmony_ci * qdi65x0_set_piomode - PIO setup for QDI65x0 66662306a36Sopenharmony_ci * @ap: Port 66762306a36Sopenharmony_ci * @adev: Device 66862306a36Sopenharmony_ci * 66962306a36Sopenharmony_ci * In single channel mode the 6580 has one clock per device and we can 67062306a36Sopenharmony_ci * avoid the requirement to clock switch. We also have to load the timing 67162306a36Sopenharmony_ci * into the right clock according to whether we are master or slave. 67262306a36Sopenharmony_ci * 67362306a36Sopenharmony_ci * In dual channel mode the 6580 has one clock per channel and we have 67462306a36Sopenharmony_ci * to software clockswitch in qc_issue. 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic void qdi65x0_set_piomode(struct ata_port *ap, struct ata_device *adev) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct ata_timing t; 68062306a36Sopenharmony_ci struct legacy_data *ld_qdi = ap->host->private_data; 68162306a36Sopenharmony_ci int active, recovery; 68262306a36Sopenharmony_ci u8 timing; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* Get the timing data in cycles */ 68562306a36Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (ld_qdi->fast) { 68862306a36Sopenharmony_ci active = 8 - clamp_val(t.active, 1, 8); 68962306a36Sopenharmony_ci recovery = 18 - clamp_val(t.recover, 3, 18); 69062306a36Sopenharmony_ci } else { 69162306a36Sopenharmony_ci active = 9 - clamp_val(t.active, 2, 9); 69262306a36Sopenharmony_ci recovery = 15 - clamp_val(t.recover, 0, 15); 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci timing = (recovery << 4) | active | 0x08; 69562306a36Sopenharmony_ci ld_qdi->clock[adev->devno] = timing; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (ld_qdi->type == QDI6580) 69862306a36Sopenharmony_ci outb(timing, ld_qdi->timing + 2 * adev->devno); 69962306a36Sopenharmony_ci else 70062306a36Sopenharmony_ci outb(timing, ld_qdi->timing + 2 * ap->port_no); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* Clear the FIFO */ 70362306a36Sopenharmony_ci if (ld_qdi->type != QDI6500 && adev->class != ATA_DEV_ATA) 70462306a36Sopenharmony_ci outb(0x5F, (ld_qdi->timing & 0xFFF0) + 3); 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci/** 70862306a36Sopenharmony_ci * qdi_qc_issue - command issue 70962306a36Sopenharmony_ci * @qc: command pending 71062306a36Sopenharmony_ci * 71162306a36Sopenharmony_ci * Called when the libata layer is about to issue a command. We wrap 71262306a36Sopenharmony_ci * this interface so that we can load the correct ATA timings. 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic unsigned int qdi_qc_issue(struct ata_queued_cmd *qc) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct ata_port *ap = qc->ap; 71862306a36Sopenharmony_ci struct ata_device *adev = qc->dev; 71962306a36Sopenharmony_ci struct legacy_data *ld_qdi = ap->host->private_data; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (ld_qdi->clock[adev->devno] != ld_qdi->last) { 72262306a36Sopenharmony_ci if (adev->pio_mode) { 72362306a36Sopenharmony_ci ld_qdi->last = ld_qdi->clock[adev->devno]; 72462306a36Sopenharmony_ci outb(ld_qdi->clock[adev->devno], ld_qdi->timing + 72562306a36Sopenharmony_ci 2 * ap->port_no); 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci return ata_sff_qc_issue(qc); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic unsigned int vlb32_data_xfer(struct ata_queued_cmd *qc, 73262306a36Sopenharmony_ci unsigned char *buf, 73362306a36Sopenharmony_ci unsigned int buflen, int rw) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct ata_device *adev = qc->dev; 73662306a36Sopenharmony_ci struct ata_port *ap = adev->link->ap; 73762306a36Sopenharmony_ci int slop = buflen & 3; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3) 74062306a36Sopenharmony_ci && (ap->pflags & ATA_PFLAG_PIO32)) { 74162306a36Sopenharmony_ci if (rw == WRITE) 74262306a36Sopenharmony_ci iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); 74362306a36Sopenharmony_ci else 74462306a36Sopenharmony_ci ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (unlikely(slop)) { 74762306a36Sopenharmony_ci __le32 pad = 0; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (rw == WRITE) { 75062306a36Sopenharmony_ci memcpy(&pad, buf + buflen - slop, slop); 75162306a36Sopenharmony_ci iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); 75262306a36Sopenharmony_ci } else { 75362306a36Sopenharmony_ci pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); 75462306a36Sopenharmony_ci memcpy(buf + buflen - slop, &pad, slop); 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci return (buflen + 3) & ~3; 75862306a36Sopenharmony_ci } else 75962306a36Sopenharmony_ci return ata_sff_data_xfer(qc, buf, buflen, rw); 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic int qdi_port(struct platform_device *dev, 76362306a36Sopenharmony_ci struct legacy_probe *lp, struct legacy_data *ld) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci if (devm_request_region(&dev->dev, lp->private, 4, "qdi") == NULL) 76662306a36Sopenharmony_ci return -EBUSY; 76762306a36Sopenharmony_ci ld->timing = lp->private; 76862306a36Sopenharmony_ci return 0; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic struct ata_port_operations qdi6500_port_ops = { 77262306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 77362306a36Sopenharmony_ci .set_piomode = qdi65x0_set_piomode, 77462306a36Sopenharmony_ci .qc_issue = qdi_qc_issue, 77562306a36Sopenharmony_ci .sff_data_xfer = vlb32_data_xfer, 77662306a36Sopenharmony_ci}; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic struct ata_port_operations qdi6580_port_ops = { 77962306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 78062306a36Sopenharmony_ci .set_piomode = qdi65x0_set_piomode, 78162306a36Sopenharmony_ci .sff_data_xfer = vlb32_data_xfer, 78262306a36Sopenharmony_ci}; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic struct ata_port_operations qdi6580dp_port_ops = { 78562306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 78662306a36Sopenharmony_ci .set_piomode = qdi65x0_set_piomode, 78762306a36Sopenharmony_ci .qc_issue = qdi_qc_issue, 78862306a36Sopenharmony_ci .sff_data_xfer = vlb32_data_xfer, 78962306a36Sopenharmony_ci}; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic DEFINE_SPINLOCK(winbond_lock); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic void winbond_writecfg(unsigned long port, u8 reg, u8 val) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci unsigned long flags; 79662306a36Sopenharmony_ci spin_lock_irqsave(&winbond_lock, flags); 79762306a36Sopenharmony_ci outb(reg, port + 0x01); 79862306a36Sopenharmony_ci outb(val, port + 0x02); 79962306a36Sopenharmony_ci spin_unlock_irqrestore(&winbond_lock, flags); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic u8 winbond_readcfg(unsigned long port, u8 reg) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci u8 val; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci unsigned long flags; 80762306a36Sopenharmony_ci spin_lock_irqsave(&winbond_lock, flags); 80862306a36Sopenharmony_ci outb(reg, port + 0x01); 80962306a36Sopenharmony_ci val = inb(port + 0x02); 81062306a36Sopenharmony_ci spin_unlock_irqrestore(&winbond_lock, flags); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return val; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci struct ata_timing t; 81862306a36Sopenharmony_ci struct legacy_data *ld_winbond = ap->host->private_data; 81962306a36Sopenharmony_ci int active, recovery; 82062306a36Sopenharmony_ci u8 reg; 82162306a36Sopenharmony_ci int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci reg = winbond_readcfg(ld_winbond->timing, 0x81); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* Get the timing data in cycles */ 82662306a36Sopenharmony_ci if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ 82762306a36Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); 82862306a36Sopenharmony_ci else 82962306a36Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci active = (clamp_val(t.active, 3, 17) - 1) & 0x0F; 83262306a36Sopenharmony_ci recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F; 83362306a36Sopenharmony_ci timing = (active << 4) | recovery; 83462306a36Sopenharmony_ci winbond_writecfg(ld_winbond->timing, timing, reg); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Load the setup timing */ 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci reg = 0x35; 83962306a36Sopenharmony_ci if (adev->class != ATA_DEV_ATA) 84062306a36Sopenharmony_ci reg |= 0x08; /* FIFO off */ 84162306a36Sopenharmony_ci if (!ata_pio_need_iordy(adev)) 84262306a36Sopenharmony_ci reg |= 0x02; /* IORDY off */ 84362306a36Sopenharmony_ci reg |= (clamp_val(t.setup, 0, 3) << 6); 84462306a36Sopenharmony_ci winbond_writecfg(ld_winbond->timing, timing + 1, reg); 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic int winbond_port(struct platform_device *dev, 84862306a36Sopenharmony_ci struct legacy_probe *lp, struct legacy_data *ld) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci if (devm_request_region(&dev->dev, lp->private, 4, "winbond") == NULL) 85162306a36Sopenharmony_ci return -EBUSY; 85262306a36Sopenharmony_ci ld->timing = lp->private; 85362306a36Sopenharmony_ci return 0; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_cistatic struct ata_port_operations winbond_port_ops = { 85762306a36Sopenharmony_ci .inherits = &legacy_base_port_ops, 85862306a36Sopenharmony_ci .set_piomode = winbond_set_piomode, 85962306a36Sopenharmony_ci .sff_data_xfer = vlb32_data_xfer, 86062306a36Sopenharmony_ci}; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic struct legacy_controller controllers[] = { 86362306a36Sopenharmony_ci {"BIOS", &legacy_port_ops, ATA_PIO4, 86462306a36Sopenharmony_ci ATA_FLAG_NO_IORDY, 0, NULL }, 86562306a36Sopenharmony_ci {"Snooping", &simple_port_ops, ATA_PIO4, 86662306a36Sopenharmony_ci 0, 0, NULL }, 86762306a36Sopenharmony_ci {"PDC20230", &pdc20230_port_ops, ATA_PIO2, 86862306a36Sopenharmony_ci ATA_FLAG_NO_IORDY, 86962306a36Sopenharmony_ci ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, NULL }, 87062306a36Sopenharmony_ci {"HT6560A", &ht6560a_port_ops, ATA_PIO2, 87162306a36Sopenharmony_ci ATA_FLAG_NO_IORDY, 0, NULL }, 87262306a36Sopenharmony_ci {"HT6560B", &ht6560b_port_ops, ATA_PIO4, 87362306a36Sopenharmony_ci ATA_FLAG_NO_IORDY, 0, NULL }, 87462306a36Sopenharmony_ci {"OPTI82C611A", &opti82c611a_port_ops, ATA_PIO3, 87562306a36Sopenharmony_ci 0, 0, NULL }, 87662306a36Sopenharmony_ci {"OPTI82C46X", &opti82c46x_port_ops, ATA_PIO3, 87762306a36Sopenharmony_ci 0, 0, NULL }, 87862306a36Sopenharmony_ci {"QDI6500", &qdi6500_port_ops, ATA_PIO2, 87962306a36Sopenharmony_ci ATA_FLAG_NO_IORDY, 88062306a36Sopenharmony_ci ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, 88162306a36Sopenharmony_ci {"QDI6580", &qdi6580_port_ops, ATA_PIO4, 88262306a36Sopenharmony_ci 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, 88362306a36Sopenharmony_ci {"QDI6580DP", &qdi6580dp_port_ops, ATA_PIO4, 88462306a36Sopenharmony_ci 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, 88562306a36Sopenharmony_ci {"W83759A", &winbond_port_ops, ATA_PIO4, 88662306a36Sopenharmony_ci 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, 88762306a36Sopenharmony_ci winbond_port } 88862306a36Sopenharmony_ci}; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci/** 89162306a36Sopenharmony_ci * probe_chip_type - Discover controller 89262306a36Sopenharmony_ci * @probe: Probe entry to check 89362306a36Sopenharmony_ci * 89462306a36Sopenharmony_ci * Probe an ATA port and identify the type of controller. We don't 89562306a36Sopenharmony_ci * check if the controller appears to be driveless at this point. 89662306a36Sopenharmony_ci */ 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic __init int probe_chip_type(struct legacy_probe *probe) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci int mask = 1 << probe->slot; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (winbond && (probe->port == 0x1F0 || probe->port == 0x170)) { 90362306a36Sopenharmony_ci u8 reg = winbond_readcfg(winbond, 0x81); 90462306a36Sopenharmony_ci reg |= 0x80; /* jumpered mode off */ 90562306a36Sopenharmony_ci winbond_writecfg(winbond, 0x81, reg); 90662306a36Sopenharmony_ci reg = winbond_readcfg(winbond, 0x83); 90762306a36Sopenharmony_ci reg |= 0xF0; /* local control */ 90862306a36Sopenharmony_ci winbond_writecfg(winbond, 0x83, reg); 90962306a36Sopenharmony_ci reg = winbond_readcfg(winbond, 0x85); 91062306a36Sopenharmony_ci reg |= 0xF0; /* programmable timing */ 91162306a36Sopenharmony_ci winbond_writecfg(winbond, 0x85, reg); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci reg = winbond_readcfg(winbond, 0x81); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (reg & mask) 91662306a36Sopenharmony_ci return W83759A; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci if (probe->port == 0x1F0) { 91962306a36Sopenharmony_ci unsigned long flags; 92062306a36Sopenharmony_ci local_irq_save(flags); 92162306a36Sopenharmony_ci /* Probes */ 92262306a36Sopenharmony_ci outb(inb(0x1F2) | 0x80, 0x1F2); 92362306a36Sopenharmony_ci inb(0x1F5); 92462306a36Sopenharmony_ci inb(0x1F2); 92562306a36Sopenharmony_ci inb(0x3F6); 92662306a36Sopenharmony_ci inb(0x3F6); 92762306a36Sopenharmony_ci inb(0x1F2); 92862306a36Sopenharmony_ci inb(0x1F2); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if ((inb(0x1F2) & 0x80) == 0) { 93162306a36Sopenharmony_ci /* PDC20230c or 20630 ? */ 93262306a36Sopenharmony_ci printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller" 93362306a36Sopenharmony_ci " detected.\n"); 93462306a36Sopenharmony_ci udelay(100); 93562306a36Sopenharmony_ci inb(0x1F5); 93662306a36Sopenharmony_ci local_irq_restore(flags); 93762306a36Sopenharmony_ci return PDC20230; 93862306a36Sopenharmony_ci } else { 93962306a36Sopenharmony_ci outb(0x55, 0x1F2); 94062306a36Sopenharmony_ci inb(0x1F2); 94162306a36Sopenharmony_ci inb(0x1F2); 94262306a36Sopenharmony_ci if (inb(0x1F2) == 0x00) 94362306a36Sopenharmony_ci printk(KERN_INFO "PDC20230-B VLB ATA " 94462306a36Sopenharmony_ci "controller detected.\n"); 94562306a36Sopenharmony_ci local_irq_restore(flags); 94662306a36Sopenharmony_ci return BIOS; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (ht6560a & mask) 95162306a36Sopenharmony_ci return HT6560A; 95262306a36Sopenharmony_ci if (ht6560b & mask) 95362306a36Sopenharmony_ci return HT6560B; 95462306a36Sopenharmony_ci if (opti82c611a & mask) 95562306a36Sopenharmony_ci return OPTI611A; 95662306a36Sopenharmony_ci if (opti82c46x & mask) 95762306a36Sopenharmony_ci return OPTI46X; 95862306a36Sopenharmony_ci if (autospeed & mask) 95962306a36Sopenharmony_ci return SNOOP; 96062306a36Sopenharmony_ci return BIOS; 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci/** 96562306a36Sopenharmony_ci * legacy_init_one - attach a legacy interface 96662306a36Sopenharmony_ci * @probe: probe record 96762306a36Sopenharmony_ci * 96862306a36Sopenharmony_ci * Register an ISA bus IDE interface. Such interfaces are PIO and we 96962306a36Sopenharmony_ci * assume do not support IRQ sharing. 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic __init int legacy_init_one(struct legacy_probe *probe) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci struct legacy_controller *controller = &controllers[probe->type]; 97562306a36Sopenharmony_ci int pio_modes = controller->pio_mask; 97662306a36Sopenharmony_ci unsigned long io = probe->port; 97762306a36Sopenharmony_ci u32 mask = (1 << probe->slot); 97862306a36Sopenharmony_ci struct ata_port_operations *ops = controller->ops; 97962306a36Sopenharmony_ci struct legacy_data *ld = &legacy_data[probe->slot]; 98062306a36Sopenharmony_ci struct ata_host *host = NULL; 98162306a36Sopenharmony_ci struct ata_port *ap; 98262306a36Sopenharmony_ci struct platform_device *pdev; 98362306a36Sopenharmony_ci struct ata_device *dev; 98462306a36Sopenharmony_ci void __iomem *io_addr, *ctrl_addr; 98562306a36Sopenharmony_ci u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY; 98662306a36Sopenharmony_ci int ret; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci iordy |= controller->flags; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci pdev = platform_device_register_simple(DRV_NAME, probe->slot, NULL, 0); 99162306a36Sopenharmony_ci if (IS_ERR(pdev)) 99262306a36Sopenharmony_ci return PTR_ERR(pdev); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci ret = -EBUSY; 99562306a36Sopenharmony_ci if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL || 99662306a36Sopenharmony_ci devm_request_region(&pdev->dev, io + 0x0206, 1, 99762306a36Sopenharmony_ci "pata_legacy") == NULL) 99862306a36Sopenharmony_ci goto fail; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci ret = -ENOMEM; 100162306a36Sopenharmony_ci io_addr = devm_ioport_map(&pdev->dev, io, 8); 100262306a36Sopenharmony_ci ctrl_addr = devm_ioport_map(&pdev->dev, io + 0x0206, 1); 100362306a36Sopenharmony_ci if (!io_addr || !ctrl_addr) 100462306a36Sopenharmony_ci goto fail; 100562306a36Sopenharmony_ci ld->type = probe->type; 100662306a36Sopenharmony_ci if (controller->setup) 100762306a36Sopenharmony_ci if (controller->setup(pdev, probe, ld) < 0) 100862306a36Sopenharmony_ci goto fail; 100962306a36Sopenharmony_ci host = ata_host_alloc(&pdev->dev, 1); 101062306a36Sopenharmony_ci if (!host) 101162306a36Sopenharmony_ci goto fail; 101262306a36Sopenharmony_ci ap = host->ports[0]; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci ap->ops = ops; 101562306a36Sopenharmony_ci ap->pio_mask = pio_modes; 101662306a36Sopenharmony_ci ap->flags |= ATA_FLAG_SLAVE_POSS | iordy; 101762306a36Sopenharmony_ci ap->pflags |= controller->pflags; 101862306a36Sopenharmony_ci ap->ioaddr.cmd_addr = io_addr; 101962306a36Sopenharmony_ci ap->ioaddr.altstatus_addr = ctrl_addr; 102062306a36Sopenharmony_ci ap->ioaddr.ctl_addr = ctrl_addr; 102162306a36Sopenharmony_ci ata_sff_std_ports(&ap->ioaddr); 102262306a36Sopenharmony_ci ap->host->private_data = ld; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, io + 0x0206); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci ret = ata_host_activate(host, probe->irq, ata_sff_interrupt, 0, 102762306a36Sopenharmony_ci &legacy_sht); 102862306a36Sopenharmony_ci if (ret) 102962306a36Sopenharmony_ci goto fail; 103062306a36Sopenharmony_ci async_synchronize_full(); 103162306a36Sopenharmony_ci ld->platform_dev = pdev; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* Nothing found means we drop the port as its probably not there */ 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci ret = -ENODEV; 103662306a36Sopenharmony_ci ata_for_each_dev(dev, &ap->link, ALL) { 103762306a36Sopenharmony_ci if (!ata_dev_absent(dev)) { 103862306a36Sopenharmony_ci legacy_host[probe->slot] = host; 103962306a36Sopenharmony_ci ld->platform_dev = pdev; 104062306a36Sopenharmony_ci return 0; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci ata_host_detach(host); 104462306a36Sopenharmony_cifail: 104562306a36Sopenharmony_ci platform_device_unregister(pdev); 104662306a36Sopenharmony_ci return ret; 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci/** 105062306a36Sopenharmony_ci * legacy_check_special_cases - ATA special cases 105162306a36Sopenharmony_ci * @p: PCI device to check 105262306a36Sopenharmony_ci * @primary: set this if we find an ATA master 105362306a36Sopenharmony_ci * @secondary: set this if we find an ATA secondary 105462306a36Sopenharmony_ci * 105562306a36Sopenharmony_ci * A small number of vendors implemented early PCI ATA interfaces 105662306a36Sopenharmony_ci * on bridge logic without the ATA interface being PCI visible. 105762306a36Sopenharmony_ci * Where we have a matching PCI driver we must skip the relevant 105862306a36Sopenharmony_ci * device here. If we don't know about it then the legacy driver 105962306a36Sopenharmony_ci * is the right driver anyway. 106062306a36Sopenharmony_ci */ 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic void __init legacy_check_special_cases(struct pci_dev *p, int *primary, 106362306a36Sopenharmony_ci int *secondary) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci /* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */ 106662306a36Sopenharmony_ci if (p->vendor == 0x1078 && p->device == 0x0000) { 106762306a36Sopenharmony_ci *primary = *secondary = 1; 106862306a36Sopenharmony_ci return; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci /* Cyrix CS5520 pre SFF MWDMA ATA on the bridge */ 107162306a36Sopenharmony_ci if (p->vendor == 0x1078 && p->device == 0x0002) { 107262306a36Sopenharmony_ci *primary = *secondary = 1; 107362306a36Sopenharmony_ci return; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci /* Intel MPIIX - PIO ATA on non PCI side of bridge */ 107662306a36Sopenharmony_ci if (p->vendor == 0x8086 && p->device == 0x1234) { 107762306a36Sopenharmony_ci u16 r; 107862306a36Sopenharmony_ci pci_read_config_word(p, 0x6C, &r); 107962306a36Sopenharmony_ci if (r & 0x8000) { 108062306a36Sopenharmony_ci /* ATA port enabled */ 108162306a36Sopenharmony_ci if (r & 0x4000) 108262306a36Sopenharmony_ci *secondary = 1; 108362306a36Sopenharmony_ci else 108462306a36Sopenharmony_ci *primary = 1; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci return; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cistatic __init void probe_opti_vlb(void) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci /* If an OPTI 82C46X is present find out where the channels are */ 109362306a36Sopenharmony_ci static const char *optis[4] = { 109462306a36Sopenharmony_ci "3/463MV", "5MV", 109562306a36Sopenharmony_ci "5MVA", "5MVB" 109662306a36Sopenharmony_ci }; 109762306a36Sopenharmony_ci u8 chans = 1; 109862306a36Sopenharmony_ci u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci opti82c46x = 3; /* Assume master and slave first */ 110162306a36Sopenharmony_ci printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", 110262306a36Sopenharmony_ci optis[ctrl]); 110362306a36Sopenharmony_ci if (ctrl == 3) 110462306a36Sopenharmony_ci chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1; 110562306a36Sopenharmony_ci ctrl = opti_syscfg(0xAC); 110662306a36Sopenharmony_ci /* Check enabled and this port is the 465MV port. On the 110762306a36Sopenharmony_ci MVB we may have two channels */ 110862306a36Sopenharmony_ci if (ctrl & 8) { 110962306a36Sopenharmony_ci if (chans == 2) { 111062306a36Sopenharmony_ci legacy_probe_add(0x1F0, 14, OPTI46X, 0); 111162306a36Sopenharmony_ci legacy_probe_add(0x170, 15, OPTI46X, 0); 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci if (ctrl & 4) 111462306a36Sopenharmony_ci legacy_probe_add(0x170, 15, OPTI46X, 0); 111562306a36Sopenharmony_ci else 111662306a36Sopenharmony_ci legacy_probe_add(0x1F0, 14, OPTI46X, 0); 111762306a36Sopenharmony_ci } else 111862306a36Sopenharmony_ci legacy_probe_add(0x1F0, 14, OPTI46X, 0); 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_cistatic __init void qdi65_identify_port(u8 r, u8 res, unsigned long port) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci static const unsigned long ide_port[2] = { 0x170, 0x1F0 }; 112462306a36Sopenharmony_ci /* Check card type */ 112562306a36Sopenharmony_ci if ((r & 0xF0) == 0xC0) { 112662306a36Sopenharmony_ci /* QD6500: single channel */ 112762306a36Sopenharmony_ci if (r & 8) 112862306a36Sopenharmony_ci /* Disabled ? */ 112962306a36Sopenharmony_ci return; 113062306a36Sopenharmony_ci legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), 113162306a36Sopenharmony_ci QDI6500, port); 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) { 113462306a36Sopenharmony_ci /* QD6580: dual channel */ 113562306a36Sopenharmony_ci if (!request_region(port + 2 , 2, "pata_qdi")) { 113662306a36Sopenharmony_ci release_region(port, 2); 113762306a36Sopenharmony_ci return; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci res = inb(port + 3); 114062306a36Sopenharmony_ci /* Single channel mode ? */ 114162306a36Sopenharmony_ci if (res & 1) 114262306a36Sopenharmony_ci legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), 114362306a36Sopenharmony_ci QDI6580, port); 114462306a36Sopenharmony_ci else { /* Dual channel mode */ 114562306a36Sopenharmony_ci legacy_probe_add(0x1F0, 14, QDI6580DP, port); 114662306a36Sopenharmony_ci /* port + 0x02, r & 0x04 */ 114762306a36Sopenharmony_ci legacy_probe_add(0x170, 15, QDI6580DP, port + 2); 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci release_region(port + 2, 2); 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cistatic __init void probe_qdi_vlb(void) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci unsigned long flags; 115662306a36Sopenharmony_ci static const unsigned long qd_port[2] = { 0x30, 0xB0 }; 115762306a36Sopenharmony_ci int i; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* 116062306a36Sopenharmony_ci * Check each possible QD65xx base address 116162306a36Sopenharmony_ci */ 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 116462306a36Sopenharmony_ci unsigned long port = qd_port[i]; 116562306a36Sopenharmony_ci u8 r, res; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (request_region(port, 2, "pata_qdi")) { 116962306a36Sopenharmony_ci /* Check for a card */ 117062306a36Sopenharmony_ci local_irq_save(flags); 117162306a36Sopenharmony_ci /* I have no h/w that needs this delay but it 117262306a36Sopenharmony_ci is present in the historic code */ 117362306a36Sopenharmony_ci r = inb(port); 117462306a36Sopenharmony_ci udelay(1); 117562306a36Sopenharmony_ci outb(0x19, port); 117662306a36Sopenharmony_ci udelay(1); 117762306a36Sopenharmony_ci res = inb(port); 117862306a36Sopenharmony_ci udelay(1); 117962306a36Sopenharmony_ci outb(r, port); 118062306a36Sopenharmony_ci udelay(1); 118162306a36Sopenharmony_ci local_irq_restore(flags); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci /* Fail */ 118462306a36Sopenharmony_ci if (res == 0x19) { 118562306a36Sopenharmony_ci release_region(port, 2); 118662306a36Sopenharmony_ci continue; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci /* Passes the presence test */ 118962306a36Sopenharmony_ci r = inb(port + 1); 119062306a36Sopenharmony_ci udelay(1); 119162306a36Sopenharmony_ci /* Check port agrees with port set */ 119262306a36Sopenharmony_ci if ((r & 2) >> 1 == i) 119362306a36Sopenharmony_ci qdi65_identify_port(r, res, port); 119462306a36Sopenharmony_ci release_region(port, 2); 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci/** 120062306a36Sopenharmony_ci * legacy_init - attach legacy interfaces 120162306a36Sopenharmony_ci * 120262306a36Sopenharmony_ci * Attach legacy IDE interfaces by scanning the usual IRQ/port suspects. 120362306a36Sopenharmony_ci * Right now we do not scan the ide0 and ide1 address but should do so 120462306a36Sopenharmony_ci * for non PCI systems or systems with no PCI IDE legacy mode devices. 120562306a36Sopenharmony_ci * If you fix that note there are special cases to consider like VLB 120662306a36Sopenharmony_ci * drivers and CS5510/20. 120762306a36Sopenharmony_ci */ 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic __init int legacy_init(void) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci int i; 121262306a36Sopenharmony_ci int ct = 0; 121362306a36Sopenharmony_ci int primary = 0; 121462306a36Sopenharmony_ci int secondary = 0; 121562306a36Sopenharmony_ci int pci_present = 0; 121662306a36Sopenharmony_ci struct legacy_probe *pl = &probe_list[0]; 121762306a36Sopenharmony_ci int slot = 0; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci struct pci_dev *p = NULL; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci for_each_pci_dev(p) { 122262306a36Sopenharmony_ci int r; 122362306a36Sopenharmony_ci /* Check for any overlap of the system ATA mappings. Native 122462306a36Sopenharmony_ci mode controllers stuck on these addresses or some devices 122562306a36Sopenharmony_ci in 'raid' mode won't be found by the storage class test */ 122662306a36Sopenharmony_ci for (r = 0; r < 6; r++) { 122762306a36Sopenharmony_ci if (pci_resource_start(p, r) == 0x1f0) 122862306a36Sopenharmony_ci primary = 1; 122962306a36Sopenharmony_ci if (pci_resource_start(p, r) == 0x170) 123062306a36Sopenharmony_ci secondary = 1; 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci /* Check for special cases */ 123362306a36Sopenharmony_ci legacy_check_special_cases(p, &primary, &secondary); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* If PCI bus is present then don't probe for tertiary 123662306a36Sopenharmony_ci legacy ports */ 123762306a36Sopenharmony_ci pci_present = 1; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (winbond == 1) 124162306a36Sopenharmony_ci winbond = 0x130; /* Default port, alt is 1B0 */ 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if (primary == 0 || all) 124462306a36Sopenharmony_ci legacy_probe_add(0x1F0, 14, UNKNOWN, 0); 124562306a36Sopenharmony_ci if (secondary == 0 || all) 124662306a36Sopenharmony_ci legacy_probe_add(0x170, 15, UNKNOWN, 0); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (probe_all || !pci_present) { 124962306a36Sopenharmony_ci /* ISA/VLB extra ports */ 125062306a36Sopenharmony_ci legacy_probe_add(0x1E8, 11, UNKNOWN, 0); 125162306a36Sopenharmony_ci legacy_probe_add(0x168, 10, UNKNOWN, 0); 125262306a36Sopenharmony_ci legacy_probe_add(0x1E0, 8, UNKNOWN, 0); 125362306a36Sopenharmony_ci legacy_probe_add(0x160, 12, UNKNOWN, 0); 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci if (opti82c46x) 125762306a36Sopenharmony_ci probe_opti_vlb(); 125862306a36Sopenharmony_ci if (qdi) 125962306a36Sopenharmony_ci probe_qdi_vlb(); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci for (i = 0; i < NR_HOST; i++, pl++) { 126262306a36Sopenharmony_ci if (pl->port == 0) 126362306a36Sopenharmony_ci continue; 126462306a36Sopenharmony_ci if (pl->type == UNKNOWN) 126562306a36Sopenharmony_ci pl->type = probe_chip_type(pl); 126662306a36Sopenharmony_ci pl->slot = slot++; 126762306a36Sopenharmony_ci if (legacy_init_one(pl) == 0) 126862306a36Sopenharmony_ci ct++; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci if (ct != 0) 127162306a36Sopenharmony_ci return 0; 127262306a36Sopenharmony_ci return -ENODEV; 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_cistatic __exit void legacy_exit(void) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci int i; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci for (i = 0; i < nr_legacy_host; i++) { 128062306a36Sopenharmony_ci struct legacy_data *ld = &legacy_data[i]; 128162306a36Sopenharmony_ci ata_host_detach(legacy_host[i]); 128262306a36Sopenharmony_ci platform_device_unregister(ld->platform_dev); 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ciMODULE_AUTHOR("Alan Cox"); 128762306a36Sopenharmony_ciMODULE_DESCRIPTION("low-level driver for legacy ATA"); 128862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 128962306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 129062306a36Sopenharmony_ciMODULE_ALIAS("pata_qdi"); 129162306a36Sopenharmony_ciMODULE_ALIAS("pata_winbond"); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_cimodule_init(legacy_init); 129462306a36Sopenharmony_cimodule_exit(legacy_exit); 1295