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, 111c6fd2807SJeff Garzik .data_xfer = ata_pio_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; 191c6fd2807SJeff Garzik 192c6fd2807SJeff Garzik if (!printed_version++) 193c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); 194c6fd2807SJeff Garzik 195*24dc5f33STejun Heo rc = pcim_enable_device(pdev); 196c6fd2807SJeff Garzik if (rc) 197c6fd2807SJeff Garzik return rc; 198c6fd2807SJeff Garzik 199c6fd2807SJeff Garzik rc = pci_request_regions(pdev, DRV_NAME); 200c6fd2807SJeff Garzik if (rc) { 201*24dc5f33STejun Heo pcim_pin_device(pdev); 202*24dc5f33STejun Heo return rc; 203c6fd2807SJeff Garzik } 204c6fd2807SJeff Garzik 205c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); 206c6fd2807SJeff Garzik if (rc) 207*24dc5f33STejun Heo return rc; 208c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); 209c6fd2807SJeff Garzik if (rc) 210*24dc5f33STejun Heo return rc; 211c6fd2807SJeff Garzik 21229da9f6dSJeff Garzik ppi[0] = ppi[1] = &uli_port_info; 21329da9f6dSJeff Garzik probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); 214*24dc5f33STejun Heo if (!probe_ent) 215*24dc5f33STejun Heo return -ENOMEM; 216c6fd2807SJeff Garzik 217*24dc5f33STejun Heo hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); 218*24dc5f33STejun Heo if (!hpriv) 219*24dc5f33STejun Heo return -ENOMEM; 220c6fd2807SJeff Garzik 221c6fd2807SJeff Garzik probe_ent->private_data = hpriv; 222c6fd2807SJeff Garzik 223c6fd2807SJeff Garzik switch (board_idx) { 224c6fd2807SJeff Garzik case uli_5287: 225c6fd2807SJeff Garzik hpriv->scr_cfg_addr[0] = ULI5287_BASE; 226c6fd2807SJeff Garzik hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS; 227c6fd2807SJeff Garzik probe_ent->n_ports = 4; 228c6fd2807SJeff Garzik 229c6fd2807SJeff Garzik probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8; 230c6fd2807SJeff Garzik probe_ent->port[2].altstatus_addr = 231c6fd2807SJeff Garzik probe_ent->port[2].ctl_addr = 232c6fd2807SJeff Garzik (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4; 233c6fd2807SJeff Garzik probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16; 234c6fd2807SJeff Garzik hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; 235c6fd2807SJeff Garzik 236c6fd2807SJeff Garzik probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8; 237c6fd2807SJeff Garzik probe_ent->port[3].altstatus_addr = 238c6fd2807SJeff Garzik probe_ent->port[3].ctl_addr = 239c6fd2807SJeff Garzik (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4; 240c6fd2807SJeff Garzik probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24; 241c6fd2807SJeff Garzik hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; 242c6fd2807SJeff Garzik 243c6fd2807SJeff Garzik ata_std_ports(&probe_ent->port[2]); 244c6fd2807SJeff Garzik ata_std_ports(&probe_ent->port[3]); 245c6fd2807SJeff Garzik break; 246c6fd2807SJeff Garzik 247c6fd2807SJeff Garzik case uli_5289: 248c6fd2807SJeff Garzik hpriv->scr_cfg_addr[0] = ULI5287_BASE; 249c6fd2807SJeff Garzik hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS; 250c6fd2807SJeff Garzik break; 251c6fd2807SJeff Garzik 252c6fd2807SJeff Garzik case uli_5281: 253c6fd2807SJeff Garzik hpriv->scr_cfg_addr[0] = ULI5281_BASE; 254c6fd2807SJeff Garzik hpriv->scr_cfg_addr[1] = ULI5281_BASE + ULI5281_OFFS; 255c6fd2807SJeff Garzik break; 256c6fd2807SJeff Garzik 257c6fd2807SJeff Garzik default: 258c6fd2807SJeff Garzik BUG(); 259c6fd2807SJeff Garzik break; 260c6fd2807SJeff Garzik } 261c6fd2807SJeff Garzik 262c6fd2807SJeff Garzik pci_set_master(pdev); 263c6fd2807SJeff Garzik pci_intx(pdev, 1); 264c6fd2807SJeff Garzik 265*24dc5f33STejun Heo if (!ata_device_add(probe_ent)) 266*24dc5f33STejun Heo return -ENODEV; 267c6fd2807SJeff Garzik 268*24dc5f33STejun Heo devm_kfree(&pdev->dev, probe_ent); 269c6fd2807SJeff Garzik return 0; 270c6fd2807SJeff Garzik } 271c6fd2807SJeff Garzik 272c6fd2807SJeff Garzik static int __init uli_init(void) 273c6fd2807SJeff Garzik { 274c6fd2807SJeff Garzik return pci_register_driver(&uli_pci_driver); 275c6fd2807SJeff Garzik } 276c6fd2807SJeff Garzik 277c6fd2807SJeff Garzik static void __exit uli_exit(void) 278c6fd2807SJeff Garzik { 279c6fd2807SJeff Garzik pci_unregister_driver(&uli_pci_driver); 280c6fd2807SJeff Garzik } 281c6fd2807SJeff Garzik 282c6fd2807SJeff Garzik 283c6fd2807SJeff Garzik module_init(uli_init); 284c6fd2807SJeff Garzik module_exit(uli_exit); 285