1c6fd2807SJeff Garzik /* 2c6fd2807SJeff Garzik * sata_uli.c - ULi Electronics SATA 3c6fd2807SJeff Garzik * 4c6fd2807SJeff Garzik * 5c6fd2807SJeff Garzik * This program is free software; you can redistribute it and/or modify 6c6fd2807SJeff Garzik * it under the terms of the GNU General Public License as published by 7c6fd2807SJeff Garzik * the Free Software Foundation; either version 2, or (at your option) 8c6fd2807SJeff Garzik * any later version. 9c6fd2807SJeff Garzik * 10c6fd2807SJeff Garzik * This program is distributed in the hope that it will be useful, 11c6fd2807SJeff Garzik * but WITHOUT ANY WARRANTY; without even the implied warranty of 12c6fd2807SJeff Garzik * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13c6fd2807SJeff Garzik * GNU General Public License for more details. 14c6fd2807SJeff Garzik * 15c6fd2807SJeff Garzik * You should have received a copy of the GNU General Public License 16c6fd2807SJeff Garzik * along with this program; see the file COPYING. If not, write to 17c6fd2807SJeff Garzik * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 18c6fd2807SJeff Garzik * 19c6fd2807SJeff Garzik * 20c6fd2807SJeff Garzik * libata documentation is available via 'make {ps|pdf}docs', 21c6fd2807SJeff Garzik * as Documentation/DocBook/libata.* 22c6fd2807SJeff Garzik * 23c6fd2807SJeff Garzik * Hardware documentation available under NDA. 24c6fd2807SJeff Garzik * 25c6fd2807SJeff Garzik */ 26c6fd2807SJeff Garzik 27c6fd2807SJeff Garzik #include <linux/kernel.h> 28c6fd2807SJeff Garzik #include <linux/module.h> 29c6fd2807SJeff Garzik #include <linux/pci.h> 30c6fd2807SJeff Garzik #include <linux/init.h> 31c6fd2807SJeff Garzik #include <linux/blkdev.h> 32c6fd2807SJeff Garzik #include <linux/delay.h> 33c6fd2807SJeff Garzik #include <linux/interrupt.h> 34c6fd2807SJeff Garzik #include <linux/device.h> 35c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 36c6fd2807SJeff Garzik #include <linux/libata.h> 37c6fd2807SJeff Garzik 38c6fd2807SJeff Garzik #define DRV_NAME "sata_uli" 39c6fd2807SJeff Garzik #define DRV_VERSION "1.0" 40c6fd2807SJeff Garzik 41c6fd2807SJeff Garzik enum { 42c6fd2807SJeff Garzik uli_5289 = 0, 43c6fd2807SJeff Garzik uli_5287 = 1, 44c6fd2807SJeff Garzik uli_5281 = 2, 45c6fd2807SJeff Garzik 46c6fd2807SJeff Garzik uli_max_ports = 4, 47c6fd2807SJeff Garzik 48c6fd2807SJeff Garzik /* PCI configuration registers */ 49c6fd2807SJeff Garzik ULI5287_BASE = 0x90, /* sata0 phy SCR registers */ 50c6fd2807SJeff Garzik ULI5287_OFFS = 0x10, /* offset from sata0->sata1 phy regs */ 51c6fd2807SJeff Garzik ULI5281_BASE = 0x60, /* sata0 phy SCR registers */ 52c6fd2807SJeff Garzik ULI5281_OFFS = 0x60, /* offset from sata0->sata1 phy regs */ 53c6fd2807SJeff Garzik }; 54c6fd2807SJeff Garzik 55c6fd2807SJeff Garzik struct uli_priv { 56c6fd2807SJeff Garzik unsigned int scr_cfg_addr[uli_max_ports]; 57c6fd2807SJeff Garzik }; 58c6fd2807SJeff Garzik 59c6fd2807SJeff Garzik static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); 60c6fd2807SJeff Garzik static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg); 61c6fd2807SJeff Garzik static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); 62c6fd2807SJeff Garzik 63c6fd2807SJeff Garzik static const struct pci_device_id uli_pci_tbl[] = { 6454bb3a94SJeff Garzik { PCI_VDEVICE(AL, 0x5289), uli_5289 }, 6554bb3a94SJeff Garzik { PCI_VDEVICE(AL, 0x5287), uli_5287 }, 6654bb3a94SJeff Garzik { PCI_VDEVICE(AL, 0x5281), uli_5281 }, 6754bb3a94SJeff Garzik 68c6fd2807SJeff Garzik { } /* terminate list */ 69c6fd2807SJeff Garzik }; 70c6fd2807SJeff Garzik 71c6fd2807SJeff Garzik static struct pci_driver uli_pci_driver = { 72c6fd2807SJeff Garzik .name = DRV_NAME, 73c6fd2807SJeff Garzik .id_table = uli_pci_tbl, 74c6fd2807SJeff Garzik .probe = uli_init_one, 75c6fd2807SJeff Garzik .remove = ata_pci_remove_one, 76c6fd2807SJeff Garzik }; 77c6fd2807SJeff Garzik 78c6fd2807SJeff Garzik static struct scsi_host_template uli_sht = { 79c6fd2807SJeff Garzik .module = THIS_MODULE, 80c6fd2807SJeff Garzik .name = DRV_NAME, 81c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 82c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 83c6fd2807SJeff Garzik .can_queue = ATA_DEF_QUEUE, 84c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 85c6fd2807SJeff Garzik .sg_tablesize = LIBATA_MAX_PRD, 86c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 87c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 88c6fd2807SJeff Garzik .use_clustering = ATA_SHT_USE_CLUSTERING, 89c6fd2807SJeff Garzik .proc_name = DRV_NAME, 90c6fd2807SJeff Garzik .dma_boundary = ATA_DMA_BOUNDARY, 91c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 92c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 93c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 94c6fd2807SJeff Garzik }; 95c6fd2807SJeff Garzik 96c6fd2807SJeff Garzik static const struct ata_port_operations uli_ops = { 97c6fd2807SJeff Garzik .port_disable = ata_port_disable, 98c6fd2807SJeff Garzik 99c6fd2807SJeff Garzik .tf_load = ata_tf_load, 100c6fd2807SJeff Garzik .tf_read = ata_tf_read, 101c6fd2807SJeff Garzik .check_status = ata_check_status, 102c6fd2807SJeff Garzik .exec_command = ata_exec_command, 103c6fd2807SJeff Garzik .dev_select = ata_std_dev_select, 104c6fd2807SJeff Garzik 105c6fd2807SJeff Garzik .bmdma_setup = ata_bmdma_setup, 106c6fd2807SJeff Garzik .bmdma_start = ata_bmdma_start, 107c6fd2807SJeff Garzik .bmdma_stop = ata_bmdma_stop, 108c6fd2807SJeff Garzik .bmdma_status = ata_bmdma_status, 109c6fd2807SJeff Garzik .qc_prep = ata_qc_prep, 110c6fd2807SJeff Garzik .qc_issue = ata_qc_issue_prot, 111*0d5ff566STejun Heo .data_xfer = ata_data_xfer, 112c6fd2807SJeff Garzik 113c6fd2807SJeff Garzik .freeze = ata_bmdma_freeze, 114c6fd2807SJeff Garzik .thaw = ata_bmdma_thaw, 115c6fd2807SJeff Garzik .error_handler = ata_bmdma_error_handler, 116c6fd2807SJeff Garzik .post_internal_cmd = ata_bmdma_post_internal_cmd, 117c6fd2807SJeff Garzik 118c6fd2807SJeff Garzik .irq_handler = ata_interrupt, 119c6fd2807SJeff Garzik .irq_clear = ata_bmdma_irq_clear, 120c6fd2807SJeff Garzik 121c6fd2807SJeff Garzik .scr_read = uli_scr_read, 122c6fd2807SJeff Garzik .scr_write = uli_scr_write, 123c6fd2807SJeff Garzik 124c6fd2807SJeff Garzik .port_start = ata_port_start, 125c6fd2807SJeff Garzik }; 126c6fd2807SJeff Garzik 127c6fd2807SJeff Garzik static struct ata_port_info uli_port_info = { 128c6fd2807SJeff Garzik .sht = &uli_sht, 129b2a8bbe6STejun Heo .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 130b2a8bbe6STejun Heo ATA_FLAG_IGN_SIMPLEX, 131c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 132c6fd2807SJeff Garzik .udma_mask = 0x7f, /* udma0-6 */ 133c6fd2807SJeff Garzik .port_ops = &uli_ops, 134c6fd2807SJeff Garzik }; 135c6fd2807SJeff Garzik 136c6fd2807SJeff Garzik 137c6fd2807SJeff Garzik MODULE_AUTHOR("Peer Chen"); 138c6fd2807SJeff Garzik MODULE_DESCRIPTION("low-level driver for ULi Electronics SATA controller"); 139c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 140c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, uli_pci_tbl); 141c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 142c6fd2807SJeff Garzik 143c6fd2807SJeff Garzik static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) 144c6fd2807SJeff Garzik { 145cca3974eSJeff Garzik struct uli_priv *hpriv = ap->host->private_data; 146c6fd2807SJeff Garzik return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg); 147c6fd2807SJeff Garzik } 148c6fd2807SJeff Garzik 149c6fd2807SJeff Garzik static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) 150c6fd2807SJeff Garzik { 151cca3974eSJeff Garzik struct pci_dev *pdev = to_pci_dev(ap->host->dev); 152c6fd2807SJeff Garzik unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); 153c6fd2807SJeff Garzik u32 val; 154c6fd2807SJeff Garzik 155c6fd2807SJeff Garzik pci_read_config_dword(pdev, cfg_addr, &val); 156c6fd2807SJeff Garzik return val; 157c6fd2807SJeff Garzik } 158c6fd2807SJeff Garzik 159c6fd2807SJeff Garzik static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) 160c6fd2807SJeff Garzik { 161cca3974eSJeff Garzik struct pci_dev *pdev = to_pci_dev(ap->host->dev); 162c6fd2807SJeff Garzik unsigned int cfg_addr = get_scr_cfg_addr(ap, scr); 163c6fd2807SJeff Garzik 164c6fd2807SJeff Garzik pci_write_config_dword(pdev, cfg_addr, val); 165c6fd2807SJeff Garzik } 166c6fd2807SJeff Garzik 167c6fd2807SJeff Garzik static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg) 168c6fd2807SJeff Garzik { 169c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 170c6fd2807SJeff Garzik return 0xffffffffU; 171c6fd2807SJeff Garzik 172c6fd2807SJeff Garzik return uli_scr_cfg_read(ap, sc_reg); 173c6fd2807SJeff Garzik } 174c6fd2807SJeff Garzik 175c6fd2807SJeff Garzik static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) 176c6fd2807SJeff Garzik { 177c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0 178c6fd2807SJeff Garzik return; 179c6fd2807SJeff Garzik 180c6fd2807SJeff Garzik uli_scr_cfg_write(ap, sc_reg, val); 181c6fd2807SJeff Garzik } 182c6fd2807SJeff Garzik 183c6fd2807SJeff Garzik static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) 184c6fd2807SJeff Garzik { 185c6fd2807SJeff Garzik static int printed_version; 186c6fd2807SJeff Garzik struct ata_probe_ent *probe_ent; 18729da9f6dSJeff Garzik struct ata_port_info *ppi[2]; 188c6fd2807SJeff Garzik int rc; 189c6fd2807SJeff Garzik unsigned int board_idx = (unsigned int) ent->driver_data; 190c6fd2807SJeff Garzik struct uli_priv *hpriv; 191*0d5ff566STejun Heo void __iomem * const *iomap; 192c6fd2807SJeff Garzik 193c6fd2807SJeff Garzik if (!printed_version++) 194c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); 195c6fd2807SJeff Garzik 19624dc5f33STejun Heo rc = pcim_enable_device(pdev); 197c6fd2807SJeff Garzik if (rc) 198c6fd2807SJeff Garzik return rc; 199c6fd2807SJeff Garzik 200c6fd2807SJeff Garzik rc = pci_request_regions(pdev, DRV_NAME); 201c6fd2807SJeff Garzik if (rc) { 20224dc5f33STejun Heo pcim_pin_device(pdev); 20324dc5f33STejun Heo return rc; 204c6fd2807SJeff Garzik } 205c6fd2807SJeff Garzik 206c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); 207c6fd2807SJeff Garzik if (rc) 20824dc5f33STejun Heo return rc; 209c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); 210c6fd2807SJeff Garzik if (rc) 21124dc5f33STejun Heo return rc; 212c6fd2807SJeff Garzik 21329da9f6dSJeff Garzik ppi[0] = ppi[1] = &uli_port_info; 21429da9f6dSJeff Garzik probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); 21524dc5f33STejun Heo if (!probe_ent) 21624dc5f33STejun Heo return -ENOMEM; 217c6fd2807SJeff Garzik 21824dc5f33STejun Heo hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); 21924dc5f33STejun Heo if (!hpriv) 22024dc5f33STejun Heo return -ENOMEM; 221c6fd2807SJeff Garzik 222c6fd2807SJeff Garzik probe_ent->private_data = hpriv; 223c6fd2807SJeff Garzik 224*0d5ff566STejun Heo iomap = pcim_iomap_table(pdev); 225*0d5ff566STejun Heo 226c6fd2807SJeff Garzik switch (board_idx) { 227c6fd2807SJeff Garzik case uli_5287: 228c6fd2807SJeff Garzik hpriv->scr_cfg_addr[0] = ULI5287_BASE; 229c6fd2807SJeff Garzik hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS; 230c6fd2807SJeff Garzik probe_ent->n_ports = 4; 231c6fd2807SJeff Garzik 232*0d5ff566STejun Heo probe_ent->port[2].cmd_addr = iomap[0] + 8; 233c6fd2807SJeff Garzik probe_ent->port[2].altstatus_addr = 234*0d5ff566STejun Heo probe_ent->port[2].ctl_addr = (void __iomem *) 235*0d5ff566STejun Heo ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4; 236*0d5ff566STejun Heo probe_ent->port[2].bmdma_addr = iomap[4] + 16; 237c6fd2807SJeff Garzik hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; 238c6fd2807SJeff Garzik 239*0d5ff566STejun Heo probe_ent->port[3].cmd_addr = iomap[2] + 8; 240c6fd2807SJeff Garzik probe_ent->port[3].altstatus_addr = 241*0d5ff566STejun Heo probe_ent->port[3].ctl_addr = (void __iomem *) 242*0d5ff566STejun Heo ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4; 243*0d5ff566STejun Heo probe_ent->port[3].bmdma_addr = iomap[4] + 24; 244c6fd2807SJeff Garzik hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; 245c6fd2807SJeff Garzik 246c6fd2807SJeff Garzik ata_std_ports(&probe_ent->port[2]); 247c6fd2807SJeff Garzik ata_std_ports(&probe_ent->port[3]); 248c6fd2807SJeff Garzik break; 249c6fd2807SJeff Garzik 250c6fd2807SJeff Garzik case uli_5289: 251c6fd2807SJeff Garzik hpriv->scr_cfg_addr[0] = ULI5287_BASE; 252c6fd2807SJeff Garzik hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS; 253c6fd2807SJeff Garzik break; 254c6fd2807SJeff Garzik 255c6fd2807SJeff Garzik case uli_5281: 256c6fd2807SJeff Garzik hpriv->scr_cfg_addr[0] = ULI5281_BASE; 257c6fd2807SJeff Garzik hpriv->scr_cfg_addr[1] = ULI5281_BASE + ULI5281_OFFS; 258c6fd2807SJeff Garzik break; 259c6fd2807SJeff Garzik 260c6fd2807SJeff Garzik default: 261c6fd2807SJeff Garzik BUG(); 262c6fd2807SJeff Garzik break; 263c6fd2807SJeff Garzik } 264c6fd2807SJeff Garzik 265c6fd2807SJeff Garzik pci_set_master(pdev); 266c6fd2807SJeff Garzik pci_intx(pdev, 1); 267c6fd2807SJeff Garzik 26824dc5f33STejun Heo if (!ata_device_add(probe_ent)) 26924dc5f33STejun Heo return -ENODEV; 270c6fd2807SJeff Garzik 27124dc5f33STejun Heo devm_kfree(&pdev->dev, probe_ent); 272c6fd2807SJeff Garzik return 0; 273c6fd2807SJeff Garzik } 274c6fd2807SJeff Garzik 275c6fd2807SJeff Garzik static int __init uli_init(void) 276c6fd2807SJeff Garzik { 277c6fd2807SJeff Garzik return pci_register_driver(&uli_pci_driver); 278c6fd2807SJeff Garzik } 279c6fd2807SJeff Garzik 280c6fd2807SJeff Garzik static void __exit uli_exit(void) 281c6fd2807SJeff Garzik { 282c6fd2807SJeff Garzik pci_unregister_driver(&uli_pci_driver); 283c6fd2807SJeff Garzik } 284c6fd2807SJeff Garzik 285c6fd2807SJeff Garzik 286c6fd2807SJeff Garzik module_init(uli_init); 287c6fd2807SJeff Garzik module_exit(uli_exit); 288