2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 1998 - 2000 Andreas S . Krebs ( akrebs @ altavista . net ) , Maintainer
* Copyright ( C ) 1998 - 2002 Andre Hedrick < andre @ linux - ide . org > , Integrator
2010-01-18 10:18:47 +03:00
* Copyright ( C ) 2007 - 2010 Bartlomiej Zolnierkiewicz
2005-04-17 02:20:36 +04:00
*
* CYPRESS CY82C693 chipset IDE controller
*
* The CY82C693 chipset is used on Digital ' s PC - Alpha 164 SX boards .
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/pci.h>
# include <linux/ide.h>
# include <linux/init.h>
# include <asm/io.h>
2008-07-25 00:53:32 +04:00
# define DRV_NAME "cy82c693"
2005-04-17 02:20:36 +04:00
/*
* NOTE : the value for busmaster timeout is tricky and I got it by
* trial and error ! By using a to low value will cause DMA timeouts
* and drop IDE performance , and by using a to high value will cause
* audio playback to scatter .
* If you know a better value or how to calc it , please let me know .
*/
/* twice the value written in cy82c693ub datasheet */
# define BUSMASTER_TIMEOUT 0x50
/*
* the value above was tested on my machine and it seems to work okay
*/
/* here are the offset definitions for the registers */
# define CY82_IDE_CMDREG 0x04
# define CY82_IDE_ADDRSETUP 0x48
# define CY82_IDE_MASTER_IOR 0x4C
# define CY82_IDE_MASTER_IOW 0x4D
# define CY82_IDE_SLAVE_IOR 0x4E
# define CY82_IDE_SLAVE_IOW 0x4F
# define CY82_IDE_MASTER_8BIT 0x50
# define CY82_IDE_SLAVE_8BIT 0x51
# define CY82_INDEX_PORT 0x22
# define CY82_DATA_PORT 0x23
# define CY82_INDEX_CHANNEL0 0x30
# define CY82_INDEX_CHANNEL1 0x31
# define CY82_INDEX_TIMEOUT 0x32
/*
* set DMA mode a specific channel for CY82C693
*/
2010-01-19 12:45:29 +03:00
static void cy82c693_set_dma_mode ( ide_hwif_t * hwif , ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2010-01-19 12:45:29 +03:00
const u8 mode = drive - > dma_mode ;
2008-01-26 22:13:00 +03:00
u8 single = ( mode & 0x10 ) > > 4 , index = 0 , data = 0 ;
2005-04-17 02:20:36 +04:00
2008-01-26 22:13:00 +03:00
index = hwif - > channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0 ;
2005-04-17 02:20:36 +04:00
2008-01-26 22:13:00 +03:00
data = ( mode & 3 ) | ( single < < 2 ) ;
2005-04-17 02:20:36 +04:00
2007-02-17 04:40:25 +03:00
outb ( index , CY82_INDEX_PORT ) ;
outb ( data , CY82_DATA_PORT ) ;
2005-04-17 02:20:36 +04:00
2008-04-26 19:36:42 +04:00
/*
2005-04-17 02:20:36 +04:00
* note : below we set the value for Bus Master IDE TimeOut Register
2011-03-31 05:57:33 +04:00
* I ' m not absolutely sure what this does , but it solved my problem
2005-04-17 02:20:36 +04:00
* with IDE DMA and sound , so I now can play sound and work with
* my IDE driver at the same time : - )
*
* If you know the correct ( best ) value for this register please
* let me know - ASK
*/
data = BUSMASTER_TIMEOUT ;
2007-02-17 04:40:25 +03:00
outb ( CY82_INDEX_TIMEOUT , CY82_INDEX_PORT ) ;
outb ( data , CY82_DATA_PORT ) ;
2005-04-17 02:20:36 +04:00
}
2010-01-19 12:44:41 +03:00
static void cy82c693_set_pio_mode ( ide_hwif_t * hwif , ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( hwif - > dev ) ;
2010-01-18 10:18:47 +03:00
int bus_speed = ide_pci_clk ? ide_pci_clk : 33 ;
const unsigned long T = 1000000 / bus_speed ;
2005-04-17 02:20:36 +04:00
unsigned int addrCtrl ;
2010-01-18 10:18:47 +03:00
struct ide_timing t ;
u8 time_16 , time_8 ;
2005-04-17 02:20:36 +04:00
/* select primary or secondary channel */
if ( hwif - > index > 0 ) { /* drive is on the secondary channel */
2006-10-03 12:14:35 +04:00
dev = pci_get_slot ( dev - > bus , dev - > devfn + 1 ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev ) {
printk ( KERN_ERR " %s: tune_drive: "
" Cannot find secondary interface! \n " ,
drive - > name ) ;
return ;
}
}
2010-01-19 12:44:41 +03:00
ide_timing_compute ( drive , drive - > pio_mode , & t , T , 1 ) ;
2010-01-18 10:18:47 +03:00
time_16 = clamp_val ( t . recover - 1 , 0 , 15 ) |
( clamp_val ( t . active - 1 , 0 , 15 ) < < 4 ) ;
time_8 = clamp_val ( t . act8b - 1 , 0 , 15 ) |
( clamp_val ( t . rec8b - 1 , 0 , 15 ) < < 4 ) ;
2005-04-17 02:20:36 +04:00
/* now let's write the clocks registers */
2008-10-13 23:39:40 +04:00
if ( ( drive - > dn & 1 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
/*
* set master drive
* address setup control register
* is 32 bit ! ! !
2008-04-26 19:36:42 +04:00
*/
2005-04-17 02:20:36 +04:00
pci_read_config_dword ( dev , CY82_IDE_ADDRSETUP , & addrCtrl ) ;
2008-04-26 19:36:42 +04:00
2005-04-17 02:20:36 +04:00
addrCtrl & = ( ~ 0xF ) ;
2010-01-18 10:18:47 +03:00
addrCtrl | = clamp_val ( t . setup - 1 , 0 , 15 ) ;
2005-04-17 02:20:36 +04:00
pci_write_config_dword ( dev , CY82_IDE_ADDRSETUP , addrCtrl ) ;
/* now let's set the remaining registers */
2010-01-18 10:18:47 +03:00
pci_write_config_byte ( dev , CY82_IDE_MASTER_IOR , time_16 ) ;
pci_write_config_byte ( dev , CY82_IDE_MASTER_IOW , time_16 ) ;
pci_write_config_byte ( dev , CY82_IDE_MASTER_8BIT , time_8 ) ;
2005-04-17 02:20:36 +04:00
} else {
/*
* set slave drive
* address setup control register
* is 32 bit ! ! !
2008-04-26 19:36:42 +04:00
*/
2005-04-17 02:20:36 +04:00
pci_read_config_dword ( dev , CY82_IDE_ADDRSETUP , & addrCtrl ) ;
addrCtrl & = ( ~ 0xF0 ) ;
2010-01-18 10:18:47 +03:00
addrCtrl | = ( clamp_val ( t . setup - 1 , 0 , 15 ) < < 4 ) ;
2005-04-17 02:20:36 +04:00
pci_write_config_dword ( dev , CY82_IDE_ADDRSETUP , addrCtrl ) ;
/* now let's set the remaining registers */
2010-01-18 10:18:47 +03:00
pci_write_config_byte ( dev , CY82_IDE_SLAVE_IOR , time_16 ) ;
pci_write_config_byte ( dev , CY82_IDE_SLAVE_IOW , time_16 ) ;
pci_write_config_byte ( dev , CY82_IDE_SLAVE_8BIT , time_8 ) ;
2008-04-26 19:36:42 +04:00
}
2011-08-04 12:30:34 +04:00
if ( hwif - > index > 0 )
pci_dev_put ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-10 01:07:56 +03:00
static void __devinit init_iops_cy82c693 ( ide_hwif_t * hwif )
2005-04-17 02:20:36 +04:00
{
2007-10-26 22:31:15 +04:00
static ide_hwif_t * primary ;
2008-02-02 01:09:31 +03:00
struct pci_dev * dev = to_pci_dev ( hwif - > dev ) ;
2007-10-26 22:31:15 +04:00
2008-02-02 01:09:31 +03:00
if ( PCI_FUNC ( dev - > devfn ) = = 1 )
2005-04-17 02:20:36 +04:00
primary = hwif ;
else {
hwif - > mate = primary ;
hwif - > channel = 1 ;
}
}
2008-04-27 00:25:14 +04:00
static const struct ide_port_ops cy82c693_port_ops = {
. set_pio_mode = cy82c693_set_pio_mode ,
. set_dma_mode = cy82c693_set_dma_mode ,
} ;
2007-10-20 02:32:34 +04:00
static const struct ide_port_info cy82c693_chipset __devinitdata = {
2008-07-25 00:53:32 +04:00
. name = DRV_NAME ,
2007-02-17 04:40:24 +03:00
. init_iops = init_iops_cy82c693 ,
2008-04-27 00:25:14 +04:00
. port_ops = & cy82c693_port_ops ,
2008-04-26 19:36:38 +04:00
. host_flags = IDE_HFLAG_SINGLE ,
2007-07-20 03:11:59 +04:00
. pio_mask = ATA_PIO4 ,
2008-01-26 22:13:00 +03:00
. swdma_mask = ATA_SWDMA2 ,
. mwdma_mask = ATA_MWDMA2 ,
2005-04-17 02:20:36 +04:00
} ;
static int __devinit cy82c693_init_one ( struct pci_dev * dev , const struct pci_device_id * id )
{
struct pci_dev * dev2 ;
int ret = - ENODEV ;
/* CY82C693 is more than only a IDE controller.
Function 1 is primary IDE channel , function 2 - secondary . */
2008-04-26 19:36:42 +04:00
if ( ( dev - > class > > 8 ) = = PCI_CLASS_STORAGE_IDE & &
2005-04-17 02:20:36 +04:00
PCI_FUNC ( dev - > devfn ) = = 1 ) {
2006-10-03 12:14:35 +04:00
dev2 = pci_get_slot ( dev - > bus , dev - > devfn + 1 ) ;
2008-07-25 00:53:14 +04:00
ret = ide_pci_init_two ( dev , dev2 , & cy82c693_chipset , NULL ) ;
2008-07-25 00:53:21 +04:00
if ( ret )
pci_dev_put ( dev2 ) ;
2005-04-17 02:20:36 +04:00
}
return ret ;
}
2008-07-25 00:53:21 +04:00
static void __devexit cy82c693_remove ( struct pci_dev * dev )
{
struct ide_host * host = pci_get_drvdata ( dev ) ;
struct pci_dev * dev2 = host - > dev [ 1 ] ? to_pci_dev ( host - > dev [ 1 ] ) : NULL ;
ide_pci_remove ( dev ) ;
pci_dev_put ( dev2 ) ;
}
2007-10-17 00:29:56 +04:00
static const struct pci_device_id cy82c693_pci_tbl [ ] = {
{ PCI_VDEVICE ( CONTAQ , PCI_DEVICE_ID_CONTAQ_82C693 ) , 0 } ,
2005-04-17 02:20:36 +04:00
{ 0 , } ,
} ;
MODULE_DEVICE_TABLE ( pci , cy82c693_pci_tbl ) ;
2008-10-13 23:39:41 +04:00
static struct pci_driver cy82c693_pci_driver = {
2005-04-17 02:20:36 +04:00
. name = " Cypress_IDE " ,
. id_table = cy82c693_pci_tbl ,
. probe = cy82c693_init_one ,
2008-08-18 23:40:03 +04:00
. remove = __devexit_p ( cy82c693_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 cy82c693_ide_init ( void )
2005-04-17 02:20:36 +04:00
{
2008-10-13 23:39:41 +04:00
return ide_pci_register_driver ( & cy82c693_pci_driver ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-25 00:53:21 +04:00
static void __exit cy82c693_ide_exit ( void )
{
2008-10-13 23:39:41 +04:00
pci_unregister_driver ( & cy82c693_pci_driver ) ;
2008-07-25 00:53:21 +04:00
}
2005-04-17 02:20:36 +04:00
module_init ( cy82c693_ide_init ) ;
2008-07-25 00:53:21 +04:00
module_exit ( cy82c693_ide_exit ) ;
2005-04-17 02:20:36 +04:00
2010-01-18 10:18:47 +03:00
MODULE_AUTHOR ( " Andreas Krebs, Andre Hedrick, Bartlomiej Zolnierkiewicz " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " PCI driver module for the Cypress CY82C693 IDE " ) ;
MODULE_LICENSE ( " GPL " ) ;