2005-04-17 02:20:36 +04:00
/*
* sata_sis . c - Silicon Integrated Systems SATA
*
* Maintained by : Uwe Koziolek
* Please ALWAYS copy linux - ide @ vger . kernel . org
* on emails .
*
* Copyright 2004 Uwe Koziolek
*
2005-08-29 04:18:39 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*
* libata documentation is available via ' make { ps | pdf } docs ' ,
* as Documentation / DocBook / libata . *
*
* Hardware documentation available under NDA .
2005-04-17 02:20:36 +04:00
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/blkdev.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
2005-10-30 22:39:11 +03:00
# include <linux/device.h>
2005-04-17 02:20:36 +04:00
# include <scsi/scsi_host.h>
# include <linux/libata.h>
2007-02-16 12:40:04 +03:00
# include "sis.h"
2005-04-17 02:20:36 +04:00
# define DRV_NAME "sata_sis"
2006-12-04 03:34:42 +03:00
# define DRV_VERSION "0.7"
2005-04-17 02:20:36 +04:00
enum {
sis_180 = 0 ,
SIS_SCR_PCI_BAR = 5 ,
/* PCI configuration registers */
SIS_GENCTL = 0x54 , /* IDE General Control register */
SIS_SCR_BASE = 0xc0 , /* sata0 phy SCR registers */
2005-09-08 00:44:48 +04:00
SIS180_SATA1_OFS = 0x10 , /* offset from sata0->sata1 phy regs */
SIS182_SATA1_OFS = 0x20 , /* offset from sata0->sata1 phy regs */
SIS_PMR = 0x90 , /* port mapping register */
2005-09-09 07:07:29 +04:00
SIS_PMR_COMBINED = 0x30 ,
2005-04-17 02:20:36 +04:00
/* random bits */
SIS_FLAG_CFGSCR = ( 1 < < 30 ) , /* host flag: SCRs via PCI cfg */
GENCTL_IOMAPPED_SCR = ( 1 < < 26 ) , /* if set, SCRs are in IO space */
} ;
static int sis_init_one ( struct pci_dev * pdev , const struct pci_device_id * ent ) ;
static u32 sis_scr_read ( struct ata_port * ap , unsigned int sc_reg ) ;
static void sis_scr_write ( struct ata_port * ap , unsigned int sc_reg , u32 val ) ;
2005-11-10 19:04:11 +03:00
static const struct pci_device_id sis_pci_tbl [ ] = {
2006-12-04 03:34:42 +03:00
{ PCI_VDEVICE ( SI , 0x0180 ) , sis_180 } , /* SiS 964/180 */
{ PCI_VDEVICE ( SI , 0x0181 ) , sis_180 } , /* SiS 964/180 */
{ PCI_VDEVICE ( SI , 0x0182 ) , sis_180 } , /* SiS 965/965L */
{ PCI_VDEVICE ( SI , 0x0183 ) , sis_180 } , /* SiS 965/965L */
{ PCI_VDEVICE ( SI , 0x1182 ) , sis_180 } , /* SiS 966/966L */
{ PCI_VDEVICE ( SI , 0x1183 ) , sis_180 } , /* SiS 966/966L */
2006-09-29 04:21:59 +04:00
2005-04-17 02:20:36 +04:00
{ } /* terminate list */
} ;
static struct pci_driver sis_pci_driver = {
. name = DRV_NAME ,
. id_table = sis_pci_tbl ,
. probe = sis_init_one ,
. remove = ata_pci_remove_one ,
} ;
2005-11-07 08:59:37 +03:00
static struct scsi_host_template sis_sht = {
2005-04-17 02:20:36 +04:00
. module = THIS_MODULE ,
. name = DRV_NAME ,
. ioctl = ata_scsi_ioctl ,
. queuecommand = ata_scsi_queuecmd ,
. can_queue = ATA_DEF_QUEUE ,
. this_id = ATA_SHT_THIS_ID ,
. sg_tablesize = ATA_MAX_PRD ,
. cmd_per_lun = ATA_SHT_CMD_PER_LUN ,
. emulated = ATA_SHT_EMULATED ,
. use_clustering = ATA_SHT_USE_CLUSTERING ,
. proc_name = DRV_NAME ,
. dma_boundary = ATA_DMA_BOUNDARY ,
. slave_configure = ata_scsi_slave_config ,
2006-05-31 13:28:09 +04:00
. slave_destroy = ata_scsi_slave_destroy ,
2005-04-17 02:20:36 +04:00
. bios_param = ata_std_bios_param ,
} ;
2005-10-22 22:27:05 +04:00
static const struct ata_port_operations sis_ops = {
2005-04-17 02:20:36 +04:00
. port_disable = ata_port_disable ,
. tf_load = ata_tf_load ,
. tf_read = ata_tf_read ,
. check_status = ata_check_status ,
. exec_command = ata_exec_command ,
. dev_select = ata_std_dev_select ,
. bmdma_setup = ata_bmdma_setup ,
. bmdma_start = ata_bmdma_start ,
. bmdma_stop = ata_bmdma_stop ,
. bmdma_status = ata_bmdma_status ,
. qc_prep = ata_qc_prep ,
. qc_issue = ata_qc_issue_prot ,
2007-02-01 09:06:36 +03:00
. data_xfer = ata_data_xfer ,
2006-06-16 10:00:18 +04:00
. freeze = ata_bmdma_freeze ,
. thaw = ata_bmdma_thaw ,
. error_handler = ata_bmdma_error_handler ,
. post_internal_cmd = ata_bmdma_post_internal_cmd ,
2005-04-17 02:20:36 +04:00
. irq_handler = ata_interrupt ,
. irq_clear = ata_bmdma_irq_clear ,
2007-01-26 10:27:58 +03:00
. irq_on = ata_irq_on ,
. irq_ack = ata_irq_ack ,
2005-04-17 02:20:36 +04:00
. scr_read = sis_scr_read ,
. scr_write = sis_scr_write ,
. port_start = ata_port_start ,
} ;
static struct ata_port_info sis_port_info = {
. sht = & sis_sht ,
2006-08-24 11:19:22 +04:00
. flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY ,
2005-04-17 02:20:36 +04:00
. pio_mask = 0x1f ,
. mwdma_mask = 0x7 ,
. udma_mask = 0x7f ,
. port_ops = & sis_ops ,
} ;
MODULE_AUTHOR ( " Uwe Koziolek " ) ;
MODULE_DESCRIPTION ( " low-level driver for Silicon Integratad Systems SATA controller " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( pci , sis_pci_tbl ) ;
MODULE_VERSION ( DRV_VERSION ) ;
2007-01-08 19:11:07 +03:00
static unsigned int get_scr_cfg_addr ( struct ata_port * ap , unsigned int sc_reg )
2005-04-17 02:20:36 +04:00
{
2007-01-08 19:11:07 +03:00
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2005-04-17 02:20:36 +04:00
unsigned int addr = SIS_SCR_BASE + ( 4 * sc_reg ) ;
2007-01-08 19:11:07 +03:00
u8 pmr ;
2005-04-17 02:20:36 +04:00
2007-01-08 19:11:07 +03:00
if ( ap - > port_no ) {
2006-12-04 03:34:42 +03:00
switch ( pdev - > device ) {
case 0x0180 :
case 0x0181 :
2007-01-08 19:11:07 +03:00
pci_read_config_byte ( pdev , SIS_PMR , & pmr ) ;
if ( ( pmr & SIS_PMR_COMBINED ) = = 0 )
addr + = SIS180_SATA1_OFS ;
2006-12-04 03:34:42 +03:00
break ;
case 0x0182 :
case 0x0183 :
case 0x1182 :
case 0x1183 :
addr + = SIS182_SATA1_OFS ;
break ;
}
2005-09-09 07:07:29 +04:00
}
2005-04-17 02:20:36 +04:00
return addr ;
}
static u32 sis_scr_cfg_read ( struct ata_port * ap , unsigned int sc_reg )
{
2006-08-24 11:19:22 +04:00
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2007-01-08 19:11:07 +03:00
unsigned int cfg_addr = get_scr_cfg_addr ( ap , sc_reg ) ;
2005-09-11 19:03:35 +04:00
u32 val , val2 = 0 ;
2005-09-08 00:44:48 +04:00
u8 pmr ;
2005-04-17 02:20:36 +04:00
if ( sc_reg = = SCR_ERROR ) /* doesn't exist in PCI cfg space */
return 0xffffffff ;
2005-09-08 00:44:48 +04:00
pci_read_config_byte ( pdev , SIS_PMR , & pmr ) ;
2005-09-09 07:07:29 +04:00
2005-04-17 02:20:36 +04:00
pci_read_config_dword ( pdev , cfg_addr , & val ) ;
2005-09-08 00:44:48 +04:00
2006-12-04 03:34:42 +03:00
if ( ( pdev - > device = = 0x0182 ) | | ( pdev - > device = = 0x0183 ) | | ( pdev - > device = = 0x1182 ) | |
( pdev - > device = = 0x1183 ) | | ( pmr & SIS_PMR_COMBINED ) )
2005-09-08 00:44:48 +04:00
pci_read_config_dword ( pdev , cfg_addr + 0x10 , & val2 ) ;
2006-11-08 11:57:00 +03:00
return ( val | val2 ) & 0xfffffffb ; /* avoid problems with powerdowned ports */
2005-04-17 02:20:36 +04:00
}
2007-01-08 19:11:07 +03:00
static void sis_scr_cfg_write ( struct ata_port * ap , unsigned int sc_reg , u32 val )
2005-04-17 02:20:36 +04:00
{
2006-08-24 11:19:22 +04:00
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2007-01-08 19:11:07 +03:00
unsigned int cfg_addr = get_scr_cfg_addr ( ap , sc_reg ) ;
2005-09-08 00:44:48 +04:00
u8 pmr ;
2005-04-17 02:20:36 +04:00
2007-01-08 19:11:07 +03:00
if ( sc_reg = = SCR_ERROR ) /* doesn't exist in PCI cfg space */
2005-04-17 02:20:36 +04:00
return ;
2005-09-08 00:44:48 +04:00
pci_read_config_byte ( pdev , SIS_PMR , & pmr ) ;
2005-09-09 07:07:29 +04:00
2005-04-17 02:20:36 +04:00
pci_write_config_dword ( pdev , cfg_addr , val ) ;
2005-09-08 00:44:48 +04:00
2006-12-04 03:34:42 +03:00
if ( ( pdev - > device = = 0x0182 ) | | ( pdev - > device = = 0x0183 ) | | ( pdev - > device = = 0x1182 ) | |
( pdev - > device = = 0x1183 ) | | ( pmr & SIS_PMR_COMBINED ) )
2005-09-08 00:44:48 +04:00
pci_write_config_dword ( pdev , cfg_addr + 0x10 , val ) ;
2005-04-17 02:20:36 +04:00
}
static u32 sis_scr_read ( struct ata_port * ap , unsigned int sc_reg )
{
2006-08-24 11:19:22 +04:00
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2005-09-09 07:07:29 +04:00
u32 val , val2 = 0 ;
2005-09-08 00:44:48 +04:00
u8 pmr ;
2005-04-17 02:20:36 +04:00
if ( sc_reg > SCR_CONTROL )
return 0xffffffffU ;
if ( ap - > flags & SIS_FLAG_CFGSCR )
return sis_scr_cfg_read ( ap , sc_reg ) ;
2005-09-08 00:44:48 +04:00
pci_read_config_byte ( pdev , SIS_PMR , & pmr ) ;
2007-02-01 09:06:36 +03:00
val = ioread32 ( ap - > ioaddr . scr_addr + ( sc_reg * 4 ) ) ;
2005-09-08 00:44:48 +04:00
2006-12-04 03:34:42 +03:00
if ( ( pdev - > device = = 0x0182 ) | | ( pdev - > device = = 0x0183 ) | | ( pdev - > device = = 0x1182 ) | |
( pdev - > device = = 0x1183 ) | | ( pmr & SIS_PMR_COMBINED ) )
2007-02-01 09:06:36 +03:00
val2 = ioread32 ( ap - > ioaddr . scr_addr + ( sc_reg * 4 ) + 0x10 ) ;
2005-09-08 00:44:48 +04:00
2006-11-08 11:57:00 +03:00
return ( val | val2 ) & 0xfffffffb ;
2005-04-17 02:20:36 +04:00
}
static void sis_scr_write ( struct ata_port * ap , unsigned int sc_reg , u32 val )
{
2006-08-24 11:19:22 +04:00
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2005-09-08 00:44:48 +04:00
u8 pmr ;
2005-04-17 02:20:36 +04:00
if ( sc_reg > SCR_CONTROL )
return ;
2005-09-08 00:44:48 +04:00
pci_read_config_byte ( pdev , SIS_PMR , & pmr ) ;
2005-09-09 07:07:29 +04:00
2005-04-17 02:20:36 +04:00
if ( ap - > flags & SIS_FLAG_CFGSCR )
sis_scr_cfg_write ( ap , sc_reg , val ) ;
2005-09-08 00:44:48 +04:00
else {
2007-02-01 09:06:36 +03:00
iowrite32 ( val , ap - > ioaddr . scr_addr + ( sc_reg * 4 ) ) ;
2006-12-04 03:34:42 +03:00
if ( ( pdev - > device = = 0x0182 ) | | ( pdev - > device = = 0x0183 ) | | ( pdev - > device = = 0x1182 ) | |
( pdev - > device = = 0x1183 ) | | ( pmr & SIS_PMR_COMBINED ) )
2007-02-01 09:06:36 +03:00
iowrite32 ( val , ap - > ioaddr . scr_addr + ( sc_reg * 4 ) + 0x10 ) ;
2005-09-08 00:44:48 +04:00
}
2005-04-17 02:20:36 +04:00
}
static int sis_init_one ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
2005-10-30 22:39:11 +03:00
static int printed_version ;
2005-04-17 02:20:36 +04:00
struct ata_probe_ent * probe_ent = NULL ;
int rc ;
2006-11-08 11:57:00 +03:00
u32 genctl , val ;
2006-10-28 06:08:47 +04:00
struct ata_port_info pi = sis_port_info , * ppi [ 2 ] = { & pi , & pi } ;
2005-09-08 00:44:48 +04:00
u8 pmr ;
2006-12-04 03:34:42 +03:00
u8 port2_start = 0x20 ;
2005-04-17 02:20:36 +04:00
2005-10-30 22:39:11 +03:00
if ( ! printed_version + + )
dev_printk ( KERN_INFO , & pdev - > dev , " version " DRV_VERSION " \n " ) ;
2007-01-20 10:00:28 +03:00
rc = pcim_enable_device ( pdev ) ;
2005-04-17 02:20:36 +04:00
if ( rc )
return rc ;
rc = pci_request_regions ( pdev , DRV_NAME ) ;
if ( rc ) {
2007-01-20 10:00:28 +03:00
pcim_pin_device ( pdev ) ;
return rc ;
2005-04-17 02:20:36 +04:00
}
rc = pci_set_dma_mask ( pdev , ATA_DMA_MASK ) ;
if ( rc )
2007-01-20 10:00:28 +03:00
return rc ;
2005-04-17 02:20:36 +04:00
rc = pci_set_consistent_dma_mask ( pdev , ATA_DMA_MASK ) ;
if ( rc )
2007-01-20 10:00:28 +03:00
return rc ;
2005-04-17 02:20:36 +04:00
/* check and see if the SCRs are in IO space or PCI cfg space */
pci_read_config_dword ( pdev , SIS_GENCTL , & genctl ) ;
if ( ( genctl & GENCTL_IOMAPPED_SCR ) = = 0 )
2006-10-28 06:08:47 +04:00
pi . flags | = SIS_FLAG_CFGSCR ;
2005-07-31 21:13:24 +04:00
2005-04-17 02:20:36 +04:00
/* if hardware thinks SCRs are in IO space, but there are
* no IO resources assigned , change to PCI cfg space .
*/
2006-10-28 06:08:47 +04:00
if ( ( ! ( pi . flags & SIS_FLAG_CFGSCR ) ) & &
2005-04-17 02:20:36 +04:00
( ( pci_resource_start ( pdev , SIS_SCR_PCI_BAR ) = = 0 ) | |
( pci_resource_len ( pdev , SIS_SCR_PCI_BAR ) < 128 ) ) ) {
genctl & = ~ GENCTL_IOMAPPED_SCR ;
pci_write_config_dword ( pdev , SIS_GENCTL , genctl ) ;
2006-10-28 06:08:47 +04:00
pi . flags | = SIS_FLAG_CFGSCR ;
2005-04-17 02:20:36 +04:00
}
2005-09-08 00:44:48 +04:00
pci_read_config_byte ( pdev , SIS_PMR , & pmr ) ;
2006-12-04 03:34:42 +03:00
switch ( ent - > device ) {
case 0x0180 :
case 0x0181 :
2007-01-08 19:11:07 +03:00
/* The PATA-handling is provided by pata_sis */
switch ( pmr & 0x30 ) {
case 0x10 :
ppi [ 1 ] = & sis_info133 ;
break ;
2007-02-26 13:51:33 +03:00
2007-01-08 19:11:07 +03:00
case 0x30 :
ppi [ 0 ] = & sis_info133 ;
break ;
}
2005-09-08 00:44:48 +04:00
if ( ( pmr & SIS_PMR_COMBINED ) = = 0 ) {
2005-10-30 22:39:11 +03:00
dev_printk ( KERN_INFO , & pdev - > dev ,
2006-11-08 11:57:00 +03:00
" Detected SiS 180/181/964 chipset in SATA mode \n " ) ;
2005-09-13 02:36:45 +04:00
port2_start = 64 ;
2006-12-04 03:34:42 +03:00
} else {
2005-10-30 22:39:11 +03:00
dev_printk ( KERN_INFO , & pdev - > dev ,
" Detected SiS 180/181 chipset in combined mode \n " ) ;
2005-09-08 00:44:48 +04:00
port2_start = 0 ;
2006-11-08 11:57:00 +03:00
pi . flags | = ATA_FLAG_SLAVE_POSS ;
2005-09-08 00:44:48 +04:00
}
2006-12-04 03:34:42 +03:00
break ;
2006-12-11 19:14:06 +03:00
2006-12-04 03:34:42 +03:00
case 0x0182 :
case 0x0183 :
2006-11-08 11:57:00 +03:00
pci_read_config_dword ( pdev , 0x6C , & val ) ;
if ( val & ( 1L < < 31 ) ) {
dev_printk ( KERN_INFO , & pdev - > dev , " Detected SiS 182/965 chipset \n " ) ;
pi . flags | = ATA_FLAG_SLAVE_POSS ;
2006-12-04 03:34:42 +03:00
} else {
2006-11-08 11:57:00 +03:00
dev_printk ( KERN_INFO , & pdev - > dev , " Detected SiS 182/965L chipset \n " ) ;
2006-12-04 03:34:42 +03:00
}
break ;
case 0x1182 :
case 0x1183 :
pci_read_config_dword ( pdev , 0x64 , & val ) ;
if ( val & 0x10000000 ) {
dev_printk ( KERN_INFO , & pdev - > dev , " Detected SiS 1182/1183/966L SATA controller \n " ) ;
} else {
dev_printk ( KERN_INFO , & pdev - > dev , " Detected SiS 1182/1183/966 SATA controller \n " ) ;
pi . flags | = ATA_FLAG_SLAVE_POSS ;
}
break ;
2005-09-08 00:44:48 +04:00
}
2006-10-28 06:08:47 +04:00
probe_ent = ata_pci_init_native_mode ( pdev , ppi , ATA_PORT_PRIMARY | ATA_PORT_SECONDARY ) ;
2007-01-20 10:00:28 +03:00
if ( ! probe_ent )
return - ENOMEM ;
2006-10-28 06:08:47 +04:00
2006-08-24 11:19:22 +04:00
if ( ! ( probe_ent - > port_flags & SIS_FLAG_CFGSCR ) ) {
2007-02-01 09:06:36 +03:00
void * mmio ;
mmio = pcim_iomap ( pdev , SIS_SCR_PCI_BAR , 0 ) ;
if ( ! mmio )
return - ENOMEM ;
probe_ent - > port [ 0 ] . scr_addr = mmio ;
probe_ent - > port [ 1 ] . scr_addr = mmio + port2_start ;
2005-04-17 02:20:36 +04:00
}
pci_set_master ( pdev ) ;
2005-08-15 23:23:41 +04:00
pci_intx ( pdev , 1 ) ;
2005-04-17 02:20:36 +04:00
2007-01-20 10:00:28 +03:00
if ( ! ata_device_add ( probe_ent ) )
return - EIO ;
2005-04-17 02:20:36 +04:00
2007-01-20 10:00:28 +03:00
devm_kfree ( & pdev - > dev , probe_ent ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int __init sis_init ( void )
{
2006-08-10 13:13:18 +04:00
return pci_register_driver ( & sis_pci_driver ) ;
2005-04-17 02:20:36 +04:00
}
static void __exit sis_exit ( void )
{
pci_unregister_driver ( & sis_pci_driver ) ;
}
module_init ( sis_init ) ;
module_exit ( sis_exit ) ;