2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 1996 - 1998 Linus Torvalds & authors ( see below )
*/
/*
* Authors :
* Jaromir Koutek < miri @ punknet . cz > ,
* Jan Harkes < jaharkes @ cwi . nl > ,
* Mark Lord < mlord @ pobox . com >
* Some parts of code are from ali14xx . c and from rz1000 . c .
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/ide.h>
# include <asm/io.h>
2008-07-25 00:53:32 +04:00
# define DRV_NAME "opti621"
2005-04-17 02:20:36 +04:00
# define READ_REG 0 /* index of Read cycle timing register */
# define WRITE_REG 1 /* index of Write cycle timing register */
# define CNTRL_REG 3 /* index of Control register */
# define STRAP_REG 5 /* index of Strap register */
# define MISC_REG 6 /* index of Miscellaneous register */
static int reg_base ;
2007-10-20 02:32:35 +04:00
static DEFINE_SPINLOCK ( opti621_lock ) ;
2005-04-17 02:20:36 +04:00
/* Write value to register reg, base of register
* is at reg_base ( 0x1f0 primary , 0x170 secondary ,
* if not changed by PCI configuration ) .
* This is from setupvic . exe program .
*/
2007-02-17 04:40:25 +03:00
static void write_reg ( u8 value , int reg )
2005-04-17 02:20:36 +04:00
{
2007-02-17 04:40:25 +03:00
inw ( reg_base + 1 ) ;
inw ( reg_base + 1 ) ;
outb ( 3 , reg_base + 2 ) ;
outb ( value , reg_base + reg ) ;
outb ( 0x83 , reg_base + 2 ) ;
2005-04-17 02:20:36 +04:00
}
/* Read value from register reg, base of register
* is at reg_base ( 0x1f0 primary , 0x170 secondary ,
* if not changed by PCI configuration ) .
* This is from setupvic . exe program .
*/
2007-02-17 04:40:25 +03:00
static u8 read_reg ( int reg )
2005-04-17 02:20:36 +04:00
{
u8 ret = 0 ;
2007-02-17 04:40:25 +03:00
inw ( reg_base + 1 ) ;
inw ( reg_base + 1 ) ;
outb ( 3 , reg_base + 2 ) ;
ret = inb ( reg_base + reg ) ;
outb ( 0x83 , reg_base + 2 ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2010-01-19 12:44:41 +03:00
static void opti621_set_pio_mode ( ide_hwif_t * hwif , ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2008-10-11 00:39:26 +04:00
ide_drive_t * pair = ide_get_pair_dev ( drive ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2010-01-19 12:44:41 +03:00
unsigned long mode = drive - > pio_mode , pair_mode ;
const u8 pio = mode - XFER_PIO_0 ;
2008-06-15 23:00:22 +04:00
u8 tim , misc , addr_pio = pio , clk ;
/* DRDY is default 2 (by OPTi Databook) */
2008-06-15 23:00:22 +04:00
static const u8 addr_timings [ 2 ] [ 5 ] = {
{ 0x20 , 0x10 , 0x00 , 0x00 , 0x00 } , /* 33 MHz */
{ 0x10 , 0x10 , 0x00 , 0x00 , 0x00 } , /* 25 MHz */
2008-06-15 23:00:22 +04:00
} ;
2008-06-15 23:00:22 +04:00
static const u8 data_rec_timings [ 2 ] [ 5 ] = {
{ 0x5b , 0x45 , 0x32 , 0x21 , 0x20 } , /* 33 MHz */
{ 0x48 , 0x34 , 0x21 , 0x10 , 0x10 } /* 25 MHz */
2008-06-15 23:00:22 +04:00
} ;
2005-04-17 02:20:36 +04:00
2009-06-16 00:13:44 +04:00
ide_set_drivedata ( drive , ( void * ) mode ) ;
2008-06-15 23:00:22 +04:00
2008-10-11 00:39:26 +04:00
if ( pair ) {
2009-06-16 00:13:44 +04:00
pair_mode = ( unsigned long ) ide_get_drivedata ( pair ) ;
if ( pair_mode & & pair_mode < mode )
addr_pio = pair_mode - XFER_PIO_0 ;
2008-06-15 23:00:22 +04:00
}
2005-04-17 02:20:36 +04:00
2008-06-15 23:00:22 +04:00
spin_lock_irqsave ( & opti621_lock , flags ) ;
reg_base = hwif - > io_ports . data_addr ;
/* allow Register-B */
outb ( 0xc0 , reg_base + CNTRL_REG ) ;
/* hmm, setupvic.exe does this ;-) */
outb ( 0xff , reg_base + 5 ) ;
/* if reads 0xff, adapter not exist? */
( void ) inb ( reg_base + CNTRL_REG ) ;
/* if reads 0xc0, no interface exist? */
read_reg ( CNTRL_REG ) ;
/* check CLK speed */
clk = read_reg ( STRAP_REG ) & 1 ;
printk ( KERN_INFO " %s: CLK = %d MHz \n " , hwif - > name , clk ? 25 : 33 ) ;
2008-06-15 23:00:22 +04:00
tim = data_rec_timings [ clk ] [ pio ] ;
misc = addr_timings [ clk ] [ addr_pio ] ;
2005-04-17 02:20:36 +04:00
2008-06-15 23:00:22 +04:00
/* select Index-0/1 for Register-A/B */
2008-10-13 23:39:40 +04:00
write_reg ( drive - > dn & 1 , MISC_REG ) ;
2007-02-17 04:40:25 +03:00
/* set read cycle timings */
2008-06-15 23:00:22 +04:00
write_reg ( tim , READ_REG ) ;
2007-02-17 04:40:25 +03:00
/* set write cycle timings */
2008-06-15 23:00:22 +04:00
write_reg ( tim , WRITE_REG ) ;
2005-04-17 02:20:36 +04:00
/* use Register-A for drive 0 */
/* use Register-B for drive 1 */
2007-02-17 04:40:25 +03:00
write_reg ( 0x85 , CNTRL_REG ) ;
2005-04-17 02:20:36 +04:00
/* set address setup, DRDY timings, */
/* and read prefetch for both drives */
2007-02-17 04:40:25 +03:00
write_reg ( misc , MISC_REG ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 02:32:35 +04:00
spin_unlock_irqrestore ( & opti621_lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-27 00:25:14 +04:00
static const struct ide_port_ops opti621_port_ops = {
. set_pio_mode = opti621_set_pio_mode ,
} ;
2005-04-17 02:20:36 +04:00
2008-06-15 23:00:22 +04:00
static const struct ide_port_info opti621_chipset __devinitdata = {
2008-07-25 00:53:32 +04:00
. name = DRV_NAME ,
2008-06-15 23:00:22 +04:00
. enablebits = { { 0x45 , 0x80 , 0x00 } , { 0x40 , 0x08 , 0x00 } } ,
. port_ops = & opti621_port_ops ,
. host_flags = IDE_HFLAG_NO_DMA ,
. pio_mask = ATA_PIO4 ,
2005-04-17 02:20:36 +04:00
} ;
static int __devinit opti621_init_one ( struct pci_dev * dev , const struct pci_device_id * id )
{
2008-07-25 00:53:14 +04:00
return ide_pci_init_one ( dev , & opti621_chipset , NULL ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-17 00:29:56 +04:00
static const struct pci_device_id opti621_pci_tbl [ ] = {
{ PCI_VDEVICE ( OPTI , PCI_DEVICE_ID_OPTI_82C621 ) , 0 } ,
2008-06-15 23:00:22 +04:00
{ PCI_VDEVICE ( OPTI , PCI_DEVICE_ID_OPTI_82C825 ) , 0 } ,
2005-04-17 02:20:36 +04:00
{ 0 , } ,
} ;
MODULE_DEVICE_TABLE ( pci , opti621_pci_tbl ) ;
2008-10-13 23:39:41 +04:00
static struct pci_driver opti621_pci_driver = {
2005-04-17 02:20:36 +04:00
. name = " Opti621_IDE " ,
. id_table = opti621_pci_tbl ,
. probe = opti621_init_one ,
2008-07-25 00:53:23 +04:00
. remove = ide_pci_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 opti621_ide_init ( void )
2005-04-17 02:20:36 +04:00
{
2008-10-13 23:39:41 +04:00
return ide_pci_register_driver ( & opti621_pci_driver ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-25 00:53:23 +04:00
static void __exit opti621_ide_exit ( void )
{
2008-10-13 23:39:41 +04:00
pci_unregister_driver ( & opti621_pci_driver ) ;
2008-07-25 00:53:23 +04:00
}
2005-04-17 02:20:36 +04:00
module_init ( opti621_ide_init ) ;
2008-07-25 00:53:23 +04:00
module_exit ( opti621_ide_exit ) ;
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Jaromir Koutek, Jan Harkes, Mark Lord " ) ;
MODULE_DESCRIPTION ( " PCI driver module for Opti621 IDE " ) ;
MODULE_LICENSE ( " GPL " ) ;