1c6fd2807SJeff Garzik /* 2c6fd2807SJeff Garzik * sata_via.c - VIA Serial ATA controllers 3c6fd2807SJeff Garzik * 4c6fd2807SJeff Garzik * Maintained by: Jeff Garzik <jgarzik@pobox.com> 5c6fd2807SJeff Garzik * Please ALWAYS copy linux-ide@vger.kernel.org 6c6fd2807SJeff Garzik on emails. 7c6fd2807SJeff Garzik * 8c6fd2807SJeff Garzik * Copyright 2003-2004 Red Hat, Inc. All rights reserved. 9c6fd2807SJeff Garzik * Copyright 2003-2004 Jeff Garzik 10c6fd2807SJeff Garzik * 11c6fd2807SJeff Garzik * 12c6fd2807SJeff Garzik * This program is free software; you can redistribute it and/or modify 13c6fd2807SJeff Garzik * it under the terms of the GNU General Public License as published by 14c6fd2807SJeff Garzik * the Free Software Foundation; either version 2, or (at your option) 15c6fd2807SJeff Garzik * any later version. 16c6fd2807SJeff Garzik * 17c6fd2807SJeff Garzik * This program is distributed in the hope that it will be useful, 18c6fd2807SJeff Garzik * but WITHOUT ANY WARRANTY; without even the implied warranty of 19c6fd2807SJeff Garzik * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20c6fd2807SJeff Garzik * GNU General Public License for more details. 21c6fd2807SJeff Garzik * 22c6fd2807SJeff Garzik * You should have received a copy of the GNU General Public License 23c6fd2807SJeff Garzik * along with this program; see the file COPYING. If not, write to 24c6fd2807SJeff Garzik * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 25c6fd2807SJeff Garzik * 26c6fd2807SJeff Garzik * 27c6fd2807SJeff Garzik * libata documentation is available via 'make {ps|pdf}docs', 28c6fd2807SJeff Garzik * as Documentation/DocBook/libata.* 29c6fd2807SJeff Garzik * 30c6fd2807SJeff Garzik * Hardware documentation available under NDA. 31c6fd2807SJeff Garzik * 32c6fd2807SJeff Garzik * 33c6fd2807SJeff Garzik * To-do list: 34c6fd2807SJeff Garzik * - VT6421 PATA support 35c6fd2807SJeff Garzik * 36c6fd2807SJeff Garzik */ 37c6fd2807SJeff Garzik 38c6fd2807SJeff Garzik #include <linux/kernel.h> 39c6fd2807SJeff Garzik #include <linux/module.h> 40c6fd2807SJeff Garzik #include <linux/pci.h> 41c6fd2807SJeff Garzik #include <linux/init.h> 42c6fd2807SJeff Garzik #include <linux/blkdev.h> 43c6fd2807SJeff Garzik #include <linux/delay.h> 44c6fd2807SJeff Garzik #include <linux/device.h> 45c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 46c6fd2807SJeff Garzik #include <linux/libata.h> 47c6fd2807SJeff Garzik 48c6fd2807SJeff Garzik #define DRV_NAME "sata_via" 498bc3fc47SJeff Garzik #define DRV_VERSION "2.2" 50c6fd2807SJeff Garzik 51c6fd2807SJeff Garzik enum board_ids_enum { 52c6fd2807SJeff Garzik vt6420, 53c6fd2807SJeff Garzik vt6421, 54c6fd2807SJeff Garzik }; 55c6fd2807SJeff Garzik 56c6fd2807SJeff Garzik enum { 57c6fd2807SJeff Garzik SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ 58c6fd2807SJeff Garzik SATA_INT_GATE = 0x41, /* SATA interrupt gating */ 59c6fd2807SJeff Garzik SATA_NATIVE_MODE = 0x42, /* Native mode enable */ 60c6fd2807SJeff Garzik SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */ 61d73f30e1SAlan PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */ 62d73f30e1SAlan PATA_PIO_TIMING = 0xAB, /* PATA timing register */ 63c6fd2807SJeff Garzik 64c6fd2807SJeff Garzik PORT0 = (1 << 1), 65c6fd2807SJeff Garzik PORT1 = (1 << 0), 66c6fd2807SJeff Garzik ALL_PORTS = PORT0 | PORT1, 67c6fd2807SJeff Garzik 68c6fd2807SJeff Garzik NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), 69c6fd2807SJeff Garzik 70c6fd2807SJeff Garzik SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */ 71c6fd2807SJeff Garzik SATA_2DEV = (1 << 5), /* SATA is master/slave */ 72c6fd2807SJeff Garzik }; 73c6fd2807SJeff Garzik 74c6fd2807SJeff Garzik static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); 75c6fd2807SJeff Garzik static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); 76c6fd2807SJeff Garzik static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); 7717234246STejun Heo static void svia_noop_freeze(struct ata_port *ap); 7854a86bfcSJeff Garzik static void vt6420_error_handler(struct ata_port *ap); 79a0fcdc02SJeff Garzik static int vt6421_pata_cable_detect(struct ata_port *ap); 80d73f30e1SAlan static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev); 81d73f30e1SAlan static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev); 82c6fd2807SJeff Garzik 83c6fd2807SJeff Garzik static const struct pci_device_id svia_pci_tbl[] = { 8496bc103fSLuca Pedrielli { PCI_VDEVICE(VIA, 0x5337), vt6420 }, 852d2744fcSJeff Garzik { PCI_VDEVICE(VIA, 0x0591), vt6420 }, 862d2744fcSJeff Garzik { PCI_VDEVICE(VIA, 0x3149), vt6420 }, 872d2744fcSJeff Garzik { PCI_VDEVICE(VIA, 0x3249), vt6421 }, 88*52df0ee0SJeff Garzik { PCI_VDEVICE(VIA, 0x5287), vt6420 }, 89*52df0ee0SJeff Garzik { PCI_VDEVICE(VIA, 0x5372), vt6420 }, 90*52df0ee0SJeff Garzik { PCI_VDEVICE(VIA, 0x7372), vt6420 }, 91c6fd2807SJeff Garzik 92c6fd2807SJeff Garzik { } /* terminate list */ 93c6fd2807SJeff Garzik }; 94c6fd2807SJeff Garzik 95c6fd2807SJeff Garzik static struct pci_driver svia_pci_driver = { 96c6fd2807SJeff Garzik .name = DRV_NAME, 97c6fd2807SJeff Garzik .id_table = svia_pci_tbl, 98c6fd2807SJeff Garzik .probe = svia_init_one, 99e1e143cfSTejun Heo #ifdef CONFIG_PM 100e1e143cfSTejun Heo .suspend = ata_pci_device_suspend, 101e1e143cfSTejun Heo .resume = ata_pci_device_resume, 102e1e143cfSTejun Heo #endif 103c6fd2807SJeff Garzik .remove = ata_pci_remove_one, 104c6fd2807SJeff Garzik }; 105c6fd2807SJeff Garzik 106c6fd2807SJeff Garzik static struct scsi_host_template svia_sht = { 107c6fd2807SJeff Garzik .module = THIS_MODULE, 108c6fd2807SJeff Garzik .name = DRV_NAME, 109c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 110c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 111c6fd2807SJeff Garzik .can_queue = ATA_DEF_QUEUE, 112c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 113c6fd2807SJeff Garzik .sg_tablesize = LIBATA_MAX_PRD, 114c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 115c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 116c6fd2807SJeff Garzik .use_clustering = ATA_SHT_USE_CLUSTERING, 117c6fd2807SJeff Garzik .proc_name = DRV_NAME, 118c6fd2807SJeff Garzik .dma_boundary = ATA_DMA_BOUNDARY, 119c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 120c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 121c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 122c6fd2807SJeff Garzik }; 123c6fd2807SJeff Garzik 12454a86bfcSJeff Garzik static const struct ata_port_operations vt6420_sata_ops = { 12554a86bfcSJeff Garzik .port_disable = ata_port_disable, 12654a86bfcSJeff Garzik 12754a86bfcSJeff Garzik .tf_load = ata_tf_load, 12854a86bfcSJeff Garzik .tf_read = ata_tf_read, 12954a86bfcSJeff Garzik .check_status = ata_check_status, 13054a86bfcSJeff Garzik .exec_command = ata_exec_command, 13154a86bfcSJeff Garzik .dev_select = ata_std_dev_select, 13254a86bfcSJeff Garzik 13354a86bfcSJeff Garzik .bmdma_setup = ata_bmdma_setup, 13454a86bfcSJeff Garzik .bmdma_start = ata_bmdma_start, 13554a86bfcSJeff Garzik .bmdma_stop = ata_bmdma_stop, 13654a86bfcSJeff Garzik .bmdma_status = ata_bmdma_status, 13754a86bfcSJeff Garzik 13854a86bfcSJeff Garzik .qc_prep = ata_qc_prep, 13954a86bfcSJeff Garzik .qc_issue = ata_qc_issue_prot, 1400d5ff566STejun Heo .data_xfer = ata_data_xfer, 14154a86bfcSJeff Garzik 14217234246STejun Heo .freeze = svia_noop_freeze, 14354a86bfcSJeff Garzik .thaw = ata_bmdma_thaw, 14454a86bfcSJeff Garzik .error_handler = vt6420_error_handler, 14554a86bfcSJeff Garzik .post_internal_cmd = ata_bmdma_post_internal_cmd, 14654a86bfcSJeff Garzik 14754a86bfcSJeff Garzik .irq_clear = ata_bmdma_irq_clear, 148246ce3b6SAkira Iguchi .irq_on = ata_irq_on, 149246ce3b6SAkira Iguchi .irq_ack = ata_irq_ack, 15054a86bfcSJeff Garzik 15154a86bfcSJeff Garzik .port_start = ata_port_start, 15254a86bfcSJeff Garzik }; 15354a86bfcSJeff Garzik 154d73f30e1SAlan static const struct ata_port_operations vt6421_pata_ops = { 155d73f30e1SAlan .port_disable = ata_port_disable, 156d73f30e1SAlan 157d73f30e1SAlan .set_piomode = vt6421_set_pio_mode, 158d73f30e1SAlan .set_dmamode = vt6421_set_dma_mode, 159d73f30e1SAlan 160d73f30e1SAlan .tf_load = ata_tf_load, 161d73f30e1SAlan .tf_read = ata_tf_read, 162d73f30e1SAlan .check_status = ata_check_status, 163d73f30e1SAlan .exec_command = ata_exec_command, 164d73f30e1SAlan .dev_select = ata_std_dev_select, 165d73f30e1SAlan 166d73f30e1SAlan .bmdma_setup = ata_bmdma_setup, 167d73f30e1SAlan .bmdma_start = ata_bmdma_start, 168d73f30e1SAlan .bmdma_stop = ata_bmdma_stop, 169d73f30e1SAlan .bmdma_status = ata_bmdma_status, 170d73f30e1SAlan 171d73f30e1SAlan .qc_prep = ata_qc_prep, 172d73f30e1SAlan .qc_issue = ata_qc_issue_prot, 1730d5ff566STejun Heo .data_xfer = ata_data_xfer, 174d73f30e1SAlan 175d73f30e1SAlan .freeze = ata_bmdma_freeze, 176d73f30e1SAlan .thaw = ata_bmdma_thaw, 177a0fcdc02SJeff Garzik .error_handler = ata_bmdma_error_handler, 178d73f30e1SAlan .post_internal_cmd = ata_bmdma_post_internal_cmd, 179a0fcdc02SJeff Garzik .cable_detect = vt6421_pata_cable_detect, 180d73f30e1SAlan 181d73f30e1SAlan .irq_clear = ata_bmdma_irq_clear, 182246ce3b6SAkira Iguchi .irq_on = ata_irq_on, 183246ce3b6SAkira Iguchi .irq_ack = ata_irq_ack, 184d73f30e1SAlan 185eca25dcaSTejun Heo .port_start = ata_port_start, 186d73f30e1SAlan }; 187d73f30e1SAlan 18854a86bfcSJeff Garzik static const struct ata_port_operations vt6421_sata_ops = { 189c6fd2807SJeff Garzik .port_disable = ata_port_disable, 190c6fd2807SJeff Garzik 191c6fd2807SJeff Garzik .tf_load = ata_tf_load, 192c6fd2807SJeff Garzik .tf_read = ata_tf_read, 193c6fd2807SJeff Garzik .check_status = ata_check_status, 194c6fd2807SJeff Garzik .exec_command = ata_exec_command, 195c6fd2807SJeff Garzik .dev_select = ata_std_dev_select, 196c6fd2807SJeff Garzik 197c6fd2807SJeff Garzik .bmdma_setup = ata_bmdma_setup, 198c6fd2807SJeff Garzik .bmdma_start = ata_bmdma_start, 199c6fd2807SJeff Garzik .bmdma_stop = ata_bmdma_stop, 200c6fd2807SJeff Garzik .bmdma_status = ata_bmdma_status, 201c6fd2807SJeff Garzik 202c6fd2807SJeff Garzik .qc_prep = ata_qc_prep, 203c6fd2807SJeff Garzik .qc_issue = ata_qc_issue_prot, 2040d5ff566STejun Heo .data_xfer = ata_data_xfer, 205c6fd2807SJeff Garzik 206c6fd2807SJeff Garzik .freeze = ata_bmdma_freeze, 207c6fd2807SJeff Garzik .thaw = ata_bmdma_thaw, 208a0fcdc02SJeff Garzik .error_handler = ata_bmdma_error_handler, 209c6fd2807SJeff Garzik .post_internal_cmd = ata_bmdma_post_internal_cmd, 210a0fcdc02SJeff Garzik .cable_detect = ata_cable_sata, 211c6fd2807SJeff Garzik 212c6fd2807SJeff Garzik .irq_clear = ata_bmdma_irq_clear, 213246ce3b6SAkira Iguchi .irq_on = ata_irq_on, 214246ce3b6SAkira Iguchi .irq_ack = ata_irq_ack, 215c6fd2807SJeff Garzik 216c6fd2807SJeff Garzik .scr_read = svia_scr_read, 217c6fd2807SJeff Garzik .scr_write = svia_scr_write, 218c6fd2807SJeff Garzik 219eca25dcaSTejun Heo .port_start = ata_port_start, 220c6fd2807SJeff Garzik }; 221c6fd2807SJeff Garzik 222eca25dcaSTejun Heo static const struct ata_port_info vt6420_port_info = { 223cca3974eSJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, 224c6fd2807SJeff Garzik .pio_mask = 0x1f, 225c6fd2807SJeff Garzik .mwdma_mask = 0x07, 226c6fd2807SJeff Garzik .udma_mask = 0x7f, 22754a86bfcSJeff Garzik .port_ops = &vt6420_sata_ops, 228c6fd2807SJeff Garzik }; 229c6fd2807SJeff Garzik 230eca25dcaSTejun Heo static struct ata_port_info vt6421_sport_info = { 231eca25dcaSTejun Heo .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, 232eca25dcaSTejun Heo .pio_mask = 0x1f, 233eca25dcaSTejun Heo .mwdma_mask = 0x07, 234eca25dcaSTejun Heo .udma_mask = 0x7f, 235eca25dcaSTejun Heo .port_ops = &vt6421_sata_ops, 236eca25dcaSTejun Heo }; 237eca25dcaSTejun Heo 238eca25dcaSTejun Heo static struct ata_port_info vt6421_pport_info = { 239eca25dcaSTejun Heo .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY, 240eca25dcaSTejun Heo .pio_mask = 0x1f, 241eca25dcaSTejun Heo .mwdma_mask = 0, 242eca25dcaSTejun Heo .udma_mask = 0x7f, 243eca25dcaSTejun Heo .port_ops = &vt6421_pata_ops, 244eca25dcaSTejun Heo }; 245eca25dcaSTejun Heo 246c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik"); 247c6fd2807SJeff Garzik MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers"); 248c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 249c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, svia_pci_tbl); 250c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 251c6fd2807SJeff Garzik 252c6fd2807SJeff Garzik static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg) 253c6fd2807SJeff Garzik { 254c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 255c6fd2807SJeff Garzik return 0xffffffffU; 2560d5ff566STejun Heo return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg)); 257c6fd2807SJeff Garzik } 258c6fd2807SJeff Garzik 259c6fd2807SJeff Garzik static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) 260c6fd2807SJeff Garzik { 261c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 262c6fd2807SJeff Garzik return; 2630d5ff566STejun Heo iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg)); 264c6fd2807SJeff Garzik } 265c6fd2807SJeff Garzik 26617234246STejun Heo static void svia_noop_freeze(struct ata_port *ap) 26717234246STejun Heo { 26817234246STejun Heo /* Some VIA controllers choke if ATA_NIEN is manipulated in 26917234246STejun Heo * certain way. Leave it alone and just clear pending IRQ. 27017234246STejun Heo */ 27117234246STejun Heo ata_chk_status(ap); 272d0259872STejun Heo ata_bmdma_irq_clear(ap); 27317234246STejun Heo } 27417234246STejun Heo 27554a86bfcSJeff Garzik /** 27654a86bfcSJeff Garzik * vt6420_prereset - prereset for vt6420 27754a86bfcSJeff Garzik * @ap: target ATA port 278d4b2bab4STejun Heo * @deadline: deadline jiffies for the operation 27954a86bfcSJeff Garzik * 28054a86bfcSJeff Garzik * SCR registers on vt6420 are pieces of shit and may hang the 28154a86bfcSJeff Garzik * whole machine completely if accessed with the wrong timing. 28254a86bfcSJeff Garzik * To avoid such catastrophe, vt6420 doesn't provide generic SCR 28354a86bfcSJeff Garzik * access operations, but uses SStatus and SControl only during 28454a86bfcSJeff Garzik * boot probing in controlled way. 28554a86bfcSJeff Garzik * 28654a86bfcSJeff Garzik * As the old (pre EH update) probing code is proven to work, we 28754a86bfcSJeff Garzik * strictly follow the access pattern. 28854a86bfcSJeff Garzik * 28954a86bfcSJeff Garzik * LOCKING: 29054a86bfcSJeff Garzik * Kernel thread context (may sleep) 29154a86bfcSJeff Garzik * 29254a86bfcSJeff Garzik * RETURNS: 29354a86bfcSJeff Garzik * 0 on success, -errno otherwise. 29454a86bfcSJeff Garzik */ 295d4b2bab4STejun Heo static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) 29654a86bfcSJeff Garzik { 29754a86bfcSJeff Garzik struct ata_eh_context *ehc = &ap->eh_context; 29854a86bfcSJeff Garzik unsigned long timeout = jiffies + (HZ * 5); 29954a86bfcSJeff Garzik u32 sstatus, scontrol; 30054a86bfcSJeff Garzik int online; 30154a86bfcSJeff Garzik 30254a86bfcSJeff Garzik /* don't do any SCR stuff if we're not loading */ 30368ff6e8eSJeff Garzik if (!(ap->pflags & ATA_PFLAG_LOADING)) 30454a86bfcSJeff Garzik goto skip_scr; 30554a86bfcSJeff Garzik 30654a86bfcSJeff Garzik /* Resume phy. This is the old resume sequence from 30754a86bfcSJeff Garzik * __sata_phy_reset(). 30854a86bfcSJeff Garzik */ 30954a86bfcSJeff Garzik svia_scr_write(ap, SCR_CONTROL, 0x300); 31054a86bfcSJeff Garzik svia_scr_read(ap, SCR_CONTROL); /* flush */ 31154a86bfcSJeff Garzik 31254a86bfcSJeff Garzik /* wait for phy to become ready, if necessary */ 31354a86bfcSJeff Garzik do { 31454a86bfcSJeff Garzik msleep(200); 31554a86bfcSJeff Garzik if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1) 31654a86bfcSJeff Garzik break; 31754a86bfcSJeff Garzik } while (time_before(jiffies, timeout)); 31854a86bfcSJeff Garzik 31954a86bfcSJeff Garzik /* open code sata_print_link_status() */ 32054a86bfcSJeff Garzik sstatus = svia_scr_read(ap, SCR_STATUS); 32154a86bfcSJeff Garzik scontrol = svia_scr_read(ap, SCR_CONTROL); 32254a86bfcSJeff Garzik 32354a86bfcSJeff Garzik online = (sstatus & 0xf) == 0x3; 32454a86bfcSJeff Garzik 32554a86bfcSJeff Garzik ata_port_printk(ap, KERN_INFO, 32654a86bfcSJeff Garzik "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n", 32754a86bfcSJeff Garzik online ? "up" : "down", sstatus, scontrol); 32854a86bfcSJeff Garzik 32954a86bfcSJeff Garzik /* SStatus is read one more time */ 33054a86bfcSJeff Garzik svia_scr_read(ap, SCR_STATUS); 33154a86bfcSJeff Garzik 33254a86bfcSJeff Garzik if (!online) { 33354a86bfcSJeff Garzik /* tell EH to bail */ 33454a86bfcSJeff Garzik ehc->i.action &= ~ATA_EH_RESET_MASK; 33554a86bfcSJeff Garzik return 0; 33654a86bfcSJeff Garzik } 33754a86bfcSJeff Garzik 33854a86bfcSJeff Garzik skip_scr: 33954a86bfcSJeff Garzik /* wait for !BSY */ 340d4b2bab4STejun Heo ata_wait_ready(ap, deadline); 34154a86bfcSJeff Garzik 34254a86bfcSJeff Garzik return 0; 34354a86bfcSJeff Garzik } 34454a86bfcSJeff Garzik 34554a86bfcSJeff Garzik static void vt6420_error_handler(struct ata_port *ap) 34654a86bfcSJeff Garzik { 34754a86bfcSJeff Garzik return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset, 34854a86bfcSJeff Garzik NULL, ata_std_postreset); 34954a86bfcSJeff Garzik } 35054a86bfcSJeff Garzik 351a0fcdc02SJeff Garzik static int vt6421_pata_cable_detect(struct ata_port *ap) 352d73f30e1SAlan { 353d73f30e1SAlan struct pci_dev *pdev = to_pci_dev(ap->host->dev); 354d73f30e1SAlan u8 tmp; 355d73f30e1SAlan 356d73f30e1SAlan pci_read_config_byte(pdev, PATA_UDMA_TIMING, &tmp); 357d73f30e1SAlan if (tmp & 0x10) 358a0fcdc02SJeff Garzik return ATA_CBL_PATA40; 359a0fcdc02SJeff Garzik return ATA_CBL_PATA80; 360d73f30e1SAlan } 361d73f30e1SAlan 362d73f30e1SAlan static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev) 363d73f30e1SAlan { 364d73f30e1SAlan struct pci_dev *pdev = to_pci_dev(ap->host->dev); 365d73f30e1SAlan static const u8 pio_bits[] = { 0xA8, 0x65, 0x65, 0x31, 0x20 }; 366d73f30e1SAlan pci_write_config_byte(pdev, PATA_PIO_TIMING, pio_bits[adev->pio_mode - XFER_PIO_0]); 367d73f30e1SAlan } 368d73f30e1SAlan 369d73f30e1SAlan static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev) 370d73f30e1SAlan { 371d73f30e1SAlan struct pci_dev *pdev = to_pci_dev(ap->host->dev); 372d73f30e1SAlan static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 }; 373d73f30e1SAlan pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]); 374d73f30e1SAlan } 375d73f30e1SAlan 376c6fd2807SJeff Garzik static const unsigned int svia_bar_sizes[] = { 377c6fd2807SJeff Garzik 8, 4, 8, 4, 16, 256 378c6fd2807SJeff Garzik }; 379c6fd2807SJeff Garzik 380c6fd2807SJeff Garzik static const unsigned int vt6421_bar_sizes[] = { 381c6fd2807SJeff Garzik 16, 16, 16, 16, 32, 128 382c6fd2807SJeff Garzik }; 383c6fd2807SJeff Garzik 3840d5ff566STejun Heo static void __iomem * svia_scr_addr(void __iomem *addr, unsigned int port) 385c6fd2807SJeff Garzik { 386c6fd2807SJeff Garzik return addr + (port * 128); 387c6fd2807SJeff Garzik } 388c6fd2807SJeff Garzik 3890d5ff566STejun Heo static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port) 390c6fd2807SJeff Garzik { 391c6fd2807SJeff Garzik return addr + (port * 64); 392c6fd2807SJeff Garzik } 393c6fd2807SJeff Garzik 394eca25dcaSTejun Heo static void vt6421_init_addrs(struct ata_port *ap) 395c6fd2807SJeff Garzik { 396eca25dcaSTejun Heo void __iomem * const * iomap = ap->host->iomap; 397eca25dcaSTejun Heo void __iomem *reg_addr = iomap[ap->port_no]; 398eca25dcaSTejun Heo void __iomem *bmdma_addr = iomap[4] + (ap->port_no * 8); 399eca25dcaSTejun Heo struct ata_ioports *ioaddr = &ap->ioaddr; 400c6fd2807SJeff Garzik 401eca25dcaSTejun Heo ioaddr->cmd_addr = reg_addr; 402eca25dcaSTejun Heo ioaddr->altstatus_addr = 403eca25dcaSTejun Heo ioaddr->ctl_addr = (void __iomem *) 4040d5ff566STejun Heo ((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS); 405eca25dcaSTejun Heo ioaddr->bmdma_addr = bmdma_addr; 406eca25dcaSTejun Heo ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no); 407c6fd2807SJeff Garzik 408eca25dcaSTejun Heo ata_std_ports(ioaddr); 409c6fd2807SJeff Garzik } 410c6fd2807SJeff Garzik 411eca25dcaSTejun Heo static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) 412c6fd2807SJeff Garzik { 413eca25dcaSTejun Heo const struct ata_port_info *ppi[] = { &vt6420_port_info, NULL }; 414eca25dcaSTejun Heo struct ata_host *host; 415eca25dcaSTejun Heo int rc; 416c6fd2807SJeff Garzik 4171626aeb8STejun Heo rc = ata_pci_prepare_native_host(pdev, ppi, &host); 418eca25dcaSTejun Heo if (rc) 419eca25dcaSTejun Heo return rc; 420eca25dcaSTejun Heo *r_host = host; 421c6fd2807SJeff Garzik 422eca25dcaSTejun Heo rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME); 423eca25dcaSTejun Heo if (rc) { 424e1be5d73STejun Heo dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n"); 425eca25dcaSTejun Heo return rc; 426e1be5d73STejun Heo } 427e1be5d73STejun Heo 428eca25dcaSTejun Heo host->ports[0]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 0); 429eca25dcaSTejun Heo host->ports[1]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 1); 430c6fd2807SJeff Garzik 431eca25dcaSTejun Heo return 0; 432c6fd2807SJeff Garzik } 433c6fd2807SJeff Garzik 434eca25dcaSTejun Heo static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) 435c6fd2807SJeff Garzik { 436eca25dcaSTejun Heo const struct ata_port_info *ppi[] = 437eca25dcaSTejun Heo { &vt6421_sport_info, &vt6421_sport_info, &vt6421_pport_info }; 438eca25dcaSTejun Heo struct ata_host *host; 439eca25dcaSTejun Heo int i, rc; 440c6fd2807SJeff Garzik 441eca25dcaSTejun Heo *r_host = host = ata_host_alloc_pinfo(&pdev->dev, ppi, ARRAY_SIZE(ppi)); 442eca25dcaSTejun Heo if (!host) { 443eca25dcaSTejun Heo dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n"); 444eca25dcaSTejun Heo return -ENOMEM; 445e1be5d73STejun Heo } 446e1be5d73STejun Heo 4478fd7d1b1STejun Heo rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME); 448eca25dcaSTejun Heo if (rc) { 449eca25dcaSTejun Heo dev_printk(KERN_ERR, &pdev->dev, "failed to request/iomap " 450eca25dcaSTejun Heo "PCI BARs (errno=%d)\n", rc); 451eca25dcaSTejun Heo return rc; 452eca25dcaSTejun Heo } 453eca25dcaSTejun Heo host->iomap = pcim_iomap_table(pdev); 454c6fd2807SJeff Garzik 455eca25dcaSTejun Heo for (i = 0; i < host->n_ports; i++) 456eca25dcaSTejun Heo vt6421_init_addrs(host->ports[i]); 457eca25dcaSTejun Heo 458eca25dcaSTejun Heo rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); 459eca25dcaSTejun Heo if (rc) 460eca25dcaSTejun Heo return rc; 461eca25dcaSTejun Heo rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); 462eca25dcaSTejun Heo if (rc) 463eca25dcaSTejun Heo return rc; 464eca25dcaSTejun Heo 465eca25dcaSTejun Heo return 0; 466c6fd2807SJeff Garzik } 467c6fd2807SJeff Garzik 468c6fd2807SJeff Garzik static void svia_configure(struct pci_dev *pdev) 469c6fd2807SJeff Garzik { 470c6fd2807SJeff Garzik u8 tmp8; 471c6fd2807SJeff Garzik 472c6fd2807SJeff Garzik pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8); 473c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, "routed to hard irq line %d\n", 474c6fd2807SJeff Garzik (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); 475c6fd2807SJeff Garzik 476c6fd2807SJeff Garzik /* make sure SATA channels are enabled */ 477c6fd2807SJeff Garzik pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8); 478c6fd2807SJeff Garzik if ((tmp8 & ALL_PORTS) != ALL_PORTS) { 479c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, 480c6fd2807SJeff Garzik "enabling SATA channels (0x%x)\n", 481c6fd2807SJeff Garzik (int) tmp8); 482c6fd2807SJeff Garzik tmp8 |= ALL_PORTS; 483c6fd2807SJeff Garzik pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8); 484c6fd2807SJeff Garzik } 485c6fd2807SJeff Garzik 486c6fd2807SJeff Garzik /* make sure interrupts for each channel sent to us */ 487c6fd2807SJeff Garzik pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8); 488c6fd2807SJeff Garzik if ((tmp8 & ALL_PORTS) != ALL_PORTS) { 489c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, 490c6fd2807SJeff Garzik "enabling SATA channel interrupts (0x%x)\n", 491c6fd2807SJeff Garzik (int) tmp8); 492c6fd2807SJeff Garzik tmp8 |= ALL_PORTS; 493c6fd2807SJeff Garzik pci_write_config_byte(pdev, SATA_INT_GATE, tmp8); 494c6fd2807SJeff Garzik } 495c6fd2807SJeff Garzik 496c6fd2807SJeff Garzik /* make sure native mode is enabled */ 497c6fd2807SJeff Garzik pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8); 498c6fd2807SJeff Garzik if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) { 499c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, 500c6fd2807SJeff Garzik "enabling SATA channel native mode (0x%x)\n", 501c6fd2807SJeff Garzik (int) tmp8); 502c6fd2807SJeff Garzik tmp8 |= NATIVE_MODE_ALL; 503c6fd2807SJeff Garzik pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); 504c6fd2807SJeff Garzik } 505c6fd2807SJeff Garzik } 506c6fd2807SJeff Garzik 507c6fd2807SJeff Garzik static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) 508c6fd2807SJeff Garzik { 509c6fd2807SJeff Garzik static int printed_version; 510c6fd2807SJeff Garzik unsigned int i; 511c6fd2807SJeff Garzik int rc; 512eca25dcaSTejun Heo struct ata_host *host; 513c6fd2807SJeff Garzik int board_id = (int) ent->driver_data; 514c6fd2807SJeff Garzik const int *bar_sizes; 515c6fd2807SJeff Garzik u8 tmp8; 516c6fd2807SJeff Garzik 517c6fd2807SJeff Garzik if (!printed_version++) 518c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 519c6fd2807SJeff Garzik 52024dc5f33STejun Heo rc = pcim_enable_device(pdev); 521c6fd2807SJeff Garzik if (rc) 522c6fd2807SJeff Garzik return rc; 523c6fd2807SJeff Garzik 524c6fd2807SJeff Garzik if (board_id == vt6420) { 525c6fd2807SJeff Garzik pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); 526c6fd2807SJeff Garzik if (tmp8 & SATA_2DEV) { 527c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 528c6fd2807SJeff Garzik "SATA master/slave not supported (0x%x)\n", 529c6fd2807SJeff Garzik (int) tmp8); 53024dc5f33STejun Heo return -EIO; 531c6fd2807SJeff Garzik } 532c6fd2807SJeff Garzik 533c6fd2807SJeff Garzik bar_sizes = &svia_bar_sizes[0]; 534c6fd2807SJeff Garzik } else { 535c6fd2807SJeff Garzik bar_sizes = &vt6421_bar_sizes[0]; 536c6fd2807SJeff Garzik } 537c6fd2807SJeff Garzik 538c6fd2807SJeff Garzik for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) 539c6fd2807SJeff Garzik if ((pci_resource_start(pdev, i) == 0) || 540c6fd2807SJeff Garzik (pci_resource_len(pdev, i) < bar_sizes[i])) { 541c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 542c6fd2807SJeff Garzik "invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n", 543c6fd2807SJeff Garzik i, 544c6fd2807SJeff Garzik (unsigned long long)pci_resource_start(pdev, i), 545c6fd2807SJeff Garzik (unsigned long long)pci_resource_len(pdev, i)); 54624dc5f33STejun Heo return -ENODEV; 547c6fd2807SJeff Garzik } 548c6fd2807SJeff Garzik 549c6fd2807SJeff Garzik if (board_id == vt6420) 550eca25dcaSTejun Heo rc = vt6420_prepare_host(pdev, &host); 551c6fd2807SJeff Garzik else 552eca25dcaSTejun Heo rc = vt6421_prepare_host(pdev, &host); 553eca25dcaSTejun Heo if (rc) 554eca25dcaSTejun Heo return rc; 555c6fd2807SJeff Garzik 556c6fd2807SJeff Garzik svia_configure(pdev); 557c6fd2807SJeff Garzik 558c6fd2807SJeff Garzik pci_set_master(pdev); 559eca25dcaSTejun Heo return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, 560eca25dcaSTejun Heo &svia_sht); 561c6fd2807SJeff Garzik } 562c6fd2807SJeff Garzik 563c6fd2807SJeff Garzik static int __init svia_init(void) 564c6fd2807SJeff Garzik { 565c6fd2807SJeff Garzik return pci_register_driver(&svia_pci_driver); 566c6fd2807SJeff Garzik } 567c6fd2807SJeff Garzik 568c6fd2807SJeff Garzik static void __exit svia_exit(void) 569c6fd2807SJeff Garzik { 570c6fd2807SJeff Garzik pci_unregister_driver(&svia_pci_driver); 571c6fd2807SJeff Garzik } 572c6fd2807SJeff Garzik 573c6fd2807SJeff Garzik module_init(svia_init); 574c6fd2807SJeff Garzik module_exit(svia_exit); 575