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