18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * pata-legacy.c - Legacy port PATA/SATA controller driver. 48c2ecf20Sopenharmony_ci * Copyright 2005/2006 Red Hat, all rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * An ATA driver for the legacy ATA ports. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Data Sources: 98c2ecf20Sopenharmony_ci * Opti 82C465/82C611 support: Data sheets at opti-inc.com 108c2ecf20Sopenharmony_ci * HT6560 series: 118c2ecf20Sopenharmony_ci * Promise 20230/20620: 128c2ecf20Sopenharmony_ci * http://www.ryston.cz/petr/vlb/pdc20230b.html 138c2ecf20Sopenharmony_ci * http://www.ryston.cz/petr/vlb/pdc20230c.html 148c2ecf20Sopenharmony_ci * http://www.ryston.cz/petr/vlb/pdc20630.html 158c2ecf20Sopenharmony_ci * QDI65x0: 168c2ecf20Sopenharmony_ci * http://www.ryston.cz/petr/vlb/qd6500.html 178c2ecf20Sopenharmony_ci * http://www.ryston.cz/petr/vlb/qd6580.html 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * QDI65x0 probe code based on drivers/ide/legacy/qd65xx.c 208c2ecf20Sopenharmony_ci * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by 218c2ecf20Sopenharmony_ci * Samuel Thibault <samuel.thibault@ens-lyon.org> 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Unsupported but docs exist: 248c2ecf20Sopenharmony_ci * Appian/Adaptec AIC25VL01/Cirrus Logic PD7220 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * This driver handles legacy (that is "ISA/VLB side") IDE ports found 278c2ecf20Sopenharmony_ci * on PC class systems. There are three hybrid devices that are exceptions 288c2ecf20Sopenharmony_ci * The Cyrix 5510/5520 where a pre SFF ATA device is on the bridge and 298c2ecf20Sopenharmony_ci * the MPIIX where the tuning is PCI side but the IDE is "ISA side". 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Specific support is included for the ht6560a/ht6560b/opti82c611a/ 328c2ecf20Sopenharmony_ci * opti82c465mv/promise 20230c/20630/qdi65x0/winbond83759A 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Support for the Winbond 83759A when operating in advanced mode. 358c2ecf20Sopenharmony_ci * Multichip mode is not currently supported. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Use the autospeed and pio_mask options with: 388c2ecf20Sopenharmony_ci * Appian ADI/2 aka CLPD7220 or AIC25VL01. 398c2ecf20Sopenharmony_ci * Use the jumpers, autospeed and set pio_mask to the mode on the jumpers with 408c2ecf20Sopenharmony_ci * Goldstar GM82C711, PIC-1288A-125, UMC 82C871F, Winbond W83759, 418c2ecf20Sopenharmony_ci * Winbond W83759A, Promise PDC20230-B 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * For now use autospeed and pio_mask as above with the W83759A. This may 448c2ecf20Sopenharmony_ci * change. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include <linux/async.h> 488c2ecf20Sopenharmony_ci#include <linux/kernel.h> 498c2ecf20Sopenharmony_ci#include <linux/module.h> 508c2ecf20Sopenharmony_ci#include <linux/pci.h> 518c2ecf20Sopenharmony_ci#include <linux/init.h> 528c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 538c2ecf20Sopenharmony_ci#include <linux/delay.h> 548c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 558c2ecf20Sopenharmony_ci#include <linux/ata.h> 568c2ecf20Sopenharmony_ci#include <linux/libata.h> 578c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define DRV_NAME "pata_legacy" 608c2ecf20Sopenharmony_ci#define DRV_VERSION "0.6.5" 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define NR_HOST 6 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int all; 658c2ecf20Sopenharmony_cimodule_param(all, int, 0444); 668c2ecf20Sopenharmony_ciMODULE_PARM_DESC(all, "Grab all legacy port devices, even if PCI(0=off, 1=on)"); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cienum controller { 698c2ecf20Sopenharmony_ci BIOS = 0, 708c2ecf20Sopenharmony_ci SNOOP = 1, 718c2ecf20Sopenharmony_ci PDC20230 = 2, 728c2ecf20Sopenharmony_ci HT6560A = 3, 738c2ecf20Sopenharmony_ci HT6560B = 4, 748c2ecf20Sopenharmony_ci OPTI611A = 5, 758c2ecf20Sopenharmony_ci OPTI46X = 6, 768c2ecf20Sopenharmony_ci QDI6500 = 7, 778c2ecf20Sopenharmony_ci QDI6580 = 8, 788c2ecf20Sopenharmony_ci QDI6580DP = 9, /* Dual channel mode is different */ 798c2ecf20Sopenharmony_ci W83759A = 10, 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci UNKNOWN = -1 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct legacy_data { 858c2ecf20Sopenharmony_ci unsigned long timing; 868c2ecf20Sopenharmony_ci u8 clock[2]; 878c2ecf20Sopenharmony_ci u8 last; 888c2ecf20Sopenharmony_ci int fast; 898c2ecf20Sopenharmony_ci enum controller type; 908c2ecf20Sopenharmony_ci struct platform_device *platform_dev; 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistruct legacy_probe { 948c2ecf20Sopenharmony_ci unsigned char *name; 958c2ecf20Sopenharmony_ci unsigned long port; 968c2ecf20Sopenharmony_ci unsigned int irq; 978c2ecf20Sopenharmony_ci unsigned int slot; 988c2ecf20Sopenharmony_ci enum controller type; 998c2ecf20Sopenharmony_ci unsigned long private; 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistruct legacy_controller { 1038c2ecf20Sopenharmony_ci const char *name; 1048c2ecf20Sopenharmony_ci struct ata_port_operations *ops; 1058c2ecf20Sopenharmony_ci unsigned int pio_mask; 1068c2ecf20Sopenharmony_ci unsigned int flags; 1078c2ecf20Sopenharmony_ci unsigned int pflags; 1088c2ecf20Sopenharmony_ci int (*setup)(struct platform_device *, struct legacy_probe *probe, 1098c2ecf20Sopenharmony_ci struct legacy_data *data); 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic struct legacy_probe probe_list[NR_HOST]; 1158c2ecf20Sopenharmony_cistatic struct legacy_data legacy_data[NR_HOST]; 1168c2ecf20Sopenharmony_cistatic struct ata_host *legacy_host[NR_HOST]; 1178c2ecf20Sopenharmony_cistatic int nr_legacy_host; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int probe_all; /* Set to check all ISA port ranges */ 1218c2ecf20Sopenharmony_cistatic int ht6560a; /* HT 6560A on primary 1, second 2, both 3 */ 1228c2ecf20Sopenharmony_cistatic int ht6560b; /* HT 6560A on primary 1, second 2, both 3 */ 1238c2ecf20Sopenharmony_cistatic int opti82c611a; /* Opti82c611A on primary 1, sec 2, both 3 */ 1248c2ecf20Sopenharmony_cistatic int opti82c46x; /* Opti 82c465MV present(pri/sec autodetect) */ 1258c2ecf20Sopenharmony_cistatic int autospeed; /* Chip present which snoops speed changes */ 1268c2ecf20Sopenharmony_cistatic int pio_mask = ATA_PIO4; /* PIO range for autospeed devices */ 1278c2ecf20Sopenharmony_cistatic int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* Set to probe QDI controllers */ 1308c2ecf20Sopenharmony_ci#ifdef CONFIG_PATA_QDI_MODULE 1318c2ecf20Sopenharmony_cistatic int qdi = 1; 1328c2ecf20Sopenharmony_ci#else 1338c2ecf20Sopenharmony_cistatic int qdi; 1348c2ecf20Sopenharmony_ci#endif 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#ifdef CONFIG_PATA_WINBOND_VLB_MODULE 1378c2ecf20Sopenharmony_cistatic int winbond = 1; /* Set to probe Winbond controllers, 1388c2ecf20Sopenharmony_ci give I/O port if non standard */ 1398c2ecf20Sopenharmony_ci#else 1408c2ecf20Sopenharmony_cistatic int winbond; /* Set to probe Winbond controllers, 1418c2ecf20Sopenharmony_ci give I/O port if non standard */ 1428c2ecf20Sopenharmony_ci#endif 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/** 1458c2ecf20Sopenharmony_ci * legacy_probe_add - Add interface to probe list 1468c2ecf20Sopenharmony_ci * @port: Controller port 1478c2ecf20Sopenharmony_ci * @irq: IRQ number 1488c2ecf20Sopenharmony_ci * @type: Controller type 1498c2ecf20Sopenharmony_ci * @private: Controller specific info 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * Add an entry into the probe list for ATA controllers. This is used 1528c2ecf20Sopenharmony_ci * to add the default ISA slots and then to build up the table 1538c2ecf20Sopenharmony_ci * further according to other ISA/VLB/Weird device scans 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * An I/O port list is used to keep ordering stable and sane, as we 1568c2ecf20Sopenharmony_ci * don't have any good way to talk about ordering otherwise 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic int legacy_probe_add(unsigned long port, unsigned int irq, 1608c2ecf20Sopenharmony_ci enum controller type, unsigned long private) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct legacy_probe *lp = &probe_list[0]; 1638c2ecf20Sopenharmony_ci int i; 1648c2ecf20Sopenharmony_ci struct legacy_probe *free = NULL; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci for (i = 0; i < NR_HOST; i++) { 1678c2ecf20Sopenharmony_ci if (lp->port == 0 && free == NULL) 1688c2ecf20Sopenharmony_ci free = lp; 1698c2ecf20Sopenharmony_ci /* Matching port, or the correct slot for ordering */ 1708c2ecf20Sopenharmony_ci if (lp->port == port || legacy_port[i] == port) { 1718c2ecf20Sopenharmony_ci free = lp; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci lp++; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci if (free == NULL) { 1778c2ecf20Sopenharmony_ci printk(KERN_ERR "pata_legacy: Too many interfaces.\n"); 1788c2ecf20Sopenharmony_ci return -1; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci /* Fill in the entry for later probing */ 1818c2ecf20Sopenharmony_ci free->port = port; 1828c2ecf20Sopenharmony_ci free->irq = irq; 1838c2ecf20Sopenharmony_ci free->type = type; 1848c2ecf20Sopenharmony_ci free->private = private; 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/** 1908c2ecf20Sopenharmony_ci * legacy_set_mode - mode setting 1918c2ecf20Sopenharmony_ci * @link: IDE link 1928c2ecf20Sopenharmony_ci * @unused: Device that failed when error is returned 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Use a non standard set_mode function. We don't want to be tuned. 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * The BIOS configured everything. Our job is not to fiddle. Just use 1978c2ecf20Sopenharmony_ci * whatever PIO the hardware is using and leave it at that. When we 1988c2ecf20Sopenharmony_ci * get some kind of nice user driven API for control then we can 1998c2ecf20Sopenharmony_ci * expand on this as per hdparm in the base kernel. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int legacy_set_mode(struct ata_link *link, struct ata_device **unused) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct ata_device *dev; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ENABLED) { 2078c2ecf20Sopenharmony_ci ata_dev_info(dev, "configured for PIO\n"); 2088c2ecf20Sopenharmony_ci dev->pio_mode = XFER_PIO_0; 2098c2ecf20Sopenharmony_ci dev->xfer_mode = XFER_PIO_0; 2108c2ecf20Sopenharmony_ci dev->xfer_shift = ATA_SHIFT_PIO; 2118c2ecf20Sopenharmony_ci dev->flags |= ATA_DFLAG_PIO; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic struct scsi_host_template legacy_sht = { 2178c2ecf20Sopenharmony_ci ATA_PIO_SHT(DRV_NAME), 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic const struct ata_port_operations legacy_base_port_ops = { 2218c2ecf20Sopenharmony_ci .inherits = &ata_sff_port_ops, 2228c2ecf20Sopenharmony_ci .cable_detect = ata_cable_40wire, 2238c2ecf20Sopenharmony_ci}; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* 2268c2ecf20Sopenharmony_ci * These ops are used if the user indicates the hardware 2278c2ecf20Sopenharmony_ci * snoops the commands to decide on the mode and handles the 2288c2ecf20Sopenharmony_ci * mode selection "magically" itself. Several legacy controllers 2298c2ecf20Sopenharmony_ci * do this. The mode range can be set if it is not 0x1F by setting 2308c2ecf20Sopenharmony_ci * pio_mask as well. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic struct ata_port_operations simple_port_ops = { 2348c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 2358c2ecf20Sopenharmony_ci .sff_data_xfer = ata_sff_data_xfer32, 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic struct ata_port_operations legacy_port_ops = { 2398c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 2408c2ecf20Sopenharmony_ci .sff_data_xfer = ata_sff_data_xfer32, 2418c2ecf20Sopenharmony_ci .set_mode = legacy_set_mode, 2428c2ecf20Sopenharmony_ci}; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/* 2458c2ecf20Sopenharmony_ci * Promise 20230C and 20620 support 2468c2ecf20Sopenharmony_ci * 2478c2ecf20Sopenharmony_ci * This controller supports PIO0 to PIO2. We set PIO timings 2488c2ecf20Sopenharmony_ci * conservatively to allow for 50MHz Vesa Local Bus. The 20620 DMA 2498c2ecf20Sopenharmony_ci * support is weird being DMA to controller and PIO'd to the host 2508c2ecf20Sopenharmony_ci * and not supported. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci int tries = 5; 2568c2ecf20Sopenharmony_ci int pio = adev->pio_mode - XFER_PIO_0; 2578c2ecf20Sopenharmony_ci u8 rt; 2588c2ecf20Sopenharmony_ci unsigned long flags; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Safe as UP only. Force I/Os to occur together */ 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci local_irq_save(flags); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Unlock the control interface */ 2658c2ecf20Sopenharmony_ci do { 2668c2ecf20Sopenharmony_ci inb(0x1F5); 2678c2ecf20Sopenharmony_ci outb(inb(0x1F2) | 0x80, 0x1F2); 2688c2ecf20Sopenharmony_ci inb(0x1F2); 2698c2ecf20Sopenharmony_ci inb(0x3F6); 2708c2ecf20Sopenharmony_ci inb(0x3F6); 2718c2ecf20Sopenharmony_ci inb(0x1F2); 2728c2ecf20Sopenharmony_ci inb(0x1F2); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci while ((inb(0x1F2) & 0x80) && --tries); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci local_irq_restore(flags); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci outb(inb(0x1F4) & 0x07, 0x1F4); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci rt = inb(0x1F3); 2818c2ecf20Sopenharmony_ci rt &= ~(0x07 << (3 * !adev->devno)); 2828c2ecf20Sopenharmony_ci if (pio) 2838c2ecf20Sopenharmony_ci rt |= (1 + 3 * pio) << (3 * !adev->devno); 2848c2ecf20Sopenharmony_ci outb(rt, 0x1F3); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci udelay(100); 2878c2ecf20Sopenharmony_ci outb(inb(0x1F2) | 0x01, 0x1F2); 2888c2ecf20Sopenharmony_ci udelay(100); 2898c2ecf20Sopenharmony_ci inb(0x1F5); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic unsigned int pdc_data_xfer_vlb(struct ata_queued_cmd *qc, 2948c2ecf20Sopenharmony_ci unsigned char *buf, unsigned int buflen, int rw) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct ata_device *dev = qc->dev; 2978c2ecf20Sopenharmony_ci struct ata_port *ap = dev->link->ap; 2988c2ecf20Sopenharmony_ci int slop = buflen & 3; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* 32bit I/O capable *and* we need to write a whole number of dwords */ 3018c2ecf20Sopenharmony_ci if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3) 3028c2ecf20Sopenharmony_ci && (ap->pflags & ATA_PFLAG_PIO32)) { 3038c2ecf20Sopenharmony_ci unsigned long flags; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci local_irq_save(flags); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* Perform the 32bit I/O synchronization sequence */ 3088c2ecf20Sopenharmony_ci ioread8(ap->ioaddr.nsect_addr); 3098c2ecf20Sopenharmony_ci ioread8(ap->ioaddr.nsect_addr); 3108c2ecf20Sopenharmony_ci ioread8(ap->ioaddr.nsect_addr); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* Now the data */ 3138c2ecf20Sopenharmony_ci if (rw == READ) 3148c2ecf20Sopenharmony_ci ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); 3158c2ecf20Sopenharmony_ci else 3168c2ecf20Sopenharmony_ci iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (unlikely(slop)) { 3198c2ecf20Sopenharmony_ci __le32 pad = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (rw == READ) { 3228c2ecf20Sopenharmony_ci pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); 3238c2ecf20Sopenharmony_ci memcpy(buf + buflen - slop, &pad, slop); 3248c2ecf20Sopenharmony_ci } else { 3258c2ecf20Sopenharmony_ci memcpy(&pad, buf + buflen - slop, slop); 3268c2ecf20Sopenharmony_ci iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci buflen += 4 - slop; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci local_irq_restore(flags); 3318c2ecf20Sopenharmony_ci } else 3328c2ecf20Sopenharmony_ci buflen = ata_sff_data_xfer32(qc, buf, buflen, rw); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return buflen; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic struct ata_port_operations pdc20230_port_ops = { 3388c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 3398c2ecf20Sopenharmony_ci .set_piomode = pdc20230_set_piomode, 3408c2ecf20Sopenharmony_ci .sff_data_xfer = pdc_data_xfer_vlb, 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/* 3448c2ecf20Sopenharmony_ci * Holtek 6560A support 3458c2ecf20Sopenharmony_ci * 3468c2ecf20Sopenharmony_ci * This controller supports PIO0 to PIO2 (no IORDY even though higher 3478c2ecf20Sopenharmony_ci * timings can be loaded). 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci u8 active, recover; 3538c2ecf20Sopenharmony_ci struct ata_timing t; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Get the timing data in cycles. For now play safe at 50Mhz */ 3568c2ecf20Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci active = clamp_val(t.active, 2, 15); 3598c2ecf20Sopenharmony_ci recover = clamp_val(t.recover, 4, 15); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci inb(0x3E6); 3628c2ecf20Sopenharmony_ci inb(0x3E6); 3638c2ecf20Sopenharmony_ci inb(0x3E6); 3648c2ecf20Sopenharmony_ci inb(0x3E6); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci iowrite8(recover << 4 | active, ap->ioaddr.device_addr); 3678c2ecf20Sopenharmony_ci ioread8(ap->ioaddr.status_addr); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic struct ata_port_operations ht6560a_port_ops = { 3718c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 3728c2ecf20Sopenharmony_ci .set_piomode = ht6560a_set_piomode, 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/* 3768c2ecf20Sopenharmony_ci * Holtek 6560B support 3778c2ecf20Sopenharmony_ci * 3788c2ecf20Sopenharmony_ci * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO 3798c2ecf20Sopenharmony_ci * setting unless we see an ATAPI device in which case we force it off. 3808c2ecf20Sopenharmony_ci * 3818c2ecf20Sopenharmony_ci * FIXME: need to implement 2nd channel support. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci u8 active, recover; 3878c2ecf20Sopenharmony_ci struct ata_timing t; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Get the timing data in cycles. For now play safe at 50Mhz */ 3908c2ecf20Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci active = clamp_val(t.active, 2, 15); 3938c2ecf20Sopenharmony_ci recover = clamp_val(t.recover, 2, 16) & 0x0F; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci inb(0x3E6); 3968c2ecf20Sopenharmony_ci inb(0x3E6); 3978c2ecf20Sopenharmony_ci inb(0x3E6); 3988c2ecf20Sopenharmony_ci inb(0x3E6); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci iowrite8(recover << 4 | active, ap->ioaddr.device_addr); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (adev->class != ATA_DEV_ATA) { 4038c2ecf20Sopenharmony_ci u8 rconf = inb(0x3E6); 4048c2ecf20Sopenharmony_ci if (rconf & 0x24) { 4058c2ecf20Sopenharmony_ci rconf &= ~0x24; 4068c2ecf20Sopenharmony_ci outb(rconf, 0x3E6); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci ioread8(ap->ioaddr.status_addr); 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic struct ata_port_operations ht6560b_port_ops = { 4138c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 4148c2ecf20Sopenharmony_ci .set_piomode = ht6560b_set_piomode, 4158c2ecf20Sopenharmony_ci}; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci/* 4188c2ecf20Sopenharmony_ci * Opti core chipset helpers 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/** 4228c2ecf20Sopenharmony_ci * opti_syscfg - read OPTI chipset configuration 4238c2ecf20Sopenharmony_ci * @reg: Configuration register to read 4248c2ecf20Sopenharmony_ci * 4258c2ecf20Sopenharmony_ci * Returns the value of an OPTI system board configuration register. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic u8 opti_syscfg(u8 reg) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci unsigned long flags; 4318c2ecf20Sopenharmony_ci u8 r; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Uniprocessor chipset and must force cycles adjancent */ 4348c2ecf20Sopenharmony_ci local_irq_save(flags); 4358c2ecf20Sopenharmony_ci outb(reg, 0x22); 4368c2ecf20Sopenharmony_ci r = inb(0x24); 4378c2ecf20Sopenharmony_ci local_irq_restore(flags); 4388c2ecf20Sopenharmony_ci return r; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci/* 4428c2ecf20Sopenharmony_ci * Opti 82C611A 4438c2ecf20Sopenharmony_ci * 4448c2ecf20Sopenharmony_ci * This controller supports PIO0 to PIO3. 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic void opti82c611a_set_piomode(struct ata_port *ap, 4488c2ecf20Sopenharmony_ci struct ata_device *adev) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci u8 active, recover, setup; 4518c2ecf20Sopenharmony_ci struct ata_timing t; 4528c2ecf20Sopenharmony_ci struct ata_device *pair = ata_dev_pair(adev); 4538c2ecf20Sopenharmony_ci int clock; 4548c2ecf20Sopenharmony_ci int khz[4] = { 50000, 40000, 33000, 25000 }; 4558c2ecf20Sopenharmony_ci u8 rc; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Enter configuration mode */ 4588c2ecf20Sopenharmony_ci ioread16(ap->ioaddr.error_addr); 4598c2ecf20Sopenharmony_ci ioread16(ap->ioaddr.error_addr); 4608c2ecf20Sopenharmony_ci iowrite8(3, ap->ioaddr.nsect_addr); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* Read VLB clock strapping */ 4638c2ecf20Sopenharmony_ci clock = 1000000000 / khz[ioread8(ap->ioaddr.lbah_addr) & 0x03]; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* Get the timing data in cycles */ 4668c2ecf20Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* Setup timing is shared */ 4698c2ecf20Sopenharmony_ci if (pair) { 4708c2ecf20Sopenharmony_ci struct ata_timing tp; 4718c2ecf20Sopenharmony_ci ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci active = clamp_val(t.active, 2, 17) - 2; 4778c2ecf20Sopenharmony_ci recover = clamp_val(t.recover, 1, 16) - 1; 4788c2ecf20Sopenharmony_ci setup = clamp_val(t.setup, 1, 4) - 1; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* Select the right timing bank for write timing */ 4818c2ecf20Sopenharmony_ci rc = ioread8(ap->ioaddr.lbal_addr); 4828c2ecf20Sopenharmony_ci rc &= 0x7F; 4838c2ecf20Sopenharmony_ci rc |= (adev->devno << 7); 4848c2ecf20Sopenharmony_ci iowrite8(rc, ap->ioaddr.lbal_addr); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* Write the timings */ 4878c2ecf20Sopenharmony_ci iowrite8(active << 4 | recover, ap->ioaddr.error_addr); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* Select the right bank for read timings, also 4908c2ecf20Sopenharmony_ci load the shared timings for address */ 4918c2ecf20Sopenharmony_ci rc = ioread8(ap->ioaddr.device_addr); 4928c2ecf20Sopenharmony_ci rc &= 0xC0; 4938c2ecf20Sopenharmony_ci rc |= adev->devno; /* Index select */ 4948c2ecf20Sopenharmony_ci rc |= (setup << 4) | 0x04; 4958c2ecf20Sopenharmony_ci iowrite8(rc, ap->ioaddr.device_addr); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* Load the read timings */ 4988c2ecf20Sopenharmony_ci iowrite8(active << 4 | recover, ap->ioaddr.data_addr); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* Ensure the timing register mode is right */ 5018c2ecf20Sopenharmony_ci rc = ioread8(ap->ioaddr.lbal_addr); 5028c2ecf20Sopenharmony_ci rc &= 0x73; 5038c2ecf20Sopenharmony_ci rc |= 0x84; 5048c2ecf20Sopenharmony_ci iowrite8(rc, ap->ioaddr.lbal_addr); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* Exit command mode */ 5078c2ecf20Sopenharmony_ci iowrite8(0x83, ap->ioaddr.nsect_addr); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic struct ata_port_operations opti82c611a_port_ops = { 5128c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 5138c2ecf20Sopenharmony_ci .set_piomode = opti82c611a_set_piomode, 5148c2ecf20Sopenharmony_ci}; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci/* 5178c2ecf20Sopenharmony_ci * Opti 82C465MV 5188c2ecf20Sopenharmony_ci * 5198c2ecf20Sopenharmony_ci * This controller supports PIO0 to PIO3. Unlike the 611A the MVB 5208c2ecf20Sopenharmony_ci * version is dual channel but doesn't have a lot of unique registers. 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci u8 active, recover, setup; 5268c2ecf20Sopenharmony_ci struct ata_timing t; 5278c2ecf20Sopenharmony_ci struct ata_device *pair = ata_dev_pair(adev); 5288c2ecf20Sopenharmony_ci int clock; 5298c2ecf20Sopenharmony_ci int khz[4] = { 50000, 40000, 33000, 25000 }; 5308c2ecf20Sopenharmony_ci u8 rc; 5318c2ecf20Sopenharmony_ci u8 sysclk; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* Get the clock */ 5348c2ecf20Sopenharmony_ci sysclk = (opti_syscfg(0xAC) & 0xC0) >> 6; /* BIOS set */ 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* Enter configuration mode */ 5378c2ecf20Sopenharmony_ci ioread16(ap->ioaddr.error_addr); 5388c2ecf20Sopenharmony_ci ioread16(ap->ioaddr.error_addr); 5398c2ecf20Sopenharmony_ci iowrite8(3, ap->ioaddr.nsect_addr); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* Read VLB clock strapping */ 5428c2ecf20Sopenharmony_ci clock = 1000000000 / khz[sysclk]; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* Get the timing data in cycles */ 5458c2ecf20Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* Setup timing is shared */ 5488c2ecf20Sopenharmony_ci if (pair) { 5498c2ecf20Sopenharmony_ci struct ata_timing tp; 5508c2ecf20Sopenharmony_ci ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci active = clamp_val(t.active, 2, 17) - 2; 5568c2ecf20Sopenharmony_ci recover = clamp_val(t.recover, 1, 16) - 1; 5578c2ecf20Sopenharmony_ci setup = clamp_val(t.setup, 1, 4) - 1; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Select the right timing bank for write timing */ 5608c2ecf20Sopenharmony_ci rc = ioread8(ap->ioaddr.lbal_addr); 5618c2ecf20Sopenharmony_ci rc &= 0x7F; 5628c2ecf20Sopenharmony_ci rc |= (adev->devno << 7); 5638c2ecf20Sopenharmony_ci iowrite8(rc, ap->ioaddr.lbal_addr); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* Write the timings */ 5668c2ecf20Sopenharmony_ci iowrite8(active << 4 | recover, ap->ioaddr.error_addr); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* Select the right bank for read timings, also 5698c2ecf20Sopenharmony_ci load the shared timings for address */ 5708c2ecf20Sopenharmony_ci rc = ioread8(ap->ioaddr.device_addr); 5718c2ecf20Sopenharmony_ci rc &= 0xC0; 5728c2ecf20Sopenharmony_ci rc |= adev->devno; /* Index select */ 5738c2ecf20Sopenharmony_ci rc |= (setup << 4) | 0x04; 5748c2ecf20Sopenharmony_ci iowrite8(rc, ap->ioaddr.device_addr); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /* Load the read timings */ 5778c2ecf20Sopenharmony_ci iowrite8(active << 4 | recover, ap->ioaddr.data_addr); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* Ensure the timing register mode is right */ 5808c2ecf20Sopenharmony_ci rc = ioread8(ap->ioaddr.lbal_addr); 5818c2ecf20Sopenharmony_ci rc &= 0x73; 5828c2ecf20Sopenharmony_ci rc |= 0x84; 5838c2ecf20Sopenharmony_ci iowrite8(rc, ap->ioaddr.lbal_addr); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* Exit command mode */ 5868c2ecf20Sopenharmony_ci iowrite8(0x83, ap->ioaddr.nsect_addr); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* We need to know this for quad device on the MVB */ 5898c2ecf20Sopenharmony_ci ap->host->private_data = ap; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/** 5938c2ecf20Sopenharmony_ci * opt82c465mv_qc_issue - command issue 5948c2ecf20Sopenharmony_ci * @qc: command pending 5958c2ecf20Sopenharmony_ci * 5968c2ecf20Sopenharmony_ci * Called when the libata layer is about to issue a command. We wrap 5978c2ecf20Sopenharmony_ci * this interface so that we can load the correct ATA timings. The 5988c2ecf20Sopenharmony_ci * MVB has a single set of timing registers and these are shared 5998c2ecf20Sopenharmony_ci * across channels. As there are two registers we really ought to 6008c2ecf20Sopenharmony_ci * track the last two used values as a sort of register window. For 6018c2ecf20Sopenharmony_ci * now we just reload on a channel switch. On the single channel 6028c2ecf20Sopenharmony_ci * setup this condition never fires so we do nothing extra. 6038c2ecf20Sopenharmony_ci * 6048c2ecf20Sopenharmony_ci * FIXME: dual channel needs ->serialize support 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic unsigned int opti82c46x_qc_issue(struct ata_queued_cmd *qc) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct ata_port *ap = qc->ap; 6108c2ecf20Sopenharmony_ci struct ata_device *adev = qc->dev; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* If timings are set and for the wrong channel (2nd test is 6138c2ecf20Sopenharmony_ci due to a libata shortcoming and will eventually go I hope) */ 6148c2ecf20Sopenharmony_ci if (ap->host->private_data != ap->host 6158c2ecf20Sopenharmony_ci && ap->host->private_data != NULL) 6168c2ecf20Sopenharmony_ci opti82c46x_set_piomode(ap, adev); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return ata_sff_qc_issue(qc); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic struct ata_port_operations opti82c46x_port_ops = { 6228c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 6238c2ecf20Sopenharmony_ci .set_piomode = opti82c46x_set_piomode, 6248c2ecf20Sopenharmony_ci .qc_issue = opti82c46x_qc_issue, 6258c2ecf20Sopenharmony_ci}; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci/** 6288c2ecf20Sopenharmony_ci * qdi65x0_set_piomode - PIO setup for QDI65x0 6298c2ecf20Sopenharmony_ci * @ap: Port 6308c2ecf20Sopenharmony_ci * @adev: Device 6318c2ecf20Sopenharmony_ci * 6328c2ecf20Sopenharmony_ci * In single channel mode the 6580 has one clock per device and we can 6338c2ecf20Sopenharmony_ci * avoid the requirement to clock switch. We also have to load the timing 6348c2ecf20Sopenharmony_ci * into the right clock according to whether we are master or slave. 6358c2ecf20Sopenharmony_ci * 6368c2ecf20Sopenharmony_ci * In dual channel mode the 6580 has one clock per channel and we have 6378c2ecf20Sopenharmony_ci * to software clockswitch in qc_issue. 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic void qdi65x0_set_piomode(struct ata_port *ap, struct ata_device *adev) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci struct ata_timing t; 6438c2ecf20Sopenharmony_ci struct legacy_data *ld_qdi = ap->host->private_data; 6448c2ecf20Sopenharmony_ci int active, recovery; 6458c2ecf20Sopenharmony_ci u8 timing; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Get the timing data in cycles */ 6488c2ecf20Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (ld_qdi->fast) { 6518c2ecf20Sopenharmony_ci active = 8 - clamp_val(t.active, 1, 8); 6528c2ecf20Sopenharmony_ci recovery = 18 - clamp_val(t.recover, 3, 18); 6538c2ecf20Sopenharmony_ci } else { 6548c2ecf20Sopenharmony_ci active = 9 - clamp_val(t.active, 2, 9); 6558c2ecf20Sopenharmony_ci recovery = 15 - clamp_val(t.recover, 0, 15); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci timing = (recovery << 4) | active | 0x08; 6588c2ecf20Sopenharmony_ci ld_qdi->clock[adev->devno] = timing; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (ld_qdi->type == QDI6580) 6618c2ecf20Sopenharmony_ci outb(timing, ld_qdi->timing + 2 * adev->devno); 6628c2ecf20Sopenharmony_ci else 6638c2ecf20Sopenharmony_ci outb(timing, ld_qdi->timing + 2 * ap->port_no); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* Clear the FIFO */ 6668c2ecf20Sopenharmony_ci if (ld_qdi->type != QDI6500 && adev->class != ATA_DEV_ATA) 6678c2ecf20Sopenharmony_ci outb(0x5F, (ld_qdi->timing & 0xFFF0) + 3); 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci/** 6718c2ecf20Sopenharmony_ci * qdi_qc_issue - command issue 6728c2ecf20Sopenharmony_ci * @qc: command pending 6738c2ecf20Sopenharmony_ci * 6748c2ecf20Sopenharmony_ci * Called when the libata layer is about to issue a command. We wrap 6758c2ecf20Sopenharmony_ci * this interface so that we can load the correct ATA timings. 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic unsigned int qdi_qc_issue(struct ata_queued_cmd *qc) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct ata_port *ap = qc->ap; 6818c2ecf20Sopenharmony_ci struct ata_device *adev = qc->dev; 6828c2ecf20Sopenharmony_ci struct legacy_data *ld_qdi = ap->host->private_data; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (ld_qdi->clock[adev->devno] != ld_qdi->last) { 6858c2ecf20Sopenharmony_ci if (adev->pio_mode) { 6868c2ecf20Sopenharmony_ci ld_qdi->last = ld_qdi->clock[adev->devno]; 6878c2ecf20Sopenharmony_ci outb(ld_qdi->clock[adev->devno], ld_qdi->timing + 6888c2ecf20Sopenharmony_ci 2 * ap->port_no); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci return ata_sff_qc_issue(qc); 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic unsigned int vlb32_data_xfer(struct ata_queued_cmd *qc, 6958c2ecf20Sopenharmony_ci unsigned char *buf, 6968c2ecf20Sopenharmony_ci unsigned int buflen, int rw) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci struct ata_device *adev = qc->dev; 6998c2ecf20Sopenharmony_ci struct ata_port *ap = adev->link->ap; 7008c2ecf20Sopenharmony_ci int slop = buflen & 3; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3) 7038c2ecf20Sopenharmony_ci && (ap->pflags & ATA_PFLAG_PIO32)) { 7048c2ecf20Sopenharmony_ci if (rw == WRITE) 7058c2ecf20Sopenharmony_ci iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); 7068c2ecf20Sopenharmony_ci else 7078c2ecf20Sopenharmony_ci ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (unlikely(slop)) { 7108c2ecf20Sopenharmony_ci __le32 pad = 0; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (rw == WRITE) { 7138c2ecf20Sopenharmony_ci memcpy(&pad, buf + buflen - slop, slop); 7148c2ecf20Sopenharmony_ci iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); 7158c2ecf20Sopenharmony_ci } else { 7168c2ecf20Sopenharmony_ci pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); 7178c2ecf20Sopenharmony_ci memcpy(buf + buflen - slop, &pad, slop); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci return (buflen + 3) & ~3; 7218c2ecf20Sopenharmony_ci } else 7228c2ecf20Sopenharmony_ci return ata_sff_data_xfer(qc, buf, buflen, rw); 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic int qdi_port(struct platform_device *dev, 7268c2ecf20Sopenharmony_ci struct legacy_probe *lp, struct legacy_data *ld) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci if (devm_request_region(&dev->dev, lp->private, 4, "qdi") == NULL) 7298c2ecf20Sopenharmony_ci return -EBUSY; 7308c2ecf20Sopenharmony_ci ld->timing = lp->private; 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic struct ata_port_operations qdi6500_port_ops = { 7358c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 7368c2ecf20Sopenharmony_ci .set_piomode = qdi65x0_set_piomode, 7378c2ecf20Sopenharmony_ci .qc_issue = qdi_qc_issue, 7388c2ecf20Sopenharmony_ci .sff_data_xfer = vlb32_data_xfer, 7398c2ecf20Sopenharmony_ci}; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic struct ata_port_operations qdi6580_port_ops = { 7428c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 7438c2ecf20Sopenharmony_ci .set_piomode = qdi65x0_set_piomode, 7448c2ecf20Sopenharmony_ci .sff_data_xfer = vlb32_data_xfer, 7458c2ecf20Sopenharmony_ci}; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic struct ata_port_operations qdi6580dp_port_ops = { 7488c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 7498c2ecf20Sopenharmony_ci .set_piomode = qdi65x0_set_piomode, 7508c2ecf20Sopenharmony_ci .qc_issue = qdi_qc_issue, 7518c2ecf20Sopenharmony_ci .sff_data_xfer = vlb32_data_xfer, 7528c2ecf20Sopenharmony_ci}; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(winbond_lock); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic void winbond_writecfg(unsigned long port, u8 reg, u8 val) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci unsigned long flags; 7598c2ecf20Sopenharmony_ci spin_lock_irqsave(&winbond_lock, flags); 7608c2ecf20Sopenharmony_ci outb(reg, port + 0x01); 7618c2ecf20Sopenharmony_ci outb(val, port + 0x02); 7628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&winbond_lock, flags); 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic u8 winbond_readcfg(unsigned long port, u8 reg) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci u8 val; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci unsigned long flags; 7708c2ecf20Sopenharmony_ci spin_lock_irqsave(&winbond_lock, flags); 7718c2ecf20Sopenharmony_ci outb(reg, port + 0x01); 7728c2ecf20Sopenharmony_ci val = inb(port + 0x02); 7738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&winbond_lock, flags); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci return val; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cistatic void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct ata_timing t; 7818c2ecf20Sopenharmony_ci struct legacy_data *ld_winbond = ap->host->private_data; 7828c2ecf20Sopenharmony_ci int active, recovery; 7838c2ecf20Sopenharmony_ci u8 reg; 7848c2ecf20Sopenharmony_ci int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci reg = winbond_readcfg(ld_winbond->timing, 0x81); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* Get the timing data in cycles */ 7898c2ecf20Sopenharmony_ci if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ 7908c2ecf20Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); 7918c2ecf20Sopenharmony_ci else 7928c2ecf20Sopenharmony_ci ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci active = (clamp_val(t.active, 3, 17) - 1) & 0x0F; 7958c2ecf20Sopenharmony_ci recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F; 7968c2ecf20Sopenharmony_ci timing = (active << 4) | recovery; 7978c2ecf20Sopenharmony_ci winbond_writecfg(ld_winbond->timing, timing, reg); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* Load the setup timing */ 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci reg = 0x35; 8028c2ecf20Sopenharmony_ci if (adev->class != ATA_DEV_ATA) 8038c2ecf20Sopenharmony_ci reg |= 0x08; /* FIFO off */ 8048c2ecf20Sopenharmony_ci if (!ata_pio_need_iordy(adev)) 8058c2ecf20Sopenharmony_ci reg |= 0x02; /* IORDY off */ 8068c2ecf20Sopenharmony_ci reg |= (clamp_val(t.setup, 0, 3) << 6); 8078c2ecf20Sopenharmony_ci winbond_writecfg(ld_winbond->timing, timing + 1, reg); 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic int winbond_port(struct platform_device *dev, 8118c2ecf20Sopenharmony_ci struct legacy_probe *lp, struct legacy_data *ld) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci if (devm_request_region(&dev->dev, lp->private, 4, "winbond") == NULL) 8148c2ecf20Sopenharmony_ci return -EBUSY; 8158c2ecf20Sopenharmony_ci ld->timing = lp->private; 8168c2ecf20Sopenharmony_ci return 0; 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic struct ata_port_operations winbond_port_ops = { 8208c2ecf20Sopenharmony_ci .inherits = &legacy_base_port_ops, 8218c2ecf20Sopenharmony_ci .set_piomode = winbond_set_piomode, 8228c2ecf20Sopenharmony_ci .sff_data_xfer = vlb32_data_xfer, 8238c2ecf20Sopenharmony_ci}; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic struct legacy_controller controllers[] = { 8268c2ecf20Sopenharmony_ci {"BIOS", &legacy_port_ops, ATA_PIO4, 8278c2ecf20Sopenharmony_ci ATA_FLAG_NO_IORDY, 0, NULL }, 8288c2ecf20Sopenharmony_ci {"Snooping", &simple_port_ops, ATA_PIO4, 8298c2ecf20Sopenharmony_ci 0, 0, NULL }, 8308c2ecf20Sopenharmony_ci {"PDC20230", &pdc20230_port_ops, ATA_PIO2, 8318c2ecf20Sopenharmony_ci ATA_FLAG_NO_IORDY, 8328c2ecf20Sopenharmony_ci ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, NULL }, 8338c2ecf20Sopenharmony_ci {"HT6560A", &ht6560a_port_ops, ATA_PIO2, 8348c2ecf20Sopenharmony_ci ATA_FLAG_NO_IORDY, 0, NULL }, 8358c2ecf20Sopenharmony_ci {"HT6560B", &ht6560b_port_ops, ATA_PIO4, 8368c2ecf20Sopenharmony_ci ATA_FLAG_NO_IORDY, 0, NULL }, 8378c2ecf20Sopenharmony_ci {"OPTI82C611A", &opti82c611a_port_ops, ATA_PIO3, 8388c2ecf20Sopenharmony_ci 0, 0, NULL }, 8398c2ecf20Sopenharmony_ci {"OPTI82C46X", &opti82c46x_port_ops, ATA_PIO3, 8408c2ecf20Sopenharmony_ci 0, 0, NULL }, 8418c2ecf20Sopenharmony_ci {"QDI6500", &qdi6500_port_ops, ATA_PIO2, 8428c2ecf20Sopenharmony_ci ATA_FLAG_NO_IORDY, 8438c2ecf20Sopenharmony_ci ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, 8448c2ecf20Sopenharmony_ci {"QDI6580", &qdi6580_port_ops, ATA_PIO4, 8458c2ecf20Sopenharmony_ci 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, 8468c2ecf20Sopenharmony_ci {"QDI6580DP", &qdi6580dp_port_ops, ATA_PIO4, 8478c2ecf20Sopenharmony_ci 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, 8488c2ecf20Sopenharmony_ci {"W83759A", &winbond_port_ops, ATA_PIO4, 8498c2ecf20Sopenharmony_ci 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, 8508c2ecf20Sopenharmony_ci winbond_port } 8518c2ecf20Sopenharmony_ci}; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci/** 8548c2ecf20Sopenharmony_ci * probe_chip_type - Discover controller 8558c2ecf20Sopenharmony_ci * @probe: Probe entry to check 8568c2ecf20Sopenharmony_ci * 8578c2ecf20Sopenharmony_ci * Probe an ATA port and identify the type of controller. We don't 8588c2ecf20Sopenharmony_ci * check if the controller appears to be driveless at this point. 8598c2ecf20Sopenharmony_ci */ 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic __init int probe_chip_type(struct legacy_probe *probe) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci int mask = 1 << probe->slot; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (winbond && (probe->port == 0x1F0 || probe->port == 0x170)) { 8668c2ecf20Sopenharmony_ci u8 reg = winbond_readcfg(winbond, 0x81); 8678c2ecf20Sopenharmony_ci reg |= 0x80; /* jumpered mode off */ 8688c2ecf20Sopenharmony_ci winbond_writecfg(winbond, 0x81, reg); 8698c2ecf20Sopenharmony_ci reg = winbond_readcfg(winbond, 0x83); 8708c2ecf20Sopenharmony_ci reg |= 0xF0; /* local control */ 8718c2ecf20Sopenharmony_ci winbond_writecfg(winbond, 0x83, reg); 8728c2ecf20Sopenharmony_ci reg = winbond_readcfg(winbond, 0x85); 8738c2ecf20Sopenharmony_ci reg |= 0xF0; /* programmable timing */ 8748c2ecf20Sopenharmony_ci winbond_writecfg(winbond, 0x85, reg); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci reg = winbond_readcfg(winbond, 0x81); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (reg & mask) 8798c2ecf20Sopenharmony_ci return W83759A; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci if (probe->port == 0x1F0) { 8828c2ecf20Sopenharmony_ci unsigned long flags; 8838c2ecf20Sopenharmony_ci local_irq_save(flags); 8848c2ecf20Sopenharmony_ci /* Probes */ 8858c2ecf20Sopenharmony_ci outb(inb(0x1F2) | 0x80, 0x1F2); 8868c2ecf20Sopenharmony_ci inb(0x1F5); 8878c2ecf20Sopenharmony_ci inb(0x1F2); 8888c2ecf20Sopenharmony_ci inb(0x3F6); 8898c2ecf20Sopenharmony_ci inb(0x3F6); 8908c2ecf20Sopenharmony_ci inb(0x1F2); 8918c2ecf20Sopenharmony_ci inb(0x1F2); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if ((inb(0x1F2) & 0x80) == 0) { 8948c2ecf20Sopenharmony_ci /* PDC20230c or 20630 ? */ 8958c2ecf20Sopenharmony_ci printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller" 8968c2ecf20Sopenharmony_ci " detected.\n"); 8978c2ecf20Sopenharmony_ci udelay(100); 8988c2ecf20Sopenharmony_ci inb(0x1F5); 8998c2ecf20Sopenharmony_ci local_irq_restore(flags); 9008c2ecf20Sopenharmony_ci return PDC20230; 9018c2ecf20Sopenharmony_ci } else { 9028c2ecf20Sopenharmony_ci outb(0x55, 0x1F2); 9038c2ecf20Sopenharmony_ci inb(0x1F2); 9048c2ecf20Sopenharmony_ci inb(0x1F2); 9058c2ecf20Sopenharmony_ci if (inb(0x1F2) == 0x00) 9068c2ecf20Sopenharmony_ci printk(KERN_INFO "PDC20230-B VLB ATA " 9078c2ecf20Sopenharmony_ci "controller detected.\n"); 9088c2ecf20Sopenharmony_ci local_irq_restore(flags); 9098c2ecf20Sopenharmony_ci return BIOS; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (ht6560a & mask) 9148c2ecf20Sopenharmony_ci return HT6560A; 9158c2ecf20Sopenharmony_ci if (ht6560b & mask) 9168c2ecf20Sopenharmony_ci return HT6560B; 9178c2ecf20Sopenharmony_ci if (opti82c611a & mask) 9188c2ecf20Sopenharmony_ci return OPTI611A; 9198c2ecf20Sopenharmony_ci if (opti82c46x & mask) 9208c2ecf20Sopenharmony_ci return OPTI46X; 9218c2ecf20Sopenharmony_ci if (autospeed & mask) 9228c2ecf20Sopenharmony_ci return SNOOP; 9238c2ecf20Sopenharmony_ci return BIOS; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci/** 9288c2ecf20Sopenharmony_ci * legacy_init_one - attach a legacy interface 9298c2ecf20Sopenharmony_ci * @pl: probe record 9308c2ecf20Sopenharmony_ci * 9318c2ecf20Sopenharmony_ci * Register an ISA bus IDE interface. Such interfaces are PIO and we 9328c2ecf20Sopenharmony_ci * assume do not support IRQ sharing. 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic __init int legacy_init_one(struct legacy_probe *probe) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct legacy_controller *controller = &controllers[probe->type]; 9388c2ecf20Sopenharmony_ci int pio_modes = controller->pio_mask; 9398c2ecf20Sopenharmony_ci unsigned long io = probe->port; 9408c2ecf20Sopenharmony_ci u32 mask = (1 << probe->slot); 9418c2ecf20Sopenharmony_ci struct ata_port_operations *ops = controller->ops; 9428c2ecf20Sopenharmony_ci struct legacy_data *ld = &legacy_data[probe->slot]; 9438c2ecf20Sopenharmony_ci struct ata_host *host = NULL; 9448c2ecf20Sopenharmony_ci struct ata_port *ap; 9458c2ecf20Sopenharmony_ci struct platform_device *pdev; 9468c2ecf20Sopenharmony_ci struct ata_device *dev; 9478c2ecf20Sopenharmony_ci void __iomem *io_addr, *ctrl_addr; 9488c2ecf20Sopenharmony_ci u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY; 9498c2ecf20Sopenharmony_ci int ret; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci iordy |= controller->flags; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci pdev = platform_device_register_simple(DRV_NAME, probe->slot, NULL, 0); 9548c2ecf20Sopenharmony_ci if (IS_ERR(pdev)) 9558c2ecf20Sopenharmony_ci return PTR_ERR(pdev); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci ret = -EBUSY; 9588c2ecf20Sopenharmony_ci if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL || 9598c2ecf20Sopenharmony_ci devm_request_region(&pdev->dev, io + 0x0206, 1, 9608c2ecf20Sopenharmony_ci "pata_legacy") == NULL) 9618c2ecf20Sopenharmony_ci goto fail; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci ret = -ENOMEM; 9648c2ecf20Sopenharmony_ci io_addr = devm_ioport_map(&pdev->dev, io, 8); 9658c2ecf20Sopenharmony_ci ctrl_addr = devm_ioport_map(&pdev->dev, io + 0x0206, 1); 9668c2ecf20Sopenharmony_ci if (!io_addr || !ctrl_addr) 9678c2ecf20Sopenharmony_ci goto fail; 9688c2ecf20Sopenharmony_ci ld->type = probe->type; 9698c2ecf20Sopenharmony_ci if (controller->setup) 9708c2ecf20Sopenharmony_ci if (controller->setup(pdev, probe, ld) < 0) 9718c2ecf20Sopenharmony_ci goto fail; 9728c2ecf20Sopenharmony_ci host = ata_host_alloc(&pdev->dev, 1); 9738c2ecf20Sopenharmony_ci if (!host) 9748c2ecf20Sopenharmony_ci goto fail; 9758c2ecf20Sopenharmony_ci ap = host->ports[0]; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci ap->ops = ops; 9788c2ecf20Sopenharmony_ci ap->pio_mask = pio_modes; 9798c2ecf20Sopenharmony_ci ap->flags |= ATA_FLAG_SLAVE_POSS | iordy; 9808c2ecf20Sopenharmony_ci ap->pflags |= controller->pflags; 9818c2ecf20Sopenharmony_ci ap->ioaddr.cmd_addr = io_addr; 9828c2ecf20Sopenharmony_ci ap->ioaddr.altstatus_addr = ctrl_addr; 9838c2ecf20Sopenharmony_ci ap->ioaddr.ctl_addr = ctrl_addr; 9848c2ecf20Sopenharmony_ci ata_sff_std_ports(&ap->ioaddr); 9858c2ecf20Sopenharmony_ci ap->host->private_data = ld; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, io + 0x0206); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci ret = ata_host_activate(host, probe->irq, ata_sff_interrupt, 0, 9908c2ecf20Sopenharmony_ci &legacy_sht); 9918c2ecf20Sopenharmony_ci if (ret) 9928c2ecf20Sopenharmony_ci goto fail; 9938c2ecf20Sopenharmony_ci async_synchronize_full(); 9948c2ecf20Sopenharmony_ci ld->platform_dev = pdev; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* Nothing found means we drop the port as its probably not there */ 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci ret = -ENODEV; 9998c2ecf20Sopenharmony_ci ata_for_each_dev(dev, &ap->link, ALL) { 10008c2ecf20Sopenharmony_ci if (!ata_dev_absent(dev)) { 10018c2ecf20Sopenharmony_ci legacy_host[probe->slot] = host; 10028c2ecf20Sopenharmony_ci ld->platform_dev = pdev; 10038c2ecf20Sopenharmony_ci return 0; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci ata_host_detach(host); 10078c2ecf20Sopenharmony_cifail: 10088c2ecf20Sopenharmony_ci platform_device_unregister(pdev); 10098c2ecf20Sopenharmony_ci return ret; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/** 10138c2ecf20Sopenharmony_ci * legacy_check_special_cases - ATA special cases 10148c2ecf20Sopenharmony_ci * @p: PCI device to check 10158c2ecf20Sopenharmony_ci * @master: set this if we find an ATA master 10168c2ecf20Sopenharmony_ci * @master: set this if we find an ATA secondary 10178c2ecf20Sopenharmony_ci * 10188c2ecf20Sopenharmony_ci * A small number of vendors implemented early PCI ATA interfaces 10198c2ecf20Sopenharmony_ci * on bridge logic without the ATA interface being PCI visible. 10208c2ecf20Sopenharmony_ci * Where we have a matching PCI driver we must skip the relevant 10218c2ecf20Sopenharmony_ci * device here. If we don't know about it then the legacy driver 10228c2ecf20Sopenharmony_ci * is the right driver anyway. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic void __init legacy_check_special_cases(struct pci_dev *p, int *primary, 10268c2ecf20Sopenharmony_ci int *secondary) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci /* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */ 10298c2ecf20Sopenharmony_ci if (p->vendor == 0x1078 && p->device == 0x0000) { 10308c2ecf20Sopenharmony_ci *primary = *secondary = 1; 10318c2ecf20Sopenharmony_ci return; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci /* Cyrix CS5520 pre SFF MWDMA ATA on the bridge */ 10348c2ecf20Sopenharmony_ci if (p->vendor == 0x1078 && p->device == 0x0002) { 10358c2ecf20Sopenharmony_ci *primary = *secondary = 1; 10368c2ecf20Sopenharmony_ci return; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci /* Intel MPIIX - PIO ATA on non PCI side of bridge */ 10398c2ecf20Sopenharmony_ci if (p->vendor == 0x8086 && p->device == 0x1234) { 10408c2ecf20Sopenharmony_ci u16 r; 10418c2ecf20Sopenharmony_ci pci_read_config_word(p, 0x6C, &r); 10428c2ecf20Sopenharmony_ci if (r & 0x8000) { 10438c2ecf20Sopenharmony_ci /* ATA port enabled */ 10448c2ecf20Sopenharmony_ci if (r & 0x4000) 10458c2ecf20Sopenharmony_ci *secondary = 1; 10468c2ecf20Sopenharmony_ci else 10478c2ecf20Sopenharmony_ci *primary = 1; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci return; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic __init void probe_opti_vlb(void) 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci /* If an OPTI 82C46X is present find out where the channels are */ 10568c2ecf20Sopenharmony_ci static const char *optis[4] = { 10578c2ecf20Sopenharmony_ci "3/463MV", "5MV", 10588c2ecf20Sopenharmony_ci "5MVA", "5MVB" 10598c2ecf20Sopenharmony_ci }; 10608c2ecf20Sopenharmony_ci u8 chans = 1; 10618c2ecf20Sopenharmony_ci u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci opti82c46x = 3; /* Assume master and slave first */ 10648c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", 10658c2ecf20Sopenharmony_ci optis[ctrl]); 10668c2ecf20Sopenharmony_ci if (ctrl == 3) 10678c2ecf20Sopenharmony_ci chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1; 10688c2ecf20Sopenharmony_ci ctrl = opti_syscfg(0xAC); 10698c2ecf20Sopenharmony_ci /* Check enabled and this port is the 465MV port. On the 10708c2ecf20Sopenharmony_ci MVB we may have two channels */ 10718c2ecf20Sopenharmony_ci if (ctrl & 8) { 10728c2ecf20Sopenharmony_ci if (chans == 2) { 10738c2ecf20Sopenharmony_ci legacy_probe_add(0x1F0, 14, OPTI46X, 0); 10748c2ecf20Sopenharmony_ci legacy_probe_add(0x170, 15, OPTI46X, 0); 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci if (ctrl & 4) 10778c2ecf20Sopenharmony_ci legacy_probe_add(0x170, 15, OPTI46X, 0); 10788c2ecf20Sopenharmony_ci else 10798c2ecf20Sopenharmony_ci legacy_probe_add(0x1F0, 14, OPTI46X, 0); 10808c2ecf20Sopenharmony_ci } else 10818c2ecf20Sopenharmony_ci legacy_probe_add(0x1F0, 14, OPTI46X, 0); 10828c2ecf20Sopenharmony_ci} 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic __init void qdi65_identify_port(u8 r, u8 res, unsigned long port) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci static const unsigned long ide_port[2] = { 0x170, 0x1F0 }; 10878c2ecf20Sopenharmony_ci /* Check card type */ 10888c2ecf20Sopenharmony_ci if ((r & 0xF0) == 0xC0) { 10898c2ecf20Sopenharmony_ci /* QD6500: single channel */ 10908c2ecf20Sopenharmony_ci if (r & 8) 10918c2ecf20Sopenharmony_ci /* Disabled ? */ 10928c2ecf20Sopenharmony_ci return; 10938c2ecf20Sopenharmony_ci legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), 10948c2ecf20Sopenharmony_ci QDI6500, port); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) { 10978c2ecf20Sopenharmony_ci /* QD6580: dual channel */ 10988c2ecf20Sopenharmony_ci if (!request_region(port + 2 , 2, "pata_qdi")) { 10998c2ecf20Sopenharmony_ci release_region(port, 2); 11008c2ecf20Sopenharmony_ci return; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci res = inb(port + 3); 11038c2ecf20Sopenharmony_ci /* Single channel mode ? */ 11048c2ecf20Sopenharmony_ci if (res & 1) 11058c2ecf20Sopenharmony_ci legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), 11068c2ecf20Sopenharmony_ci QDI6580, port); 11078c2ecf20Sopenharmony_ci else { /* Dual channel mode */ 11088c2ecf20Sopenharmony_ci legacy_probe_add(0x1F0, 14, QDI6580DP, port); 11098c2ecf20Sopenharmony_ci /* port + 0x02, r & 0x04 */ 11108c2ecf20Sopenharmony_ci legacy_probe_add(0x170, 15, QDI6580DP, port + 2); 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci release_region(port + 2, 2); 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic __init void probe_qdi_vlb(void) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci unsigned long flags; 11198c2ecf20Sopenharmony_ci static const unsigned long qd_port[2] = { 0x30, 0xB0 }; 11208c2ecf20Sopenharmony_ci int i; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* 11238c2ecf20Sopenharmony_ci * Check each possible QD65xx base address 11248c2ecf20Sopenharmony_ci */ 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 11278c2ecf20Sopenharmony_ci unsigned long port = qd_port[i]; 11288c2ecf20Sopenharmony_ci u8 r, res; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (request_region(port, 2, "pata_qdi")) { 11328c2ecf20Sopenharmony_ci /* Check for a card */ 11338c2ecf20Sopenharmony_ci local_irq_save(flags); 11348c2ecf20Sopenharmony_ci /* I have no h/w that needs this delay but it 11358c2ecf20Sopenharmony_ci is present in the historic code */ 11368c2ecf20Sopenharmony_ci r = inb(port); 11378c2ecf20Sopenharmony_ci udelay(1); 11388c2ecf20Sopenharmony_ci outb(0x19, port); 11398c2ecf20Sopenharmony_ci udelay(1); 11408c2ecf20Sopenharmony_ci res = inb(port); 11418c2ecf20Sopenharmony_ci udelay(1); 11428c2ecf20Sopenharmony_ci outb(r, port); 11438c2ecf20Sopenharmony_ci udelay(1); 11448c2ecf20Sopenharmony_ci local_irq_restore(flags); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci /* Fail */ 11478c2ecf20Sopenharmony_ci if (res == 0x19) { 11488c2ecf20Sopenharmony_ci release_region(port, 2); 11498c2ecf20Sopenharmony_ci continue; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci /* Passes the presence test */ 11528c2ecf20Sopenharmony_ci r = inb(port + 1); 11538c2ecf20Sopenharmony_ci udelay(1); 11548c2ecf20Sopenharmony_ci /* Check port agrees with port set */ 11558c2ecf20Sopenharmony_ci if ((r & 2) >> 1 == i) 11568c2ecf20Sopenharmony_ci qdi65_identify_port(r, res, port); 11578c2ecf20Sopenharmony_ci release_region(port, 2); 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci/** 11638c2ecf20Sopenharmony_ci * legacy_init - attach legacy interfaces 11648c2ecf20Sopenharmony_ci * 11658c2ecf20Sopenharmony_ci * Attach legacy IDE interfaces by scanning the usual IRQ/port suspects. 11668c2ecf20Sopenharmony_ci * Right now we do not scan the ide0 and ide1 address but should do so 11678c2ecf20Sopenharmony_ci * for non PCI systems or systems with no PCI IDE legacy mode devices. 11688c2ecf20Sopenharmony_ci * If you fix that note there are special cases to consider like VLB 11698c2ecf20Sopenharmony_ci * drivers and CS5510/20. 11708c2ecf20Sopenharmony_ci */ 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic __init int legacy_init(void) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci int i; 11758c2ecf20Sopenharmony_ci int ct = 0; 11768c2ecf20Sopenharmony_ci int primary = 0; 11778c2ecf20Sopenharmony_ci int secondary = 0; 11788c2ecf20Sopenharmony_ci int pci_present = 0; 11798c2ecf20Sopenharmony_ci struct legacy_probe *pl = &probe_list[0]; 11808c2ecf20Sopenharmony_ci int slot = 0; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci struct pci_dev *p = NULL; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci for_each_pci_dev(p) { 11858c2ecf20Sopenharmony_ci int r; 11868c2ecf20Sopenharmony_ci /* Check for any overlap of the system ATA mappings. Native 11878c2ecf20Sopenharmony_ci mode controllers stuck on these addresses or some devices 11888c2ecf20Sopenharmony_ci in 'raid' mode won't be found by the storage class test */ 11898c2ecf20Sopenharmony_ci for (r = 0; r < 6; r++) { 11908c2ecf20Sopenharmony_ci if (pci_resource_start(p, r) == 0x1f0) 11918c2ecf20Sopenharmony_ci primary = 1; 11928c2ecf20Sopenharmony_ci if (pci_resource_start(p, r) == 0x170) 11938c2ecf20Sopenharmony_ci secondary = 1; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci /* Check for special cases */ 11968c2ecf20Sopenharmony_ci legacy_check_special_cases(p, &primary, &secondary); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci /* If PCI bus is present then don't probe for tertiary 11998c2ecf20Sopenharmony_ci legacy ports */ 12008c2ecf20Sopenharmony_ci pci_present = 1; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (winbond == 1) 12048c2ecf20Sopenharmony_ci winbond = 0x130; /* Default port, alt is 1B0 */ 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (primary == 0 || all) 12078c2ecf20Sopenharmony_ci legacy_probe_add(0x1F0, 14, UNKNOWN, 0); 12088c2ecf20Sopenharmony_ci if (secondary == 0 || all) 12098c2ecf20Sopenharmony_ci legacy_probe_add(0x170, 15, UNKNOWN, 0); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (probe_all || !pci_present) { 12128c2ecf20Sopenharmony_ci /* ISA/VLB extra ports */ 12138c2ecf20Sopenharmony_ci legacy_probe_add(0x1E8, 11, UNKNOWN, 0); 12148c2ecf20Sopenharmony_ci legacy_probe_add(0x168, 10, UNKNOWN, 0); 12158c2ecf20Sopenharmony_ci legacy_probe_add(0x1E0, 8, UNKNOWN, 0); 12168c2ecf20Sopenharmony_ci legacy_probe_add(0x160, 12, UNKNOWN, 0); 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci if (opti82c46x) 12208c2ecf20Sopenharmony_ci probe_opti_vlb(); 12218c2ecf20Sopenharmony_ci if (qdi) 12228c2ecf20Sopenharmony_ci probe_qdi_vlb(); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci for (i = 0; i < NR_HOST; i++, pl++) { 12258c2ecf20Sopenharmony_ci if (pl->port == 0) 12268c2ecf20Sopenharmony_ci continue; 12278c2ecf20Sopenharmony_ci if (pl->type == UNKNOWN) 12288c2ecf20Sopenharmony_ci pl->type = probe_chip_type(pl); 12298c2ecf20Sopenharmony_ci pl->slot = slot++; 12308c2ecf20Sopenharmony_ci if (legacy_init_one(pl) == 0) 12318c2ecf20Sopenharmony_ci ct++; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci if (ct != 0) 12348c2ecf20Sopenharmony_ci return 0; 12358c2ecf20Sopenharmony_ci return -ENODEV; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic __exit void legacy_exit(void) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci int i; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci for (i = 0; i < nr_legacy_host; i++) { 12438c2ecf20Sopenharmony_ci struct legacy_data *ld = &legacy_data[i]; 12448c2ecf20Sopenharmony_ci ata_host_detach(legacy_host[i]); 12458c2ecf20Sopenharmony_ci platform_device_unregister(ld->platform_dev); 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alan Cox"); 12508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("low-level driver for legacy ATA"); 12518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 12528c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 12538c2ecf20Sopenharmony_ciMODULE_ALIAS("pata_qdi"); 12548c2ecf20Sopenharmony_ciMODULE_ALIAS("pata_winbond"); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cimodule_param(probe_all, int, 0); 12578c2ecf20Sopenharmony_cimodule_param(autospeed, int, 0); 12588c2ecf20Sopenharmony_cimodule_param(ht6560a, int, 0); 12598c2ecf20Sopenharmony_cimodule_param(ht6560b, int, 0); 12608c2ecf20Sopenharmony_cimodule_param(opti82c611a, int, 0); 12618c2ecf20Sopenharmony_cimodule_param(opti82c46x, int, 0); 12628c2ecf20Sopenharmony_cimodule_param(qdi, int, 0); 12638c2ecf20Sopenharmony_cimodule_param(winbond, int, 0); 12648c2ecf20Sopenharmony_cimodule_param(pio_mask, int, 0); 12658c2ecf20Sopenharmony_cimodule_param(iordy_mask, int, 0); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_cimodule_init(legacy_init); 12688c2ecf20Sopenharmony_cimodule_exit(legacy_exit); 1269