2005-04-17 02:20:36 +04:00
/*
* linux / drivers / ide / pci / sl82c105 . c
*
* SL82C105 / Winbond 553 IDE driver
*
* Maintainer unknown .
*
* Drive tuning added from Rebel . com ' s kernel sources
* - - Russell King ( 15 / 11 / 98 ) linux @ arm . linux . org . uk
*
* Merge in Russell ' s HW workarounds , fix various problems
* with the timing registers setup .
* - - Benjamin Herrenschmidt ( 01 / 11 / 03 ) benh @ kernel . crashing . org
2007-05-06 00:03:49 +04:00
*
* Copyright ( C ) 2006 - 2007 MontaVista Software , Inc . < source @ mvista . com >
2005-04-17 02:20:36 +04:00
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/timer.h>
# include <linux/mm.h>
# include <linux/ioport.h>
# include <linux/interrupt.h>
# include <linux/blkdev.h>
# include <linux/hdreg.h>
# include <linux/pci.h>
# include <linux/ide.h>
# include <asm/io.h>
# include <asm/dma.h>
# undef DEBUG
# ifdef DEBUG
# define DBG(arg) printk arg
# else
# define DBG(fmt,...)
# endif
/*
* SL82C105 PCI config register 0x40 bits .
*/
# define CTRL_IDE_IRQB (1 << 30)
# define CTRL_IDE_IRQA (1 << 28)
# define CTRL_LEGIRQ (1 << 11)
# define CTRL_P1F16 (1 << 5)
# define CTRL_P1EN (1 << 4)
# define CTRL_P0F16 (1 << 1)
# define CTRL_P0EN (1 << 0)
/*
2007-05-06 00:03:49 +04:00
* Convert a PIO mode and cycle time to the required on / off times
* for the interface . This has protection against runaway timings .
2005-04-17 02:20:36 +04:00
*/
2007-07-20 03:11:55 +04:00
static unsigned int get_pio_timings ( ide_drive_t * drive , ide_pio_data_t * p )
2005-04-17 02:20:36 +04:00
{
2007-05-06 00:03:49 +04:00
unsigned int cmd_on , cmd_off ;
2007-07-20 03:11:55 +04:00
u8 iordy = 0 ;
2005-04-17 02:20:36 +04:00
2007-05-06 00:03:49 +04:00
cmd_on = ( ide_pio_timings [ p - > pio_mode ] . active_time + 29 ) / 30 ;
2005-04-17 02:20:36 +04:00
cmd_off = ( p - > cycle_time - 30 * cmd_on + 29 ) / 30 ;
if ( cmd_on = = 0 )
cmd_on = 1 ;
if ( cmd_off = = 0 )
cmd_off = 1 ;
2007-07-20 03:11:55 +04:00
if ( p - > pio_mode > 2 | | ide_dev_has_iordy ( drive - > id ) )
iordy = 0x40 ;
return ( cmd_on - 1 ) < < 8 | ( cmd_off - 1 ) | iordy ;
2005-04-17 02:20:36 +04:00
}
/*
2007-05-06 00:03:49 +04:00
* Configure the chipset for PIO mode .
2005-04-17 02:20:36 +04:00
*/
2007-05-06 00:03:49 +04:00
static u8 sl82c105_tune_pio ( ide_drive_t * drive , u8 pio )
2005-04-17 02:20:36 +04:00
{
2007-05-06 00:03:49 +04:00
struct pci_dev * dev = HWIF ( drive ) - > pci_dev ;
int reg = 0x44 + drive - > dn * 4 ;
2005-04-17 02:20:36 +04:00
ide_pio_data_t p ;
2007-05-06 00:03:49 +04:00
u16 drv_ctrl ;
2005-04-17 02:20:36 +04:00
2007-05-06 00:03:49 +04:00
DBG ( ( " sl82c105_tune_pio(drive:%s, pio:%u) \n " , drive - > name , pio ) ) ;
2005-04-17 02:20:36 +04:00
pio = ide_get_best_pio_mode ( drive , pio , 5 , & p ) ;
2007-07-20 03:11:55 +04:00
drv_ctrl = get_pio_timings ( drive , & p ) ;
2007-05-16 02:51:44 +04:00
/*
* Store the PIO timings so that we can restore them
* in case DMA will be turned off . . .
*/
drive - > drive_data & = 0xffff0000 ;
drive - > drive_data | = drv_ctrl ;
2005-04-17 02:20:36 +04:00
2007-05-06 00:03:49 +04:00
if ( ! drive - > using_dma ) {
2005-04-17 02:20:36 +04:00
/*
* If we are actually using MW DMA , then we can not
* reprogram the interface drive control register .
*/
2007-05-06 00:03:49 +04:00
pci_write_config_word ( dev , reg , drv_ctrl ) ;
pci_read_config_word ( dev , reg , & drv_ctrl ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-06 00:03:49 +04:00
printk ( KERN_DEBUG " %s: selected %s (%dns) (%04X) \n " , drive - > name ,
ide_xfer_verbose ( pio + XFER_PIO_0 ) , p . cycle_time , drv_ctrl ) ;
return pio ;
2005-04-17 02:20:36 +04:00
}
2007-05-16 02:51:44 +04:00
/*
* Configure the drive and chipset for a new transfer speed .
*/
static int sl82c105_tune_chipset ( ide_drive_t * drive , u8 speed )
{
static u16 mwdma_timings [ ] = { 0x0707 , 0x0201 , 0x0200 } ;
u16 drv_ctrl ;
DBG ( ( " sl82c105_tune_chipset(drive:%s, speed:%s) \n " ,
drive - > name , ide_xfer_verbose ( speed ) ) ) ;
speed = ide_rate_filter ( drive , speed ) ;
switch ( speed ) {
case XFER_MW_DMA_2 :
case XFER_MW_DMA_1 :
case XFER_MW_DMA_0 :
drv_ctrl = mwdma_timings [ speed - XFER_MW_DMA_0 ] ;
/*
* Store the DMA timings so that we can actually program
* them when DMA will be turned on . . .
*/
drive - > drive_data & = 0x0000ffff ;
drive - > drive_data | = ( unsigned long ) drv_ctrl < < 16 ;
/*
* If we are already using DMA , we just reprogram
* the drive control register .
*/
if ( drive - > using_dma ) {
struct pci_dev * dev = HWIF ( drive ) - > pci_dev ;
int reg = 0x44 + drive - > dn * 4 ;
pci_write_config_word ( dev , reg , drv_ctrl ) ;
}
break ;
case XFER_PIO_5 :
case XFER_PIO_4 :
case XFER_PIO_3 :
case XFER_PIO_2 :
case XFER_PIO_1 :
case XFER_PIO_0 :
( void ) sl82c105_tune_pio ( drive , speed - XFER_PIO_0 ) ;
break ;
default :
return - 1 ;
}
return ide_config_drive_speed ( drive , speed ) ;
}
2005-04-17 02:20:36 +04:00
/*
2007-05-06 00:03:49 +04:00
* Check to see if the drive and chipset are capable of DMA mode .
2005-04-17 02:20:36 +04:00
*/
2007-05-06 00:03:49 +04:00
static int sl82c105_ide_dma_check ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2007-05-06 00:03:49 +04:00
DBG ( ( " sl82c105_ide_dma_check(drive:%s) \n " , drive - > name ) ) ;
2005-04-17 02:20:36 +04:00
2007-05-16 02:51:46 +04:00
if ( ide_tune_dma ( drive ) )
2007-05-06 00:03:49 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2007-02-17 04:40:26 +03:00
return - 1 ;
2005-04-17 02:20:36 +04:00
}
/*
* The SL82C105 holds off all IDE interrupts while in DMA mode until
* all DMA activity is completed . Sometimes this causes problems ( eg ,
* when the drive wants to report an error condition ) .
*
* 0x7e is a " chip testing " register . Bit 2 resets the DMA controller
* state machine . We need to kick this to work around various bugs .
*/
static inline void sl82c105_reset_host ( struct pci_dev * dev )
{
u16 val ;
pci_read_config_word ( dev , 0x7e , & val ) ;
pci_write_config_word ( dev , 0x7e , val | ( 1 < < 2 ) ) ;
pci_write_config_word ( dev , 0x7e , val & ~ ( 1 < < 2 ) ) ;
}
/*
* If we get an IRQ timeout , it might be that the DMA state machine
* got confused . Fix from Todd Inglett . Details from Winbond .
*
* This function is called when the IDE timer expires , the drive
* indicates that it is READY , and we were waiting for DMA to complete .
*/
2007-07-10 01:17:54 +04:00
static void sl82c105_dma_lost_irq ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2007-05-06 00:03:49 +04:00
ide_hwif_t * hwif = HWIF ( drive ) ;
struct pci_dev * dev = hwif - > pci_dev ;
u32 val , mask = hwif - > channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA ;
u8 dma_cmd ;
2005-04-17 02:20:36 +04:00
2007-05-06 00:03:49 +04:00
printk ( " sl82c105: lost IRQ, resetting host \n " ) ;
2005-04-17 02:20:36 +04:00
/*
* Check the raw interrupt from the drive .
*/
pci_read_config_dword ( dev , 0x40 , & val ) ;
if ( val & mask )
printk ( " sl82c105: drive was requesting IRQ, but host lost it \n " ) ;
/*
* Was DMA enabled ? If so , disable it - we ' re resetting the
* host . The IDE layer will be handling the drive for us .
*/
2007-05-06 00:03:49 +04:00
dma_cmd = inb ( hwif - > dma_command ) ;
if ( dma_cmd & 1 ) {
outb ( dma_cmd & ~ 1 , hwif - > dma_command ) ;
2005-04-17 02:20:36 +04:00
printk ( " sl82c105: DMA was enabled \n " ) ;
}
sl82c105_reset_host ( dev ) ;
}
/*
* ATAPI devices can cause the SL82C105 DMA state machine to go gaga .
* Winbond recommend that the DMA state machine is reset prior to
* setting the bus master DMA enable bit .
*
* The generic IDE core will have disabled the BMEN bit before this
* function is called .
*/
2007-05-06 00:03:49 +04:00
static void sl82c105_dma_start ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2007-05-06 00:03:49 +04:00
ide_hwif_t * hwif = HWIF ( drive ) ;
struct pci_dev * dev = hwif - > pci_dev ;
2005-04-17 02:20:36 +04:00
sl82c105_reset_host ( dev ) ;
ide_dma_start ( drive ) ;
}
2007-07-10 01:17:54 +04:00
static void sl82c105_dma_timeout ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2007-07-10 01:17:54 +04:00
DBG ( ( " sl82c105_dma_timeout(drive:%s) \n " , drive - > name ) ) ;
2005-04-17 02:20:36 +04:00
2007-07-10 01:17:54 +04:00
sl82c105_reset_host ( HWIF ( drive ) - > pci_dev ) ;
ide_dma_timeout ( drive ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-06 00:03:49 +04:00
static int sl82c105_ide_dma_on ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2007-05-06 00:03:49 +04:00
struct pci_dev * dev = HWIF ( drive ) - > pci_dev ;
int rc , reg = 0x44 + drive - > dn * 4 ;
2005-04-17 02:20:36 +04:00
DBG ( ( " sl82c105_ide_dma_on(drive:%s) \n " , drive - > name ) ) ;
2007-05-06 00:03:49 +04:00
rc = __ide_dma_on ( drive ) ;
if ( rc = = 0 ) {
2007-05-16 02:51:44 +04:00
pci_write_config_word ( dev , reg , drive - > drive_data > > 16 ) ;
2007-05-06 00:03:49 +04:00
printk ( KERN_INFO " %s: DMA enabled \n " , drive - > name ) ;
}
return rc ;
2005-04-17 02:20:36 +04:00
}
2007-02-17 04:40:26 +03:00
static void sl82c105_dma_off_quietly ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2007-05-06 00:03:49 +04:00
struct pci_dev * dev = HWIF ( drive ) - > pci_dev ;
int reg = 0x44 + drive - > dn * 4 ;
2005-04-17 02:20:36 +04:00
2007-02-17 04:40:26 +03:00
DBG ( ( " sl82c105_dma_off_quietly(drive:%s) \n " , drive - > name ) ) ;
2007-05-06 00:03:49 +04:00
pci_write_config_word ( dev , reg , drive - > drive_data ) ;
2007-02-17 04:40:26 +03:00
ide_dma_off_quietly ( drive ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Ok , that is nasty , but we must make sure the DMA timings
* won ' t be used for a PIO access . The solution here is
* to make sure the 16 bits mode is diabled on the channel
* when DMA is enabled , thus causing the chip to use PIO0
* timings for those operations .
*/
static void sl82c105_selectproc ( ide_drive_t * drive )
{
2007-05-06 00:03:49 +04:00
ide_hwif_t * hwif = HWIF ( drive ) ;
struct pci_dev * dev = hwif - > pci_dev ;
2005-04-17 02:20:36 +04:00
u32 val , old , mask ;
//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
mask = hwif - > channel ? CTRL_P1F16 : CTRL_P0F16 ;
2006-12-08 13:40:01 +03:00
old = val = ( u32 ) pci_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( drive - > using_dma )
val & = ~ mask ;
else
val | = mask ;
if ( old ! = val ) {
pci_write_config_dword ( dev , 0x40 , val ) ;
2006-12-08 13:40:01 +03:00
pci_set_drvdata ( dev , ( void * ) val ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
* ATA reset will clear the 16 bits mode in the control
* register , we need to update our cache
*/
static void sl82c105_resetproc ( ide_drive_t * drive )
{
2006-12-08 13:40:01 +03:00
struct pci_dev * dev = HWIF ( drive ) - > pci_dev ;
2005-04-17 02:20:36 +04:00
u32 val ;
DBG ( ( " sl82c105_resetproc(drive:%s) \n " , drive - > name ) ) ;
pci_read_config_dword ( dev , 0x40 , & val ) ;
2006-12-08 13:40:01 +03:00
pci_set_drvdata ( dev , ( void * ) val ) ;
2005-04-17 02:20:36 +04:00
}
/*
* We only deal with PIO mode here - DMA mode ' using_dma ' is not
* initialised at the point that this function is called .
*/
2007-05-06 00:03:49 +04:00
static void sl82c105_tune_drive ( ide_drive_t * drive , u8 pio )
2005-04-17 02:20:36 +04:00
{
2007-05-06 00:03:49 +04:00
DBG ( ( " sl82c105_tune_drive(drive:%s, pio:%u) \n " , drive - > name , pio ) ) ;
2005-04-17 02:20:36 +04:00
2007-05-06 00:03:49 +04:00
pio = sl82c105_tune_pio ( drive , pio ) ;
( void ) ide_config_drive_speed ( drive , XFER_PIO_0 + pio ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Return the revision of the Winbond bridge
* which this function is part of .
*/
static unsigned int sl82c105_bridge_revision ( struct pci_dev * dev )
{
struct pci_dev * bridge ;
/*
* The bridge should be part of the same device , but function 0.
*/
2007-05-16 02:51:46 +04:00
bridge = pci_get_bus_and_slot ( dev - > bus - > number ,
2005-04-17 02:20:36 +04:00
PCI_DEVFN ( PCI_SLOT ( dev - > devfn ) , 0 ) ) ;
if ( ! bridge )
return - 1 ;
/*
* Make sure it is a Winbond 553 and is an ISA bridge .
*/
if ( bridge - > vendor ! = PCI_VENDOR_ID_WINBOND | |
bridge - > device ! = PCI_DEVICE_ID_WINBOND_83C553 | |
2007-05-16 02:51:46 +04:00
bridge - > class > > 8 ! = PCI_CLASS_BRIDGE_ISA ) {
pci_dev_put ( bridge ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
2007-05-16 02:51:46 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* We need to find function 0 ' s revision , not function 1
*/
2007-05-16 02:51:46 +04:00
pci_dev_put ( bridge ) ;
2005-04-17 02:20:36 +04:00
2007-06-09 02:46:36 +04:00
return bridge - > revision ;
2005-04-17 02:20:36 +04:00
}
/*
* Enable the PCI device
*
* - - BenH : It ' s arch fixup code that should enable channels that
* have not been enabled by firmware . I decided we can still enable
* channel 0 here at least , but channel 1 has to be enabled by
* firmware or arch code . We still set both to 16 bits mode .
*/
2005-07-03 18:36:56 +04:00
static unsigned int __devinit init_chipset_sl82c105 ( struct pci_dev * dev , const char * msg )
2005-04-17 02:20:36 +04:00
{
u32 val ;
DBG ( ( " init_chipset_sl82c105() \n " ) ) ;
pci_read_config_dword ( dev , 0x40 , & val ) ;
val | = CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16 ;
pci_write_config_dword ( dev , 0x40 , val ) ;
2006-12-08 13:40:01 +03:00
pci_set_drvdata ( dev , ( void * ) val ) ;
2005-04-17 02:20:36 +04:00
return dev - > irq ;
}
/*
2007-05-06 00:03:49 +04:00
* Initialise IDE channel
2005-04-17 02:20:36 +04:00
*/
2005-07-03 18:36:56 +04:00
static void __devinit init_hwif_sl82c105 ( ide_hwif_t * hwif )
2005-04-17 02:20:36 +04:00
{
2005-11-12 19:57:29 +03:00
unsigned int rev ;
2006-12-08 13:40:01 +03:00
2005-04-17 02:20:36 +04:00
DBG ( ( " init_hwif_sl82c105(hwif: ide%d) \n " , hwif - > index ) ) ;
2007-05-06 00:03:49 +04:00
hwif - > tuneproc = & sl82c105_tune_drive ;
2007-05-16 02:51:44 +04:00
hwif - > speedproc = & sl82c105_tune_chipset ;
2007-05-06 00:03:49 +04:00
hwif - > selectproc = & sl82c105_selectproc ;
hwif - > resetproc = & sl82c105_resetproc ;
/*
* We support 32 - bit I / O on this interface , and
* it doesn ' t have problems with interrupts .
*/
hwif - > drives [ 0 ] . io_32bit = hwif - > drives [ 1 ] . io_32bit = 1 ;
hwif - > drives [ 0 ] . unmask = hwif - > drives [ 1 ] . unmask = 1 ;
2006-12-08 13:40:01 +03:00
/*
* We always autotune PIO , this is done before DMA is checked ,
* so there ' s no risk of accidentally disabling DMA
*/
2007-05-06 00:03:49 +04:00
hwif - > drives [ 0 ] . autotune = hwif - > drives [ 1 ] . autotune = 1 ;
2005-04-17 02:20:36 +04:00
if ( ! hwif - > dma_base )
return ;
2005-11-12 19:57:29 +03:00
rev = sl82c105_bridge_revision ( hwif - > pci_dev ) ;
if ( rev < = 5 ) {
/*
* Never ever EVER under any circumstances enable
* DMA when the bridge is this old .
*/
2007-05-06 00:03:49 +04:00
printk ( " %s: Winbond W83C553 bridge revision %d, "
" BM-DMA disabled \n " , hwif - > name , rev ) ;
return ;
2005-11-12 19:57:29 +03:00
}
2007-05-06 00:03:49 +04:00
hwif - > atapi_dma = 1 ;
2007-05-16 02:51:44 +04:00
hwif - > mwdma_mask = 0x07 ;
2007-05-06 00:03:49 +04:00
hwif - > ide_dma_check = & sl82c105_ide_dma_check ;
hwif - > ide_dma_on = & sl82c105_ide_dma_on ;
hwif - > dma_off_quietly = & sl82c105_dma_off_quietly ;
2007-07-10 01:17:54 +04:00
hwif - > dma_lost_irq = & sl82c105_dma_lost_irq ;
2007-05-06 00:03:49 +04:00
hwif - > dma_start = & sl82c105_dma_start ;
2007-07-10 01:17:54 +04:00
hwif - > dma_timeout = & sl82c105_dma_timeout ;
2007-05-06 00:03:49 +04:00
if ( ! noautodma )
hwif - > autodma = 1 ;
hwif - > drives [ 0 ] . autodma = hwif - > drives [ 1 ] . autodma = hwif - > autodma ;
if ( hwif - > mate )
hwif - > serialized = hwif - > mate - > serialized = 1 ;
2005-04-17 02:20:36 +04:00
}
static ide_pci_device_t sl82c105_chipset __devinitdata = {
. name = " W82C105 " ,
. init_chipset = init_chipset_sl82c105 ,
. init_hwif = init_hwif_sl82c105 ,
. autodma = NOAUTODMA ,
. enablebits = { { 0x40 , 0x01 , 0x01 } , { 0x40 , 0x10 , 0x10 } } ,
. bootable = ON_BOARD ,
} ;
static int __devinit sl82c105_init_one ( struct pci_dev * dev , const struct pci_device_id * id )
{
return ide_setup_pci_device ( dev , & sl82c105_chipset ) ;
}
static struct pci_device_id sl82c105_pci_tbl [ ] = {
2006-06-28 15:27:02 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_WINBOND , PCI_DEVICE_ID_WINBOND_82C105 ) , 0 } ,
2005-04-17 02:20:36 +04:00
{ 0 , } ,
} ;
MODULE_DEVICE_TABLE ( pci , sl82c105_pci_tbl ) ;
static struct pci_driver driver = {
. name = " W82C105_IDE " ,
. id_table = sl82c105_pci_tbl ,
. probe = sl82c105_init_one ,
} ;
2007-01-27 15:46:56 +03:00
static int __init sl82c105_ide_init ( void )
2005-04-17 02:20:36 +04:00
{
return ide_pci_register_driver ( & driver ) ;
}
module_init ( sl82c105_ide_init ) ;
MODULE_DESCRIPTION ( " PCI driver module for W82C105 IDE " ) ;
MODULE_LICENSE ( " GPL " ) ;