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, ®); 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