2006-08-30 02:12:40 +04:00
/*
* pata_sil680 . c - SIL680 PATA for new ATA layer
* ( C ) 2005 Red Hat Inc
*
* based upon
*
* linux / drivers / ide / pci / siimage . c Version 1.07 Nov 30 , 2003
*
* Copyright ( C ) 2001 - 2002 Andre Hedrick < andre @ linux - ide . org >
* Copyright ( C ) 2003 Red Hat < alan @ redhat . com >
*
* May be copied or modified under the terms of the GNU General Public License
*
2011-03-31 05:57:33 +04:00
* Documentation publicly available .
2006-08-30 02:12:40 +04:00
*
* If you have strange problems with nVidia chipset systems please
* see the SI support documentation and update your system BIOS
2007-10-20 01:10:43 +04:00
* if necessary
2006-08-30 02:12:40 +04:00
*
* TODO
* If we know all our devices are LBA28 ( or LBA28 sized ) we could use
* the command fifo mode .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/blkdev.h>
# include <linux/delay.h>
# include <scsi/scsi_host.h>
# include <linux/libata.h>
# define DRV_NAME "pata_sil680"
2009-01-05 17:16:39 +03:00
# define DRV_VERSION "0.4.9"
2006-08-30 02:12:40 +04:00
2007-05-28 15:22:30 +04:00
# define SIL680_MMIO_BAR 5
2006-08-30 02:12:40 +04:00
/**
* sil680_selreg - return register base
2011-10-11 22:17:05 +04:00
* @ ap : ATA interface
2006-08-30 02:12:40 +04:00
* @ r : config offset
*
2011-10-11 22:17:05 +04:00
* Turn a config register offset into the right address in PCI space
* to access the control register in question .
*
2011-03-31 05:57:33 +04:00
* Thankfully this is a configuration operation so isn ' t performance
2006-08-30 02:12:40 +04:00
* criticial .
*/
2022-04-12 20:26:46 +03:00
static int sil680_selreg ( struct ata_port * ap , int r )
2006-08-30 02:12:40 +04:00
{
2022-04-12 20:26:46 +03:00
return 0xA0 + ( ap - > port_no < < 4 ) + r ;
2006-08-30 02:12:40 +04:00
}
/**
* sil680_seldev - return register base
2011-10-11 22:17:05 +04:00
* @ ap : ATA interface
2021-03-18 11:51:37 +03:00
* @ adev : ATA device
2006-08-30 02:12:40 +04:00
* @ r : config offset
*
2011-10-11 22:17:05 +04:00
* Turn a config register offset into the right address in PCI space
* to access the control register in question including accounting for
* the unit shift .
2006-08-30 02:12:40 +04:00
*/
2022-04-12 20:26:46 +03:00
static int sil680_seldev ( struct ata_port * ap , struct ata_device * adev , int r )
2006-08-30 02:12:40 +04:00
{
2022-04-12 20:26:46 +03:00
return 0xA0 + ( ap - > port_no < < 4 ) + r + ( adev - > devno < < 1 ) ;
2006-08-30 02:12:40 +04:00
}
/**
* sil680_cable_detect - cable detection
* @ ap : ATA port
*
* Perform cable detection . The SIL680 stores this in PCI config
* space for us .
*/
2011-10-11 22:21:50 +04:00
static int sil680_cable_detect ( struct ata_port * ap )
{
2006-08-30 02:12:40 +04:00
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2022-04-12 20:26:46 +03:00
int addr = sil680_selreg ( ap , 0 ) ;
2006-08-30 02:12:40 +04:00
u8 ata66 ;
2022-04-12 20:26:46 +03:00
2006-08-30 02:12:40 +04:00
pci_read_config_byte ( pdev , addr , & ata66 ) ;
if ( ata66 & 1 )
return ATA_CBL_PATA80 ;
else
return ATA_CBL_PATA40 ;
}
/**
2011-10-11 22:17:05 +04:00
* sil680_set_piomode - set PIO mode data
2006-08-30 02:12:40 +04:00
* @ ap : ATA interface
* @ adev : ATA device
*
* Program the SIL680 registers for PIO mode . Note that the task speed
* registers are shared between the devices so we must pick the lowest
* mode for command work .
*/
static void sil680_set_piomode ( struct ata_port * ap , struct ata_device * adev )
{
2011-10-11 22:20:28 +04:00
static const u16 speed_p [ 5 ] = {
0x328A , 0x2283 , 0x1104 , 0x10C3 , 0x10C1
} ;
static const u16 speed_t [ 5 ] = {
0x328A , 0x2283 , 0x1281 , 0x10C3 , 0x10C1
} ;
2006-08-30 02:12:40 +04:00
2022-04-12 20:26:46 +03:00
int tfaddr = sil680_selreg ( ap , 0x02 ) ;
int addr = sil680_seldev ( ap , adev , 0x04 ) ;
int addr_mask = 0x80 + 4 * ap - > port_no ;
2006-08-30 02:12:40 +04:00
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
int pio = adev - > pio_mode - XFER_PIO_0 ;
int lowest_pio = pio ;
2007-02-20 20:49:25 +03:00
int port_shift = 4 * adev - > devno ;
2006-08-30 02:12:40 +04:00
u16 reg ;
2007-02-20 20:49:25 +03:00
u8 mode ;
2006-08-30 02:12:40 +04:00
struct ata_device * pair = ata_dev_pair ( adev ) ;
if ( pair ! = NULL & & adev - > pio_mode > pair - > pio_mode )
lowest_pio = pair - > pio_mode - XFER_PIO_0 ;
pci_write_config_word ( pdev , addr , speed_p [ pio ] ) ;
pci_write_config_word ( pdev , tfaddr , speed_t [ lowest_pio ] ) ;
pci_read_config_word ( pdev , tfaddr - 2 , & reg ) ;
2007-02-20 20:49:25 +03:00
pci_read_config_byte ( pdev , addr_mask , & mode ) ;
2007-02-26 13:51:33 +03:00
2006-08-30 02:12:40 +04:00
reg & = ~ 0x0200 ; /* Clear IORDY */
2007-02-20 20:49:25 +03:00
mode & = ~ ( 3 < < port_shift ) ; /* Clear IORDY and DMA bits */
2007-02-26 13:51:33 +03:00
2007-02-20 20:49:25 +03:00
if ( ata_pio_need_iordy ( adev ) ) {
2006-08-30 02:12:40 +04:00
reg | = 0x0200 ; /* Enable IORDY */
2007-02-20 20:49:25 +03:00
mode | = 1 < < port_shift ;
}
2006-08-30 02:12:40 +04:00
pci_write_config_word ( pdev , tfaddr - 2 , reg ) ;
2007-02-20 20:49:25 +03:00
pci_write_config_byte ( pdev , addr_mask , mode ) ;
2006-08-30 02:12:40 +04:00
}
/**
2011-10-11 22:17:05 +04:00
* sil680_set_dmamode - set DMA mode data
2006-08-30 02:12:40 +04:00
* @ ap : ATA interface
* @ adev : ATA device
*
2011-10-11 22:17:05 +04:00
* Program the MWDMA / UDMA modes for the sil680 chipset .
*
* The MWDMA mode values are pulled from a lookup table
2006-08-30 02:12:40 +04:00
* while the chipset uses mode number for UDMA .
*/
static void sil680_set_dmamode ( struct ata_port * ap , struct ata_device * adev )
{
2011-10-11 22:20:28 +04:00
static const u8 ultra_table [ 2 ] [ 7 ] = {
2006-08-30 02:12:40 +04:00
{ 0x0C , 0x07 , 0x05 , 0x04 , 0x02 , 0x01 , 0xFF } , /* 100MHz */
{ 0x0F , 0x0B , 0x07 , 0x05 , 0x03 , 0x02 , 0x01 } , /* 133Mhz */
} ;
2011-10-11 22:20:28 +04:00
static const u16 dma_table [ 3 ] = { 0x2208 , 0x10C2 , 0x10C1 } ;
2006-08-30 02:12:40 +04:00
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2022-04-12 20:26:46 +03:00
int ma = sil680_seldev ( ap , adev , 0x08 ) ;
int ua = sil680_seldev ( ap , adev , 0x0C ) ;
int addr_mask = 0x80 + 4 * ap - > port_no ;
2006-08-30 02:12:40 +04:00
int port_shift = adev - > devno * 4 ;
u8 scsc , mode ;
u16 multi , ultra ;
pci_read_config_byte ( pdev , 0x8A , & scsc ) ;
pci_read_config_byte ( pdev , addr_mask , & mode ) ;
pci_read_config_word ( pdev , ma , & multi ) ;
pci_read_config_word ( pdev , ua , & ultra ) ;
/* Mask timing bits */
ultra & = ~ 0x3F ;
mode & = ~ ( 0x03 < < port_shift ) ;
/* Extract scsc */
2011-10-11 22:21:50 +04:00
scsc = ( scsc & 0x30 ) ? 1 : 0 ;
2006-08-30 02:12:40 +04:00
if ( adev - > dma_mode > = XFER_UDMA_0 ) {
multi = 0x10C1 ;
ultra | = ultra_table [ scsc ] [ adev - > dma_mode - XFER_UDMA_0 ] ;
mode | = ( 0x03 < < port_shift ) ;
} else {
multi = dma_table [ adev - > dma_mode - XFER_MW_DMA_0 ] ;
mode | = ( 0x02 < < port_shift ) ;
}
pci_write_config_byte ( pdev , addr_mask , mode ) ;
pci_write_config_word ( pdev , ma , multi ) ;
pci_write_config_word ( pdev , ua , ultra ) ;
}
2010-05-05 13:25:58 +04:00
/**
* sil680_sff_exec_command - issue ATA command to host controller
* @ ap : port to which command is being issued
* @ tf : ATA taskfile register set
*
* Issues ATA command , with proper synchronization with interrupt
* handler / other threads . Use our MMIO space for PCI posting to avoid
* a hideously slow cycle all the way to the device .
*
* LOCKING :
* spin_lock_irqsave ( host lock )
*/
2010-10-05 20:31:47 +04:00
static void sil680_sff_exec_command ( struct ata_port * ap ,
const struct ata_taskfile * tf )
2010-05-05 13:25:58 +04:00
{
iowrite8 ( tf - > command , ap - > ioaddr . command_addr ) ;
ioread8 ( ap - > ioaddr . bmdma_addr + ATA_DMA_CMD ) ;
}
2010-10-08 19:01:08 +04:00
static bool sil680_sff_irq_check ( struct ata_port * ap )
{
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2022-04-12 20:26:46 +03:00
int addr = sil680_selreg ( ap , 1 ) ;
2010-10-08 19:01:08 +04:00
u8 val ;
pci_read_config_byte ( pdev , addr , & val ) ;
return val & 0x08 ;
}
2023-03-22 22:53:59 +03:00
static const struct scsi_host_template sil680_sht = {
2008-03-25 06:22:49 +03:00
ATA_BMDMA_SHT ( DRV_NAME ) ,
2006-08-30 02:12:40 +04:00
} ;
2010-05-05 13:25:58 +04:00
2006-08-30 02:12:40 +04:00
static struct ata_port_operations sil680_port_ops = {
2010-05-05 13:25:58 +04:00
. inherits = & ata_bmdma32_port_ops ,
. sff_exec_command = sil680_sff_exec_command ,
2010-10-08 19:01:08 +04:00
. sff_irq_check = sil680_sff_irq_check ,
2010-05-05 13:25:58 +04:00
. cable_detect = sil680_cable_detect ,
. set_piomode = sil680_set_piomode ,
. set_dmamode = sil680_set_dmamode ,
2006-08-30 02:12:40 +04:00
} ;
2006-11-22 20:28:41 +03:00
/**
* sil680_init_chip - chip setup
* @ pdev : PCI device
2021-03-18 11:51:37 +03:00
* @ try_mmio : Indicates to caller whether MMIO should be attempted
2006-11-22 20:28:41 +03:00
*
* Perform all the chip setup which must be done both when the device
* is powered up on boot and when we resume in case we resumed from RAM .
* Returns the final clock settings .
*/
2006-12-11 19:14:06 +03:00
2007-07-07 03:21:22 +04:00
static u8 sil680_init_chip ( struct pci_dev * pdev , int * try_mmio )
2006-08-30 02:12:40 +04:00
{
u8 tmpbyte = 0 ;
2011-10-11 22:21:50 +04:00
/* FIXME: double check */
2009-11-24 21:54:49 +03:00
pci_write_config_byte ( pdev , PCI_CACHE_LINE_SIZE ,
pdev - > revision ? 1 : 255 ) ;
2006-08-30 02:12:40 +04:00
pci_write_config_byte ( pdev , 0x80 , 0x00 ) ;
pci_write_config_byte ( pdev , 0x84 , 0x00 ) ;
pci_read_config_byte ( pdev , 0x8A , & tmpbyte ) ;
2007-05-28 15:22:30 +04:00
dev_dbg ( & pdev - > dev , " sil680: BA5_EN = %d clock = %02X \n " ,
tmpbyte & 1 , tmpbyte & 0x30 ) ;
2006-08-30 02:12:40 +04:00
2008-03-29 00:52:29 +03:00
* try_mmio = 0 ;
2008-09-23 01:47:33 +04:00
# ifdef CONFIG_PPC
2008-03-29 00:52:29 +03:00
if ( machine_is ( cell ) )
* try_mmio = ( tmpbyte & 1 ) | | pci_resource_start ( pdev , 5 ) ;
# endif
2007-07-07 03:21:22 +04:00
2011-10-11 22:21:50 +04:00
switch ( tmpbyte & 0x30 ) {
case 0x00 :
/* 133 clock attempt to force it on */
pci_write_config_byte ( pdev , 0x8A , tmpbyte | 0x10 ) ;
break ;
case 0x30 :
/* if clocking is disabled */
/* 133 clock attempt to force it on */
pci_write_config_byte ( pdev , 0x8A , tmpbyte & ~ 0x20 ) ;
break ;
case 0x10 :
/* 133 already */
break ;
case 0x20 :
/* BIOS set PCI x2 clocking */
break ;
2006-08-30 02:12:40 +04:00
}
pci_read_config_byte ( pdev , 0x8A , & tmpbyte ) ;
2007-05-28 15:22:30 +04:00
dev_dbg ( & pdev - > dev , " sil680: BA5_EN = %d clock = %02X \n " ,
tmpbyte & 1 , tmpbyte & 0x30 ) ;
2006-08-30 02:12:40 +04:00
pci_write_config_byte ( pdev , 0xA1 , 0x72 ) ;
pci_write_config_word ( pdev , 0xA2 , 0x328A ) ;
pci_write_config_dword ( pdev , 0xA4 , 0x62DD62DD ) ;
pci_write_config_dword ( pdev , 0xA8 , 0x43924392 ) ;
pci_write_config_dword ( pdev , 0xAC , 0x40094009 ) ;
pci_write_config_byte ( pdev , 0xB1 , 0x72 ) ;
pci_write_config_word ( pdev , 0xB2 , 0x328A ) ;
pci_write_config_dword ( pdev , 0xB4 , 0x62DD62DD ) ;
pci_write_config_dword ( pdev , 0xB8 , 0x43924392 ) ;
pci_write_config_dword ( pdev , 0xBC , 0x40094009 ) ;
2011-10-11 22:21:50 +04:00
switch ( tmpbyte & 0x30 ) {
case 0x00 :
2021-12-21 10:21:20 +03:00
dev_info ( & pdev - > dev , " sil680: 100MHz clock. \n " ) ;
2011-10-11 22:21:50 +04:00
break ;
case 0x10 :
2021-12-21 10:21:20 +03:00
dev_info ( & pdev - > dev , " sil680: 133MHz clock. \n " ) ;
2011-10-11 22:21:50 +04:00
break ;
case 0x20 :
2021-12-21 10:21:20 +03:00
dev_info ( & pdev - > dev , " sil680: Using PCI clock. \n " ) ;
2011-10-11 22:21:50 +04:00
break ;
/* This last case is _NOT_ ok */
case 0x30 :
2021-12-21 10:21:20 +03:00
dev_err ( & pdev - > dev , " sil680: Clock disabled ? \n " ) ;
2006-11-22 20:28:41 +03:00
}
return tmpbyte & 0x30 ;
}
2012-12-22 01:19:58 +04:00
static int sil680_init_one ( struct pci_dev * pdev , const struct pci_device_id * id )
2006-11-22 20:28:41 +03:00
{
2007-05-04 14:43:58 +04:00
static const struct ata_port_info info = {
2007-05-28 14:59:48 +04:00
. flags = ATA_FLAG_SLAVE_POSS ,
2009-03-14 23:38:24 +03:00
. pio_mask = ATA_PIO4 ,
. mwdma_mask = ATA_MWDMA2 ,
2007-07-09 20:16:50 +04:00
. udma_mask = ATA_UDMA6 ,
2006-11-22 20:28:41 +03:00
. port_ops = & sil680_port_ops
} ;
2007-05-04 14:43:58 +04:00
static const struct ata_port_info info_slow = {
2007-05-28 14:59:48 +04:00
. flags = ATA_FLAG_SLAVE_POSS ,
2009-03-14 23:38:24 +03:00
. pio_mask = ATA_PIO4 ,
. mwdma_mask = ATA_MWDMA2 ,
2007-07-09 20:16:50 +04:00
. udma_mask = ATA_UDMA5 ,
2006-11-22 20:28:41 +03:00
. port_ops = & sil680_port_ops
} ;
2007-05-04 14:43:58 +04:00
const struct ata_port_info * ppi [ ] = { & info , NULL } ;
2007-07-07 03:21:22 +04:00
struct ata_host * host ;
void __iomem * mmio_base ;
int rc , try_mmio ;
2006-11-22 20:28:41 +03:00
2011-04-16 02:52:00 +04:00
ata_print_version_once ( & pdev - > dev , DRV_VERSION ) ;
2006-11-22 20:28:41 +03:00
2008-03-25 06:22:47 +03:00
rc = pcim_enable_device ( pdev ) ;
if ( rc )
return rc ;
2007-07-07 03:21:22 +04:00
switch ( sil680_init_chip ( pdev , & try_mmio ) ) {
2006-11-22 20:28:41 +03:00
case 0 :
2007-05-04 14:43:58 +04:00
ppi [ 0 ] = & info_slow ;
2006-11-22 20:28:41 +03:00
break ;
case 0x30 :
return - ENODEV ;
2006-08-30 02:12:40 +04:00
}
2007-07-07 03:21:22 +04:00
if ( ! try_mmio )
goto use_ioports ;
/* Try to acquire MMIO resources and fallback to PIO if
* that fails
*/
rc = pcim_iomap_regions ( pdev , 1 < < SIL680_MMIO_BAR , DRV_NAME ) ;
if ( rc )
goto use_ioports ;
/* Allocate host and set it up */
host = ata_host_alloc_pinfo ( & pdev - > dev , ppi , 2 ) ;
if ( ! host )
return - ENOMEM ;
host - > iomap = pcim_iomap_table ( pdev ) ;
/* Setup DMA masks */
2019-08-26 13:57:25 +03:00
rc = dma_set_mask_and_coherent ( & pdev - > dev , ATA_DMA_MASK ) ;
2007-07-07 03:21:22 +04:00
if ( rc )
return rc ;
pci_set_master ( pdev ) ;
/* Get MMIO base and initialize port addresses */
mmio_base = host - > iomap [ SIL680_MMIO_BAR ] ;
host - > ports [ 0 ] - > ioaddr . bmdma_addr = mmio_base + 0x00 ;
host - > ports [ 0 ] - > ioaddr . cmd_addr = mmio_base + 0x80 ;
host - > ports [ 0 ] - > ioaddr . ctl_addr = mmio_base + 0x8a ;
host - > ports [ 0 ] - > ioaddr . altstatus_addr = mmio_base + 0x8a ;
2008-04-07 17:47:16 +04:00
ata_sff_std_ports ( & host - > ports [ 0 ] - > ioaddr ) ;
2007-07-07 03:21:22 +04:00
host - > ports [ 1 ] - > ioaddr . bmdma_addr = mmio_base + 0x08 ;
host - > ports [ 1 ] - > ioaddr . cmd_addr = mmio_base + 0xc0 ;
host - > ports [ 1 ] - > ioaddr . ctl_addr = mmio_base + 0xca ;
host - > ports [ 1 ] - > ioaddr . altstatus_addr = mmio_base + 0xca ;
2008-04-07 17:47:16 +04:00
ata_sff_std_ports ( & host - > ports [ 1 ] - > ioaddr ) ;
2007-07-07 03:21:22 +04:00
/* Register & activate */
2010-05-20 00:10:21 +04:00
return ata_host_activate ( host , pdev - > irq , ata_bmdma_interrupt ,
2008-04-07 17:47:16 +04:00
IRQF_SHARED , & sil680_sht ) ;
2007-07-07 03:21:22 +04:00
use_ioports :
2010-05-20 00:10:22 +04:00
return ata_pci_bmdma_init_one ( pdev , ppi , & sil680_sht , NULL , 0 ) ;
2006-08-30 02:12:40 +04:00
}
2014-05-07 19:17:44 +04:00
# ifdef CONFIG_PM_SLEEP
2006-11-22 20:28:41 +03:00
static int sil680_reinit_one ( struct pci_dev * pdev )
{
2013-06-03 09:05:36 +04:00
struct ata_host * host = pci_get_drvdata ( pdev ) ;
2008-03-25 06:22:47 +03:00
int try_mmio , rc ;
2007-07-07 03:21:22 +04:00
2008-03-25 06:22:47 +03:00
rc = ata_pci_device_do_resume ( pdev ) ;
if ( rc )
return rc ;
2007-07-07 03:21:22 +04:00
sil680_init_chip ( pdev , & try_mmio ) ;
2008-03-25 06:22:47 +03:00
ata_host_resume ( host ) ;
return 0 ;
2006-11-22 20:28:41 +03:00
}
2007-03-02 11:31:26 +03:00
# endif
2006-11-22 20:28:41 +03:00
2006-08-30 02:12:40 +04:00
static const struct pci_device_id sil680 [ ] = {
2006-09-29 04:21:59 +04:00
{ PCI_VDEVICE ( CMD , PCI_DEVICE_ID_SII_680 ) , } ,
{ } ,
2006-08-30 02:12:40 +04:00
} ;
static struct pci_driver sil680_pci_driver = {
2006-09-29 04:21:59 +04:00
. name = DRV_NAME ,
2006-08-30 02:12:40 +04:00
. id_table = sil680 ,
. probe = sil680_init_one ,
2006-11-22 20:28:41 +03:00
. remove = ata_pci_remove_one ,
2014-05-07 19:17:44 +04:00
# ifdef CONFIG_PM_SLEEP
2006-11-22 20:28:41 +03:00
. suspend = ata_pci_device_suspend ,
. resume = sil680_reinit_one ,
2007-03-02 11:31:26 +03:00
# endif
2006-08-30 02:12:40 +04:00
} ;
2012-04-19 09:43:05 +04:00
module_pci_driver ( sil680_pci_driver ) ;
2006-08-30 02:12:40 +04:00
MODULE_AUTHOR ( " Alan Cox " ) ;
MODULE_DESCRIPTION ( " low-level driver for SI680 PATA " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( pci , sil680 ) ;
MODULE_VERSION ( DRV_VERSION ) ;