18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * pata_sil680.c 	- SIL680 PATA for new ATA layer
38c2ecf20Sopenharmony_ci *			  (C) 2005 Red Hat Inc
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * based upon
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * linux/drivers/ide/pci/siimage.c		Version 1.07	Nov 30, 2003
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
108c2ecf20Sopenharmony_ci * Copyright (C) 2003		Red Hat <alan@redhat.com>
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *  May be copied or modified under the terms of the GNU General Public License
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *  Documentation publicly available.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *	If you have strange problems with nVidia chipset systems please
178c2ecf20Sopenharmony_ci *	see the SI support documentation and update your system BIOS
188c2ecf20Sopenharmony_ci *	if necessary
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * TODO
218c2ecf20Sopenharmony_ci *	If we know all our devices are LBA28 (or LBA28 sized)  we could use
228c2ecf20Sopenharmony_ci *	the command fifo mode.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/kernel.h>
268c2ecf20Sopenharmony_ci#include <linux/module.h>
278c2ecf20Sopenharmony_ci#include <linux/pci.h>
288c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
298c2ecf20Sopenharmony_ci#include <linux/delay.h>
308c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
318c2ecf20Sopenharmony_ci#include <linux/libata.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define DRV_NAME "pata_sil680"
348c2ecf20Sopenharmony_ci#define DRV_VERSION "0.4.9"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define SIL680_MMIO_BAR		5
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/**
398c2ecf20Sopenharmony_ci *	sil680_selreg		-	return register base
408c2ecf20Sopenharmony_ci *	@ap: ATA interface
418c2ecf20Sopenharmony_ci *	@r: config offset
428c2ecf20Sopenharmony_ci *
438c2ecf20Sopenharmony_ci *	Turn a config register offset into the right address in PCI space
448c2ecf20Sopenharmony_ci *	to access the control register in question.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci *	Thankfully this is a configuration operation so isn't performance
478c2ecf20Sopenharmony_ci *	criticial.
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic unsigned long sil680_selreg(struct ata_port *ap, int r)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	unsigned long base = 0xA0 + r;
538c2ecf20Sopenharmony_ci	base += (ap->port_no << 4);
548c2ecf20Sopenharmony_ci	return base;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/**
588c2ecf20Sopenharmony_ci *	sil680_seldev		-	return register base
598c2ecf20Sopenharmony_ci *	@ap: ATA interface
608c2ecf20Sopenharmony_ci *	@r: config offset
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci *	Turn a config register offset into the right address in PCI space
638c2ecf20Sopenharmony_ci *	to access the control register in question including accounting for
648c2ecf20Sopenharmony_ci *	the unit shift.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic unsigned long sil680_seldev(struct ata_port *ap, struct ata_device *adev, int r)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	unsigned long base = 0xA0 + r;
708c2ecf20Sopenharmony_ci	base += (ap->port_no << 4);
718c2ecf20Sopenharmony_ci	base |= adev->devno ? 2 : 0;
728c2ecf20Sopenharmony_ci	return base;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/**
778c2ecf20Sopenharmony_ci *	sil680_cable_detect	-	cable detection
788c2ecf20Sopenharmony_ci *	@ap: ATA port
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci *	Perform cable detection. The SIL680 stores this in PCI config
818c2ecf20Sopenharmony_ci *	space for us.
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic int sil680_cable_detect(struct ata_port *ap)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
878c2ecf20Sopenharmony_ci	unsigned long addr = sil680_selreg(ap, 0);
888c2ecf20Sopenharmony_ci	u8 ata66;
898c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, addr, &ata66);
908c2ecf20Sopenharmony_ci	if (ata66 & 1)
918c2ecf20Sopenharmony_ci		return ATA_CBL_PATA80;
928c2ecf20Sopenharmony_ci	else
938c2ecf20Sopenharmony_ci		return ATA_CBL_PATA40;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/**
978c2ecf20Sopenharmony_ci *	sil680_set_piomode	-	set PIO mode data
988c2ecf20Sopenharmony_ci *	@ap: ATA interface
998c2ecf20Sopenharmony_ci *	@adev: ATA device
1008c2ecf20Sopenharmony_ci *
1018c2ecf20Sopenharmony_ci *	Program the SIL680 registers for PIO mode. Note that the task speed
1028c2ecf20Sopenharmony_ci *	registers are shared between the devices so we must pick the lowest
1038c2ecf20Sopenharmony_ci *	mode for command work.
1048c2ecf20Sopenharmony_ci */
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	static const u16 speed_p[5] = {
1098c2ecf20Sopenharmony_ci		0x328A, 0x2283, 0x1104, 0x10C3, 0x10C1
1108c2ecf20Sopenharmony_ci	};
1118c2ecf20Sopenharmony_ci	static const u16 speed_t[5] = {
1128c2ecf20Sopenharmony_ci		0x328A, 0x2283, 0x1281, 0x10C3, 0x10C1
1138c2ecf20Sopenharmony_ci	};
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	unsigned long tfaddr = sil680_selreg(ap, 0x02);
1168c2ecf20Sopenharmony_ci	unsigned long addr = sil680_seldev(ap, adev, 0x04);
1178c2ecf20Sopenharmony_ci	unsigned long addr_mask = 0x80 + 4 * ap->port_no;
1188c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
1198c2ecf20Sopenharmony_ci	int pio = adev->pio_mode - XFER_PIO_0;
1208c2ecf20Sopenharmony_ci	int lowest_pio = pio;
1218c2ecf20Sopenharmony_ci	int port_shift = 4 * adev->devno;
1228c2ecf20Sopenharmony_ci	u16 reg;
1238c2ecf20Sopenharmony_ci	u8 mode;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	struct ata_device *pair = ata_dev_pair(adev);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (pair != NULL && adev->pio_mode > pair->pio_mode)
1288c2ecf20Sopenharmony_ci		lowest_pio = pair->pio_mode - XFER_PIO_0;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	pci_write_config_word(pdev, addr, speed_p[pio]);
1318c2ecf20Sopenharmony_ci	pci_write_config_word(pdev, tfaddr, speed_t[lowest_pio]);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, tfaddr-2, &reg);
1348c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, addr_mask, &mode);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	reg &= ~0x0200;			/* Clear IORDY */
1378c2ecf20Sopenharmony_ci	mode &= ~(3 << port_shift);	/* Clear IORDY and DMA bits */
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (ata_pio_need_iordy(adev)) {
1408c2ecf20Sopenharmony_ci		reg |= 0x0200;		/* Enable IORDY */
1418c2ecf20Sopenharmony_ci		mode |= 1 << port_shift;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	pci_write_config_word(pdev, tfaddr-2, reg);
1448c2ecf20Sopenharmony_ci	pci_write_config_byte(pdev, addr_mask, mode);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci/**
1488c2ecf20Sopenharmony_ci *	sil680_set_dmamode	-	set DMA mode data
1498c2ecf20Sopenharmony_ci *	@ap: ATA interface
1508c2ecf20Sopenharmony_ci *	@adev: ATA device
1518c2ecf20Sopenharmony_ci *
1528c2ecf20Sopenharmony_ci *	Program the MWDMA/UDMA modes for the sil680 chipset.
1538c2ecf20Sopenharmony_ci *
1548c2ecf20Sopenharmony_ci *	The MWDMA mode values are pulled from a lookup table
1558c2ecf20Sopenharmony_ci *	while the chipset uses mode number for UDMA.
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	static const u8 ultra_table[2][7] = {
1618c2ecf20Sopenharmony_ci		{ 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01, 0xFF },	/* 100MHz */
1628c2ecf20Sopenharmony_ci		{ 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 },	/* 133Mhz */
1638c2ecf20Sopenharmony_ci	};
1648c2ecf20Sopenharmony_ci	static const u16 dma_table[3] = { 0x2208, 0x10C2, 0x10C1 };
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
1678c2ecf20Sopenharmony_ci	unsigned long ma = sil680_seldev(ap, adev, 0x08);
1688c2ecf20Sopenharmony_ci	unsigned long ua = sil680_seldev(ap, adev, 0x0C);
1698c2ecf20Sopenharmony_ci	unsigned long addr_mask = 0x80 + 4 * ap->port_no;
1708c2ecf20Sopenharmony_ci	int port_shift = adev->devno * 4;
1718c2ecf20Sopenharmony_ci	u8 scsc, mode;
1728c2ecf20Sopenharmony_ci	u16 multi, ultra;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, 0x8A, &scsc);
1758c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, addr_mask, &mode);
1768c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, ma, &multi);
1778c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, ua, &ultra);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* Mask timing bits */
1808c2ecf20Sopenharmony_ci	ultra &= ~0x3F;
1818c2ecf20Sopenharmony_ci	mode &= ~(0x03 << port_shift);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* Extract scsc */
1848c2ecf20Sopenharmony_ci	scsc = (scsc & 0x30) ? 1 : 0;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (adev->dma_mode >= XFER_UDMA_0) {
1878c2ecf20Sopenharmony_ci		multi = 0x10C1;
1888c2ecf20Sopenharmony_ci		ultra |= ultra_table[scsc][adev->dma_mode - XFER_UDMA_0];
1898c2ecf20Sopenharmony_ci		mode |= (0x03 << port_shift);
1908c2ecf20Sopenharmony_ci	} else {
1918c2ecf20Sopenharmony_ci		multi = dma_table[adev->dma_mode - XFER_MW_DMA_0];
1928c2ecf20Sopenharmony_ci		mode |= (0x02 << port_shift);
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci	pci_write_config_byte(pdev, addr_mask, mode);
1958c2ecf20Sopenharmony_ci	pci_write_config_word(pdev, ma, multi);
1968c2ecf20Sopenharmony_ci	pci_write_config_word(pdev, ua, ultra);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/**
2008c2ecf20Sopenharmony_ci *	sil680_sff_exec_command - issue ATA command to host controller
2018c2ecf20Sopenharmony_ci *	@ap: port to which command is being issued
2028c2ecf20Sopenharmony_ci *	@tf: ATA taskfile register set
2038c2ecf20Sopenharmony_ci *
2048c2ecf20Sopenharmony_ci *	Issues ATA command, with proper synchronization with interrupt
2058c2ecf20Sopenharmony_ci *	handler / other threads. Use our MMIO space for PCI posting to avoid
2068c2ecf20Sopenharmony_ci *	a hideously slow cycle all the way to the device.
2078c2ecf20Sopenharmony_ci *
2088c2ecf20Sopenharmony_ci *	LOCKING:
2098c2ecf20Sopenharmony_ci *	spin_lock_irqsave(host lock)
2108c2ecf20Sopenharmony_ci */
2118c2ecf20Sopenharmony_cistatic void sil680_sff_exec_command(struct ata_port *ap,
2128c2ecf20Sopenharmony_ci				    const struct ata_taskfile *tf)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
2158c2ecf20Sopenharmony_ci	iowrite8(tf->command, ap->ioaddr.command_addr);
2168c2ecf20Sopenharmony_ci	ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic bool sil680_sff_irq_check(struct ata_port *ap)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct pci_dev *pdev	= to_pci_dev(ap->host->dev);
2228c2ecf20Sopenharmony_ci	unsigned long addr	= sil680_selreg(ap, 1);
2238c2ecf20Sopenharmony_ci	u8 val;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, addr, &val);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return val & 0x08;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic struct scsi_host_template sil680_sht = {
2318c2ecf20Sopenharmony_ci	ATA_BMDMA_SHT(DRV_NAME),
2328c2ecf20Sopenharmony_ci};
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic struct ata_port_operations sil680_port_ops = {
2368c2ecf20Sopenharmony_ci	.inherits		= &ata_bmdma32_port_ops,
2378c2ecf20Sopenharmony_ci	.sff_exec_command	= sil680_sff_exec_command,
2388c2ecf20Sopenharmony_ci	.sff_irq_check		= sil680_sff_irq_check,
2398c2ecf20Sopenharmony_ci	.cable_detect		= sil680_cable_detect,
2408c2ecf20Sopenharmony_ci	.set_piomode		= sil680_set_piomode,
2418c2ecf20Sopenharmony_ci	.set_dmamode		= sil680_set_dmamode,
2428c2ecf20Sopenharmony_ci};
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci/**
2458c2ecf20Sopenharmony_ci *	sil680_init_chip		-	chip setup
2468c2ecf20Sopenharmony_ci *	@pdev: PCI device
2478c2ecf20Sopenharmony_ci *
2488c2ecf20Sopenharmony_ci *	Perform all the chip setup which must be done both when the device
2498c2ecf20Sopenharmony_ci *	is powered up on boot and when we resume in case we resumed from RAM.
2508c2ecf20Sopenharmony_ci *	Returns the final clock settings.
2518c2ecf20Sopenharmony_ci */
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	u8 tmpbyte	= 0;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/* FIXME: double check */
2588c2ecf20Sopenharmony_ci	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
2598c2ecf20Sopenharmony_ci			      pdev->revision ? 1 : 255);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	pci_write_config_byte(pdev, 0x80, 0x00);
2628c2ecf20Sopenharmony_ci	pci_write_config_byte(pdev, 0x84, 0x00);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, 0x8A, &tmpbyte);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n",
2678c2ecf20Sopenharmony_ci		tmpbyte & 1, tmpbyte & 0x30);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	*try_mmio = 0;
2708c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
2718c2ecf20Sopenharmony_ci	if (machine_is(cell))
2728c2ecf20Sopenharmony_ci		*try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5);
2738c2ecf20Sopenharmony_ci#endif
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	switch (tmpbyte & 0x30) {
2768c2ecf20Sopenharmony_ci	case 0x00:
2778c2ecf20Sopenharmony_ci		/* 133 clock attempt to force it on */
2788c2ecf20Sopenharmony_ci		pci_write_config_byte(pdev, 0x8A, tmpbyte|0x10);
2798c2ecf20Sopenharmony_ci		break;
2808c2ecf20Sopenharmony_ci	case 0x30:
2818c2ecf20Sopenharmony_ci		/* if clocking is disabled */
2828c2ecf20Sopenharmony_ci		/* 133 clock attempt to force it on */
2838c2ecf20Sopenharmony_ci		pci_write_config_byte(pdev, 0x8A, tmpbyte & ~0x20);
2848c2ecf20Sopenharmony_ci		break;
2858c2ecf20Sopenharmony_ci	case 0x10:
2868c2ecf20Sopenharmony_ci		/* 133 already */
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci	case 0x20:
2898c2ecf20Sopenharmony_ci		/* BIOS set PCI x2 clocking */
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev,   0x8A, &tmpbyte);
2948c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n",
2958c2ecf20Sopenharmony_ci		tmpbyte & 1, tmpbyte & 0x30);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	pci_write_config_byte(pdev,  0xA1, 0x72);
2988c2ecf20Sopenharmony_ci	pci_write_config_word(pdev,  0xA2, 0x328A);
2998c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, 0xA4, 0x62DD62DD);
3008c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, 0xA8, 0x43924392);
3018c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, 0xAC, 0x40094009);
3028c2ecf20Sopenharmony_ci	pci_write_config_byte(pdev,  0xB1, 0x72);
3038c2ecf20Sopenharmony_ci	pci_write_config_word(pdev,  0xB2, 0x328A);
3048c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, 0xB4, 0x62DD62DD);
3058c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, 0xB8, 0x43924392);
3068c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, 0xBC, 0x40094009);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	switch (tmpbyte & 0x30) {
3098c2ecf20Sopenharmony_ci	case 0x00:
3108c2ecf20Sopenharmony_ci		printk(KERN_INFO "sil680: 100MHz clock.\n");
3118c2ecf20Sopenharmony_ci		break;
3128c2ecf20Sopenharmony_ci	case 0x10:
3138c2ecf20Sopenharmony_ci		printk(KERN_INFO "sil680: 133MHz clock.\n");
3148c2ecf20Sopenharmony_ci		break;
3158c2ecf20Sopenharmony_ci	case 0x20:
3168c2ecf20Sopenharmony_ci		printk(KERN_INFO "sil680: Using PCI clock.\n");
3178c2ecf20Sopenharmony_ci		break;
3188c2ecf20Sopenharmony_ci	/* This last case is _NOT_ ok */
3198c2ecf20Sopenharmony_ci	case 0x30:
3208c2ecf20Sopenharmony_ci		printk(KERN_ERR "sil680: Clock disabled ?\n");
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	return tmpbyte & 0x30;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	static const struct ata_port_info info = {
3288c2ecf20Sopenharmony_ci		.flags = ATA_FLAG_SLAVE_POSS,
3298c2ecf20Sopenharmony_ci		.pio_mask = ATA_PIO4,
3308c2ecf20Sopenharmony_ci		.mwdma_mask = ATA_MWDMA2,
3318c2ecf20Sopenharmony_ci		.udma_mask = ATA_UDMA6,
3328c2ecf20Sopenharmony_ci		.port_ops = &sil680_port_ops
3338c2ecf20Sopenharmony_ci	};
3348c2ecf20Sopenharmony_ci	static const struct ata_port_info info_slow = {
3358c2ecf20Sopenharmony_ci		.flags = ATA_FLAG_SLAVE_POSS,
3368c2ecf20Sopenharmony_ci		.pio_mask = ATA_PIO4,
3378c2ecf20Sopenharmony_ci		.mwdma_mask = ATA_MWDMA2,
3388c2ecf20Sopenharmony_ci		.udma_mask = ATA_UDMA5,
3398c2ecf20Sopenharmony_ci		.port_ops = &sil680_port_ops
3408c2ecf20Sopenharmony_ci	};
3418c2ecf20Sopenharmony_ci	const struct ata_port_info *ppi[] = { &info, NULL };
3428c2ecf20Sopenharmony_ci	struct ata_host *host;
3438c2ecf20Sopenharmony_ci	void __iomem *mmio_base;
3448c2ecf20Sopenharmony_ci	int rc, try_mmio;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	ata_print_version_once(&pdev->dev, DRV_VERSION);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	rc = pcim_enable_device(pdev);
3498c2ecf20Sopenharmony_ci	if (rc)
3508c2ecf20Sopenharmony_ci		return rc;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	switch (sil680_init_chip(pdev, &try_mmio)) {
3538c2ecf20Sopenharmony_ci		case 0:
3548c2ecf20Sopenharmony_ci			ppi[0] = &info_slow;
3558c2ecf20Sopenharmony_ci			break;
3568c2ecf20Sopenharmony_ci		case 0x30:
3578c2ecf20Sopenharmony_ci			return -ENODEV;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (!try_mmio)
3618c2ecf20Sopenharmony_ci		goto use_ioports;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* Try to acquire MMIO resources and fallback to PIO if
3648c2ecf20Sopenharmony_ci	 * that fails
3658c2ecf20Sopenharmony_ci	 */
3668c2ecf20Sopenharmony_ci	rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME);
3678c2ecf20Sopenharmony_ci	if (rc)
3688c2ecf20Sopenharmony_ci		goto use_ioports;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* Allocate host and set it up */
3718c2ecf20Sopenharmony_ci	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
3728c2ecf20Sopenharmony_ci	if (!host)
3738c2ecf20Sopenharmony_ci		return -ENOMEM;
3748c2ecf20Sopenharmony_ci	host->iomap = pcim_iomap_table(pdev);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	/* Setup DMA masks */
3778c2ecf20Sopenharmony_ci	rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK);
3788c2ecf20Sopenharmony_ci	if (rc)
3798c2ecf20Sopenharmony_ci		return rc;
3808c2ecf20Sopenharmony_ci	pci_set_master(pdev);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/* Get MMIO base and initialize port addresses */
3838c2ecf20Sopenharmony_ci	mmio_base = host->iomap[SIL680_MMIO_BAR];
3848c2ecf20Sopenharmony_ci	host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x00;
3858c2ecf20Sopenharmony_ci	host->ports[0]->ioaddr.cmd_addr = mmio_base + 0x80;
3868c2ecf20Sopenharmony_ci	host->ports[0]->ioaddr.ctl_addr = mmio_base + 0x8a;
3878c2ecf20Sopenharmony_ci	host->ports[0]->ioaddr.altstatus_addr = mmio_base + 0x8a;
3888c2ecf20Sopenharmony_ci	ata_sff_std_ports(&host->ports[0]->ioaddr);
3898c2ecf20Sopenharmony_ci	host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x08;
3908c2ecf20Sopenharmony_ci	host->ports[1]->ioaddr.cmd_addr = mmio_base + 0xc0;
3918c2ecf20Sopenharmony_ci	host->ports[1]->ioaddr.ctl_addr = mmio_base + 0xca;
3928c2ecf20Sopenharmony_ci	host->ports[1]->ioaddr.altstatus_addr = mmio_base + 0xca;
3938c2ecf20Sopenharmony_ci	ata_sff_std_ports(&host->ports[1]->ioaddr);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	/* Register & activate */
3968c2ecf20Sopenharmony_ci	return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
3978c2ecf20Sopenharmony_ci				 IRQF_SHARED, &sil680_sht);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ciuse_ioports:
4008c2ecf20Sopenharmony_ci	return ata_pci_bmdma_init_one(pdev, ppi, &sil680_sht, NULL, 0);
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
4048c2ecf20Sopenharmony_cistatic int sil680_reinit_one(struct pci_dev *pdev)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct ata_host *host = pci_get_drvdata(pdev);
4078c2ecf20Sopenharmony_ci	int try_mmio, rc;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	rc = ata_pci_device_do_resume(pdev);
4108c2ecf20Sopenharmony_ci	if (rc)
4118c2ecf20Sopenharmony_ci		return rc;
4128c2ecf20Sopenharmony_ci	sil680_init_chip(pdev, &try_mmio);
4138c2ecf20Sopenharmony_ci	ata_host_resume(host);
4148c2ecf20Sopenharmony_ci	return 0;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci#endif
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic const struct pci_device_id sil680[] = {
4198c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), },
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	{ },
4228c2ecf20Sopenharmony_ci};
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic struct pci_driver sil680_pci_driver = {
4258c2ecf20Sopenharmony_ci	.name 		= DRV_NAME,
4268c2ecf20Sopenharmony_ci	.id_table	= sil680,
4278c2ecf20Sopenharmony_ci	.probe 		= sil680_init_one,
4288c2ecf20Sopenharmony_ci	.remove		= ata_pci_remove_one,
4298c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
4308c2ecf20Sopenharmony_ci	.suspend	= ata_pci_device_suspend,
4318c2ecf20Sopenharmony_ci	.resume		= sil680_reinit_one,
4328c2ecf20Sopenharmony_ci#endif
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cimodule_pci_driver(sil680_pci_driver);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alan Cox");
4388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("low-level driver for SI680 PATA");
4398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4408c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, sil680);
4418c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION);
442