2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 1999 - 2000 Andre Hedrick < andre @ linux - ide . org >
* Copyright ( C ) 2002 Lionel Bouton < Lionel . Bouton @ inet6 . fr > , Maintainer
* Copyright ( C ) 2003 Vojtech Pavlik < vojtech @ suse . cz >
2009-10-06 18:46:05 +04:00
* Copyright ( C ) 2007 - 2009 Bartlomiej Zolnierkiewicz
2007-05-16 02:51:42 +04:00
*
2005-04-17 02:20:36 +04:00
* May be copied or modified under the terms of the GNU General Public License
*
*
* Thanks :
*
* SiS Taiwan : for direct support and hardware .
* Daniela Engert : for initial ATA100 advices and numerous others .
* John Fremlin , Manfred Spraul , Dave Morgan , Peter Kjellerstedt :
* for checking code correctness , providing patches .
*
*
* Original tests and design on the SiS620 chipset .
* ATA100 tests and design on the SiS735 chipset .
* ATA16 / 33 support from specs
* ATA133 support for SiS961 / 962 by L . C . Chang < lcchang @ sis . com . tw >
* ATA133 961 / 962 / 963 fixes by Vojtech Pavlik < vojtech @ suse . cz >
*
* Documentation :
* SiS chipset documentation available under NDA to companies only
* ( not to individuals ) .
*/
/*
* The original SiS5513 comes from a SiS5511 / 55112 / 5513 chipset . The original
* SiS5513 was also used in the SiS5596 / 5513 chipset . Thus if we see a SiS5511
* or SiS5596 , we can assume we see the first MWDMA - 16 capable SiS5513 chip .
*
* Later SiS chipsets integrated the 5513 functionality into the NorthBridge ,
* starting with SiS5571 and up to SiS745 . The PCI ID didn ' t change , though . We
* can figure out that we have a more modern and more capable 5513 by looking
* for the respective NorthBridge IDs .
*
* Even later ( 96 x family ) SiS chipsets use the MuTIOL link and place the 5513
* into the SouthBrige . Here we cannot rely on looking up the NorthBridge PCI
* ID , while the now ATA - 133 capable 5513 still has the same PCI ID .
* Fortunately the 5513 can be ' unmasked ' by fiddling with some config space
* bits , changing its device id to the true one - 5517 for 961 and 5518 for
* 962 / 963.
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/ide.h>
2008-07-25 00:53:32 +04:00
# define DRV_NAME "sis5513"
2011-03-31 05:57:33 +04:00
/* registers layout and init values are chipset family dependent */
2005-04-17 02:20:36 +04:00
# define ATA_16 0x01
# define ATA_33 0x02
# define ATA_66 0x03
2008-04-26 19:36:39 +04:00
# define ATA_100a 0x04 /* SiS730/SiS550 is ATA100 with ATA66 layout */
2005-04-17 02:20:36 +04:00
# define ATA_100 0x05
2008-04-26 19:36:39 +04:00
# define ATA_133a 0x06 /* SiS961b with 133 support */
# define ATA_133 0x07 /* SiS962/963 */
2005-04-17 02:20:36 +04:00
static u8 chipset_family ;
/*
* Devices supported
*/
static const struct {
const char * name ;
u16 host_id ;
u8 chipset_family ;
u8 flags ;
} SiSHostChipInfo [ ] = {
2006-09-08 20:47:51 +04:00
{ " SiS968 " , PCI_DEVICE_ID_SI_968 , ATA_133 } ,
{ " SiS966 " , PCI_DEVICE_ID_SI_966 , ATA_133 } ,
2005-11-19 23:43:45 +03:00
{ " SiS965 " , PCI_DEVICE_ID_SI_965 , ATA_133 } ,
2005-04-17 02:20:36 +04:00
{ " SiS745 " , PCI_DEVICE_ID_SI_745 , ATA_100 } ,
{ " SiS735 " , PCI_DEVICE_ID_SI_735 , ATA_100 } ,
{ " SiS733 " , PCI_DEVICE_ID_SI_733 , ATA_100 } ,
{ " SiS635 " , PCI_DEVICE_ID_SI_635 , ATA_100 } ,
{ " SiS633 " , PCI_DEVICE_ID_SI_633 , ATA_100 } ,
{ " SiS730 " , PCI_DEVICE_ID_SI_730 , ATA_100a } ,
{ " SiS550 " , PCI_DEVICE_ID_SI_550 , ATA_100a } ,
{ " SiS640 " , PCI_DEVICE_ID_SI_640 , ATA_66 } ,
{ " SiS630 " , PCI_DEVICE_ID_SI_630 , ATA_66 } ,
{ " SiS620 " , PCI_DEVICE_ID_SI_620 , ATA_66 } ,
{ " SiS540 " , PCI_DEVICE_ID_SI_540 , ATA_66 } ,
{ " SiS530 " , PCI_DEVICE_ID_SI_530 , ATA_66 } ,
{ " SiS5600 " , PCI_DEVICE_ID_SI_5600 , ATA_33 } ,
{ " SiS5598 " , PCI_DEVICE_ID_SI_5598 , ATA_33 } ,
{ " SiS5597 " , PCI_DEVICE_ID_SI_5597 , ATA_33 } ,
{ " SiS5591/2 " , PCI_DEVICE_ID_SI_5591 , ATA_33 } ,
{ " SiS5582 " , PCI_DEVICE_ID_SI_5582 , ATA_33 } ,
{ " SiS5581 " , PCI_DEVICE_ID_SI_5581 , ATA_33 } ,
{ " SiS5596 " , PCI_DEVICE_ID_SI_5596 , ATA_16 } ,
{ " SiS5571 " , PCI_DEVICE_ID_SI_5571 , ATA_16 } ,
2006-03-28 13:56:31 +04:00
{ " SiS5517 " , PCI_DEVICE_ID_SI_5517 , ATA_16 } ,
2005-04-17 02:20:36 +04:00
{ " SiS551x " , PCI_DEVICE_ID_SI_5511 , ATA_16 } ,
} ;
/* Cycle time bits and values vary across chip dma capabilities
These three arrays hold the register layout and the values to set .
Indexed by chipset_family and ( dma_mode - XFER_UDMA_0 ) */
/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
2008-04-26 19:36:39 +04:00
static u8 cycle_time_offset [ ] = { 0 , 0 , 5 , 4 , 4 , 0 , 0 } ;
static u8 cycle_time_range [ ] = { 0 , 0 , 2 , 3 , 3 , 4 , 4 } ;
2005-04-17 02:20:36 +04:00
static u8 cycle_time_value [ ] [ XFER_UDMA_6 - XFER_UDMA_0 + 1 ] = {
2008-04-26 19:36:39 +04:00
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 } , /* no UDMA */
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 } , /* no UDMA */
{ 3 , 2 , 1 , 0 , 0 , 0 , 0 } , /* ATA_33 */
{ 7 , 5 , 3 , 2 , 1 , 0 , 0 } , /* ATA_66 */
{ 7 , 5 , 3 , 2 , 1 , 0 , 0 } , /* ATA_100a (730 specific),
different cycle_time range and offset */
{ 11 , 7 , 5 , 4 , 2 , 1 , 0 } , /* ATA_100 */
{ 15 , 10 , 7 , 5 , 3 , 2 , 1 } , /* ATA_133a (earliest 691 southbridges) */
{ 15 , 10 , 7 , 5 , 3 , 2 , 1 } , /* ATA_133 */
2005-04-17 02:20:36 +04:00
} ;
/* CRC Valid Setup Time vary across IDE clock setting 33/66/100/133
See SiS962 data sheet for more detail */
static u8 cvs_time_value [ ] [ XFER_UDMA_6 - XFER_UDMA_0 + 1 ] = {
2008-04-26 19:36:39 +04:00
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 } , /* no UDMA */
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 } , /* no UDMA */
{ 2 , 1 , 1 , 0 , 0 , 0 , 0 } ,
{ 4 , 3 , 2 , 1 , 0 , 0 , 0 } ,
{ 4 , 3 , 2 , 1 , 0 , 0 , 0 } ,
{ 6 , 4 , 3 , 1 , 1 , 1 , 0 } ,
{ 9 , 6 , 4 , 2 , 2 , 2 , 2 } ,
{ 9 , 6 , 4 , 2 , 2 , 2 , 2 } ,
2005-04-17 02:20:36 +04:00
} ;
/* Initialize time, Active time, Recovery time vary across
IDE clock settings . These 3 arrays hold the register value
for PIO0 / 1 / 2 / 3 / 4 and DMA0 / 1 / 2 mode in order */
static u8 ini_time_value [ ] [ 8 ] = {
2008-04-26 19:36:39 +04:00
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 2 , 1 , 0 , 0 , 0 , 1 , 0 , 0 } ,
{ 4 , 3 , 1 , 1 , 1 , 3 , 1 , 1 } ,
{ 4 , 3 , 1 , 1 , 1 , 3 , 1 , 1 } ,
{ 6 , 4 , 2 , 2 , 2 , 4 , 2 , 2 } ,
{ 9 , 6 , 3 , 3 , 3 , 6 , 3 , 3 } ,
{ 9 , 6 , 3 , 3 , 3 , 6 , 3 , 3 } ,
2005-04-17 02:20:36 +04:00
} ;
static u8 act_time_value [ ] [ 8 ] = {
2008-04-26 19:36:39 +04:00
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 9 , 9 , 9 , 2 , 2 , 7 , 2 , 2 } ,
{ 19 , 19 , 19 , 5 , 4 , 14 , 5 , 4 } ,
{ 19 , 19 , 19 , 5 , 4 , 14 , 5 , 4 } ,
{ 28 , 28 , 28 , 7 , 6 , 21 , 7 , 6 } ,
{ 38 , 38 , 38 , 10 , 9 , 28 , 10 , 9 } ,
{ 38 , 38 , 38 , 10 , 9 , 28 , 10 , 9 } ,
2005-04-17 02:20:36 +04:00
} ;
static u8 rco_time_value [ ] [ 8 ] = {
2008-04-26 19:36:39 +04:00
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 9 , 2 , 0 , 2 , 0 , 7 , 1 , 1 } ,
{ 19 , 5 , 1 , 5 , 2 , 16 , 3 , 2 } ,
{ 19 , 5 , 1 , 5 , 2 , 16 , 3 , 2 } ,
{ 30 , 9 , 3 , 9 , 4 , 25 , 6 , 4 } ,
{ 40 , 12 , 4 , 12 , 5 , 34 , 12 , 5 } ,
{ 40 , 12 , 4 , 12 , 5 , 34 , 12 , 5 } ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Printing configuration
*/
/* Used for chipset type printing at boot time */
2008-04-26 19:36:39 +04:00
static char * chipset_capability [ ] = {
2005-04-17 02:20:36 +04:00
" ATA " , " ATA 16 " ,
" ATA 33 " , " ATA 66 " ,
" ATA 100 (1st gen) " , " ATA 100 (2nd gen) " ,
" ATA 133 (1st gen) " , " ATA 133 (2nd gen) "
} ;
/*
* Configuration functions
*/
2007-10-17 00:29:52 +04:00
static u8 sis_ata133_get_base ( ide_drive_t * drive )
{
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( drive - > hwif - > dev ) ;
2007-10-17 00:29:52 +04:00
u32 reg54 = 0 ;
pci_read_config_dword ( dev , 0x54 , & reg54 ) ;
return ( ( reg54 & 0x40000000 ) ? 0x70 : 0x40 ) + drive - > dn * 4 ;
}
static void sis_ata16_program_timings ( ide_drive_t * drive , const u8 mode )
{
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( drive - > hwif - > dev ) ;
2007-10-17 00:29:52 +04:00
u16 t1 = 0 ;
u8 drive_pci = 0x40 + drive - > dn * 2 ;
const u16 pio_timings [ ] = { 0x000 , 0x607 , 0x404 , 0x303 , 0x301 } ;
const u16 mwdma_timings [ ] = { 0x008 , 0x302 , 0x301 } ;
pci_read_config_word ( dev , drive_pci , & t1 ) ;
/* clear active/recovery timings */
t1 & = ~ 0x070f ;
if ( mode > = XFER_MW_DMA_0 ) {
if ( chipset_family > ATA_16 )
t1 & = ~ 0x8000 ; /* disable UDMA */
t1 | = mwdma_timings [ mode - XFER_MW_DMA_0 ] ;
} else
t1 | = pio_timings [ mode - XFER_PIO_0 ] ;
pci_write_config_word ( dev , drive_pci , t1 ) ;
}
static void sis_ata100_program_timings ( ide_drive_t * drive , const u8 mode )
{
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( drive - > hwif - > dev ) ;
2007-10-17 00:29:52 +04:00
u8 t1 , drive_pci = 0x40 + drive - > dn * 2 ;
/* timing bits: 7:4 active 3:0 recovery */
const u8 pio_timings [ ] = { 0x00 , 0x67 , 0x44 , 0x33 , 0x31 } ;
const u8 mwdma_timings [ ] = { 0x08 , 0x32 , 0x31 } ;
if ( mode > = XFER_MW_DMA_0 ) {
u8 t2 = 0 ;
pci_read_config_byte ( dev , drive_pci , & t2 ) ;
t2 & = ~ 0x80 ; /* disable UDMA */
pci_write_config_byte ( dev , drive_pci , t2 ) ;
t1 = mwdma_timings [ mode - XFER_MW_DMA_0 ] ;
} else
t1 = pio_timings [ mode - XFER_PIO_0 ] ;
pci_write_config_byte ( dev , drive_pci + 1 , t1 ) ;
}
static void sis_ata133_program_timings ( ide_drive_t * drive , const u8 mode )
{
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( drive - > hwif - > dev ) ;
2007-10-17 00:29:52 +04:00
u32 t1 = 0 ;
u8 drive_pci = sis_ata133_get_base ( drive ) , clk , idx ;
pci_read_config_dword ( dev , drive_pci , & t1 ) ;
t1 & = 0xc0c00fff ;
clk = ( t1 & 0x08 ) ? ATA_133 : ATA_100 ;
if ( mode > = XFER_MW_DMA_0 ) {
t1 & = ~ 0x04 ; /* disable UDMA */
idx = mode - XFER_MW_DMA_0 + 5 ;
2007-10-20 02:32:29 +04:00
} else
2007-10-17 00:29:52 +04:00
idx = mode - XFER_PIO_0 ;
t1 | = ini_time_value [ clk ] [ idx ] < < 12 ;
t1 | = act_time_value [ clk ] [ idx ] < < 16 ;
t1 | = rco_time_value [ clk ] [ idx ] < < 24 ;
pci_write_config_dword ( dev , drive_pci , t1 ) ;
}
static void sis_program_timings ( ide_drive_t * drive , const u8 mode )
{
if ( chipset_family < ATA_100 ) /* ATA_16/33/66/100a */
sis_ata16_program_timings ( drive , mode ) ;
else if ( chipset_family < ATA_133 ) /* ATA_100/133a */
sis_ata100_program_timings ( drive , mode ) ;
else /* ATA_133 */
sis_ata133_program_timings ( drive , mode ) ;
}
2008-04-26 19:36:39 +04:00
static void config_drive_art_rwp ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2009-01-06 19:20:52 +03:00
ide_hwif_t * hwif = drive - > hwif ;
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( hwif - > dev ) ;
2005-04-17 02:20:36 +04:00
u8 reg4bh = 0 ;
2007-10-17 00:29:56 +04:00
u8 rw_prefetch = 0 ;
2005-04-17 02:20:36 +04:00
pci_read_config_byte ( dev , 0x4b , & reg4bh ) ;
2009-10-06 18:46:05 +04:00
rw_prefetch = reg4bh & ~ ( 0x11 < < drive - > dn ) ;
2007-10-17 00:29:56 +04:00
if ( drive - > media = = ide_disk )
2009-10-06 18:46:05 +04:00
rw_prefetch | = 0x11 < < drive - > dn ;
2007-10-17 00:29:56 +04:00
2009-10-06 18:46:05 +04:00
if ( reg4bh ! = rw_prefetch )
pci_write_config_byte ( dev , 0x4b , rw_prefetch ) ;
2005-04-17 02:20:36 +04:00
}
2010-01-19 12:44:41 +03:00
static void sis_set_pio_mode ( ide_hwif_t * hwif , ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
config_drive_art_rwp ( drive ) ;
2010-01-19 12:44:41 +03:00
sis_program_timings ( drive , drive - > pio_mode ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 00:17:18 +03:00
static void sis_ata133_program_udma_timings ( ide_drive_t * drive , const u8 mode )
2005-04-17 02:20:36 +04:00
{
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( drive - > hwif - > dev ) ;
2008-01-26 00:17:18 +03:00
u32 regdw = 0 ;
u8 drive_pci = sis_ata133_get_base ( drive ) , clk , idx ;
pci_read_config_dword ( dev , drive_pci , & regdw ) ;
regdw | = 0x04 ;
regdw & = 0xfffff00f ;
/* check if ATA133 enable */
clk = ( regdw & 0x08 ) ? ATA_133 : ATA_100 ;
idx = mode - XFER_UDMA_0 ;
regdw | = cycle_time_value [ clk ] [ idx ] < < 4 ;
regdw | = cvs_time_value [ clk ] [ idx ] < < 8 ;
pci_write_config_dword ( dev , drive_pci , regdw ) ;
}
static void sis_ata33_program_udma_timings ( ide_drive_t * drive , const u8 mode )
{
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( drive - > hwif - > dev ) ;
2008-01-26 00:17:18 +03:00
u8 drive_pci = 0x40 + drive - > dn * 2 , reg = 0 , i = chipset_family ;
pci_read_config_byte ( dev , drive_pci + 1 , & reg ) ;
/* force the UDMA bit on if we want to use UDMA */
reg | = 0x80 ;
/* clean reg cycle time bits */
reg & = ~ ( ( 0xff > > ( 8 - cycle_time_range [ i ] ) ) < < cycle_time_offset [ i ] ) ;
/* set reg cycle time bits */
reg | = cycle_time_value [ i ] [ mode - XFER_UDMA_0 ] < < cycle_time_offset [ i ] ;
pci_write_config_byte ( dev , drive_pci + 1 , reg ) ;
}
2005-04-17 02:20:36 +04:00
2008-01-26 00:17:18 +03:00
static void sis_program_udma_timings ( ide_drive_t * drive , const u8 mode )
{
if ( chipset_family > = ATA_133 ) /* ATA_133 */
sis_ata133_program_udma_timings ( drive , mode ) ;
else /* ATA_33/66/100a/100/133a */
sis_ata33_program_udma_timings ( drive , mode ) ;
}
2010-01-19 12:45:29 +03:00
static void sis_set_dma_mode ( ide_hwif_t * hwif , ide_drive_t * drive )
2008-01-26 00:17:18 +03:00
{
2010-01-19 12:45:29 +03:00
const u8 speed = drive - > dma_mode ;
2008-01-26 00:17:18 +03:00
if ( speed > = XFER_UDMA_0 )
sis_program_udma_timings ( drive , speed ) ;
else
sis_program_timings ( drive , speed ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-27 00:25:14 +04:00
static u8 sis_ata133_udma_filter ( ide_drive_t * drive )
2007-10-12 01:53:59 +04:00
{
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( drive - > hwif - > dev ) ;
2007-10-17 00:29:52 +04:00
u32 regdw = 0 ;
u8 drive_pci = sis_ata133_get_base ( drive ) ;
2007-10-12 01:53:59 +04:00
pci_read_config_dword ( dev , drive_pci , & regdw ) ;
/* if ATA133 disable, we should not set speed above UDMA5 */
return ( regdw & 0x08 ) ? ATA_UDMA6 : ATA_UDMA5 ;
}
2012-12-22 01:21:03 +04:00
static int sis_find_family ( struct pci_dev * dev )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * host ;
int i = 0 ;
chipset_family = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( SiSHostChipInfo ) & & ! chipset_family ; i + + ) {
2006-10-01 10:27:30 +04:00
host = pci_get_device ( PCI_VENDOR_ID_SI , SiSHostChipInfo [ i ] . host_id , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! host )
continue ;
chipset_family = SiSHostChipInfo [ i ] . chipset_family ;
/* Special case for SiS630 : 630S/ET is ATA_100a */
if ( SiSHostChipInfo [ i ] . host_id = = PCI_DEVICE_ID_SI_630 ) {
2007-06-09 02:46:36 +04:00
if ( host - > revision > = 0x30 )
2005-04-17 02:20:36 +04:00
chipset_family = ATA_100a ;
}
2006-10-01 10:27:30 +04:00
pci_dev_put ( host ) ;
2008-04-26 19:36:39 +04:00
2008-07-25 00:53:32 +04:00
printk ( KERN_INFO DRV_NAME " %s: %s %s controller \n " ,
2008-07-25 00:53:31 +04:00
pci_name ( dev ) , SiSHostChipInfo [ i ] . name ,
chipset_capability [ chipset_family ] ) ;
2005-04-17 02:20:36 +04:00
}
if ( ! chipset_family ) { /* Belongs to pci-quirks */
u32 idemisc ;
u16 trueid ;
/* Disable ID masking and register remapping */
pci_read_config_dword ( dev , 0x54 , & idemisc ) ;
pci_write_config_dword ( dev , 0x54 , ( idemisc & 0x7fffffff ) ) ;
pci_read_config_word ( dev , PCI_DEVICE_ID , & trueid ) ;
pci_write_config_dword ( dev , 0x54 , idemisc ) ;
if ( trueid = = 0x5518 ) {
2008-07-25 00:53:32 +04:00
printk ( KERN_INFO DRV_NAME " %s: SiS 962/963 MuTIOL IDE UDMA133 controller \n " ,
2008-07-25 00:53:31 +04:00
pci_name ( dev ) ) ;
2005-04-17 02:20:36 +04:00
chipset_family = ATA_133 ;
2011-03-31 05:57:33 +04:00
/* Check for 5513 compatibility mapping
2005-04-17 02:20:36 +04:00
* We must use this , else the port enabled code will fail ,
* as it expects the enablebits at 0x4a .
*/
if ( ( idemisc & 0x40000000 ) = = 0 ) {
pci_write_config_dword ( dev , 0x54 , idemisc | 0x40000000 ) ;
2008-07-25 00:53:32 +04:00
printk ( KERN_INFO DRV_NAME " %s: Switching to 5513 register mapping \n " ,
2008-07-25 00:53:31 +04:00
pci_name ( dev ) ) ;
2005-04-17 02:20:36 +04:00
}
}
}
if ( ! chipset_family ) { /* Belongs to pci-quirks */
struct pci_dev * lpc_bridge ;
u16 trueid ;
u8 prefctl ;
u8 idecfg ;
pci_read_config_byte ( dev , 0x4a , & idecfg ) ;
pci_write_config_byte ( dev , 0x4a , idecfg | 0x10 ) ;
pci_read_config_word ( dev , PCI_DEVICE_ID , & trueid ) ;
pci_write_config_byte ( dev , 0x4a , idecfg ) ;
if ( trueid = = 0x5517 ) { /* SiS 961/961B */
2006-12-08 13:39:58 +03:00
lpc_bridge = pci_get_slot ( dev - > bus , 0x10 ) ; /* Bus 0, Dev 2, Fn 0 */
2005-04-17 02:20:36 +04:00
pci_read_config_byte ( dev , 0x49 , & prefctl ) ;
2006-12-08 13:39:58 +03:00
pci_dev_put ( lpc_bridge ) ;
2005-04-17 02:20:36 +04:00
2007-06-09 02:46:36 +04:00
if ( lpc_bridge - > revision = = 0x10 & & ( prefctl & 0x80 ) ) {
2008-07-25 00:53:32 +04:00
printk ( KERN_INFO DRV_NAME " %s: SiS 961B MuTIOL IDE UDMA133 controller \n " ,
2008-07-25 00:53:31 +04:00
pci_name ( dev ) ) ;
2005-04-17 02:20:36 +04:00
chipset_family = ATA_133a ;
} else {
2008-07-25 00:53:32 +04:00
printk ( KERN_INFO DRV_NAME " %s: SiS 961 MuTIOL IDE UDMA100 controller \n " ,
2008-07-25 00:53:31 +04:00
pci_name ( dev ) ) ;
2005-04-17 02:20:36 +04:00
chipset_family = ATA_100 ;
}
}
}
2008-04-26 19:36:43 +04:00
return chipset_family ;
}
2005-04-17 02:20:36 +04:00
2009-03-25 01:22:53 +03:00
static int init_chipset_sis5513 ( struct pci_dev * dev )
2008-04-26 19:36:43 +04:00
{
2005-04-17 02:20:36 +04:00
/* Make general config ops here
1 / tell IDE channels to operate in Compatibility mode only
2 / tell old chips to allow per drive IDE timings */
2008-04-26 19:36:39 +04:00
u8 reg ;
u16 regw ;
switch ( chipset_family ) {
case ATA_133 :
/* SiS962 operation mode */
pci_read_config_word ( dev , 0x50 , & regw ) ;
if ( regw & 0x08 )
pci_write_config_word ( dev , 0x50 , regw & 0xfff7 ) ;
pci_read_config_word ( dev , 0x52 , & regw ) ;
if ( regw & 0x08 )
pci_write_config_word ( dev , 0x52 , regw & 0xfff7 ) ;
break ;
case ATA_133a :
case ATA_100 :
/* Fixup latency */
pci_write_config_byte ( dev , PCI_LATENCY_TIMER , 0x80 ) ;
/* Set compatibility bit */
pci_read_config_byte ( dev , 0x49 , & reg ) ;
if ( ! ( reg & 0x01 ) )
pci_write_config_byte ( dev , 0x49 , reg | 0x01 ) ;
break ;
case ATA_100a :
case ATA_66 :
/* Fixup latency */
pci_write_config_byte ( dev , PCI_LATENCY_TIMER , 0x10 ) ;
/* On ATA_66 chips the bit was elsewhere */
pci_read_config_byte ( dev , 0x52 , & reg ) ;
if ( ! ( reg & 0x04 ) )
pci_write_config_byte ( dev , 0x52 , reg | 0x04 ) ;
break ;
case ATA_33 :
/* On ATA_33 we didn't have a single bit to set */
pci_read_config_byte ( dev , 0x09 , & reg ) ;
if ( ( reg & 0x0f ) ! = 0x00 )
pci_write_config_byte ( dev , 0x09 , reg & 0xf0 ) ;
case ATA_16 :
/* force per drive recovery and active timings
needed on ATA_33 and below chips */
pci_read_config_byte ( dev , 0x52 , & reg ) ;
if ( ! ( reg & 0x08 ) )
pci_write_config_byte ( dev , 0x52 , reg | 0x08 ) ;
break ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-10 01:17:58 +04:00
struct sis_laptop {
u16 device ;
u16 subvendor ;
u16 subdevice ;
} ;
static const struct sis_laptop sis_laptop [ ] = {
/* devid, subvendor, subdev */
{ 0x5513 , 0x1043 , 0x1107 } , /* ASUS A6K */
2007-08-02 01:46:44 +04:00
{ 0x5513 , 0x1734 , 0x105f } , /* FSC Amilo A1630 */
2007-11-27 23:35:52 +03:00
{ 0x5513 , 0x1071 , 0x8640 } , /* EasyNote K5305 */
2007-07-10 01:17:58 +04:00
/* end marker */
{ 0 , }
} ;
2008-08-05 20:17:04 +04:00
static u8 sis_cable_detect ( ide_hwif_t * hwif )
2005-04-17 02:20:36 +04:00
{
2008-02-02 01:09:31 +03:00
struct pci_dev * pdev = to_pci_dev ( hwif - > dev ) ;
2007-07-10 01:17:58 +04:00
const struct sis_laptop * lap = & sis_laptop [ 0 ] ;
2005-04-17 02:20:36 +04:00
u8 ata66 = 0 ;
2007-07-10 01:17:58 +04:00
while ( lap - > device ) {
if ( lap - > device = = pdev - > device & &
lap - > subvendor = = pdev - > subsystem_vendor & &
lap - > subdevice = = pdev - > subsystem_device )
return ATA_CBL_PATA40_SHORT ;
lap + + ;
}
2005-04-17 02:20:36 +04:00
if ( chipset_family > = ATA_133 ) {
u16 regw = 0 ;
u16 reg_addr = hwif - > channel ? 0x52 : 0x50 ;
2008-02-02 01:09:31 +03:00
pci_read_config_word ( pdev , reg_addr , & regw ) ;
2005-04-17 02:20:36 +04:00
ata66 = ( regw & 0x8000 ) ? 0 : 1 ;
} else if ( chipset_family > = ATA_66 ) {
u8 reg48h = 0 ;
u8 mask = hwif - > channel ? 0x20 : 0x10 ;
2008-02-02 01:09:31 +03:00
pci_read_config_byte ( pdev , 0x48 , & reg48h ) ;
2005-04-17 02:20:36 +04:00
ata66 = ( reg48h & mask ) ? 0 : 1 ;
}
2007-07-10 01:17:58 +04:00
return ata66 ? ATA_CBL_PATA80 : ATA_CBL_PATA40 ;
2005-04-17 02:20:36 +04:00
}
2008-04-27 00:25:14 +04:00
static const struct ide_port_ops sis_port_ops = {
. set_pio_mode = sis_set_pio_mode ,
. set_dma_mode = sis_set_dma_mode ,
. cable_detect = sis_cable_detect ,
} ;
2007-10-12 01:53:59 +04:00
2008-04-27 00:25:14 +04:00
static const struct ide_port_ops sis_ata133_port_ops = {
. set_pio_mode = sis_set_pio_mode ,
. set_dma_mode = sis_set_dma_mode ,
. udma_filter = sis_ata133_udma_filter ,
. cable_detect = sis_cable_detect ,
} ;
2005-04-17 02:20:36 +04:00
2012-12-22 01:21:03 +04:00
static const struct ide_port_info sis5513_chipset = {
2008-07-25 00:53:32 +04:00
. name = DRV_NAME ,
2005-04-17 02:20:36 +04:00
. init_chipset = init_chipset_sis5513 ,
2008-04-26 19:36:39 +04:00
. enablebits = { { 0x4a , 0x02 , 0x02 } , { 0x4a , 0x04 , 0x04 } } ,
2009-03-25 01:22:52 +03:00
. host_flags = IDE_HFLAG_NO_AUTODMA ,
2007-07-20 03:11:59 +04:00
. pio_mask = ATA_PIO4 ,
2007-10-19 02:30:07 +04:00
. mwdma_mask = ATA_MWDMA2 ,
2005-04-17 02:20:36 +04:00
} ;
2012-12-22 01:21:03 +04:00
static int sis5513_init_one ( struct pci_dev * dev , const struct pci_device_id * id )
2005-04-17 02:20:36 +04:00
{
2008-04-26 19:36:43 +04:00
struct ide_port_info d = sis5513_chipset ;
u8 udma_rates [ ] = { 0x00 , 0x00 , 0x07 , 0x1f , 0x3f , 0x3f , 0x7f , 0x7f } ;
2008-06-10 22:56:36 +04:00
int rc ;
rc = pci_enable_device ( dev ) ;
if ( rc )
return rc ;
2008-04-26 19:36:43 +04:00
if ( sis_find_family ( dev ) = = 0 )
return - ENOTSUPP ;
2008-04-27 00:25:14 +04:00
if ( chipset_family > = ATA_133 )
d . port_ops = & sis_ata133_port_ops ;
else
d . port_ops = & sis_port_ops ;
2008-04-26 19:36:43 +04:00
d . udma_mask = udma_rates [ chipset_family ] ;
2008-07-25 00:53:14 +04:00
return ide_pci_init_one ( dev , & d , NULL ) ;
2005-04-17 02:20:36 +04:00
}
2012-12-22 01:21:03 +04:00
static void sis5513_remove ( struct pci_dev * dev )
2008-07-25 00:53:25 +04:00
{
ide_pci_remove ( dev ) ;
pci_disable_device ( dev ) ;
}
2007-10-17 00:29:56 +04:00
static const struct pci_device_id sis5513_pci_tbl [ ] = {
{ PCI_VDEVICE ( SI , PCI_DEVICE_ID_SI_5513 ) , 0 } ,
{ PCI_VDEVICE ( SI , PCI_DEVICE_ID_SI_5518 ) , 0 } ,
{ PCI_VDEVICE ( SI , PCI_DEVICE_ID_SI_1180 ) , 0 } ,
2005-04-17 02:20:36 +04:00
{ 0 , } ,
} ;
MODULE_DEVICE_TABLE ( pci , sis5513_pci_tbl ) ;
2008-10-13 23:39:41 +04:00
static struct pci_driver sis5513_pci_driver = {
2005-04-17 02:20:36 +04:00
. name = " SIS_IDE " ,
. id_table = sis5513_pci_tbl ,
. probe = sis5513_init_one ,
2012-12-22 01:21:03 +04:00
. remove = sis5513_remove ,
2008-10-11 00:39:32 +04:00
. suspend = ide_pci_suspend ,
. resume = ide_pci_resume ,
2005-04-17 02:20:36 +04:00
} ;
2007-01-27 15:46:56 +03:00
static int __init sis5513_ide_init ( void )
2005-04-17 02:20:36 +04:00
{
2008-10-13 23:39:41 +04:00
return ide_pci_register_driver ( & sis5513_pci_driver ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-25 00:53:25 +04:00
static void __exit sis5513_ide_exit ( void )
{
2008-10-13 23:39:41 +04:00
pci_unregister_driver ( & sis5513_pci_driver ) ;
2008-07-25 00:53:25 +04:00
}
2005-04-17 02:20:36 +04:00
module_init ( sis5513_ide_init ) ;
2008-07-25 00:53:25 +04:00
module_exit ( sis5513_ide_exit ) ;
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik " ) ;
MODULE_DESCRIPTION ( " PCI driver module for SIS IDE " ) ;
MODULE_LICENSE ( " GPL " ) ;