2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 1995 - 1996 Linus Torvalds & author ( see below )
*/
/*
* Principal Author / Maintainer : PODIEN @ hml2 . atlas . de ( Wolfram Podien )
*
* This file provides support for the advanced features
* of the UMC 8672 IDE interface .
*
* Version 0.01 Initial version , hacked out of ide . c ,
* and # include ' d rather than compiled separately .
* This will get cleaned up in a subsequent release .
*
* Version 0.02 now configs / compiles separate from ide . c - ml
* Version 0.03 enhanced auto - tune , fix display bug
* Version 0.05 replace sti ( ) with restore_flags ( ) - ml
* add detection of possible race condition - ml
*/
/*
2008-04-26 19:36:40 +04:00
* VLB Controller Support from
2005-04-17 02:20:36 +04:00
* Wolfram Podien
* Rohoefe 3
* D28832 Achim
* Germany
*
* To enable UMC8672 support there must a lilo line like
* append = " ide0=umc8672 " . . .
* To set the speed according to the abilities of the hardware there must be a
* line like
* # define UMC_DRIVE0 11
* in the beginning of the driver , which sets the speed of drive 0 to 11 ( there
* are some lines present ) . 0 - 11 are allowed speed values . These values are
2008-04-26 19:36:40 +04:00
* the results from the DOS speed test program supplied from UMC . 11 is the
2005-04-17 02:20:36 +04:00
* highest speed ( about PIO mode 3 )
*/
# define REALLY_SLOW_IO /* some systems can safely undef this */
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/timer.h>
# include <linux/mm.h>
# include <linux/ioport.h>
# include <linux/blkdev.h>
# include <linux/ide.h>
# include <linux/init.h>
# include <asm/io.h>
2008-04-27 00:25:18 +04:00
# define DRV_NAME "umc8672"
2005-04-17 02:20:36 +04:00
/*
* Default speeds . These can be changed with " auto-tune " and / or hdparm .
*/
# define UMC_DRIVE0 1 /* DOS measured drive speeds */
# define UMC_DRIVE1 1 /* 0 to 11 allowed */
# define UMC_DRIVE2 1 /* 11 = Fastest Speed */
# define UMC_DRIVE3 1 /* In case of crash reduce speed */
static u8 current_speeds [ 4 ] = { UMC_DRIVE0 , UMC_DRIVE1 , UMC_DRIVE2 , UMC_DRIVE3 } ;
2008-04-26 19:36:40 +04:00
static const u8 pio_to_umc [ 5 ] = { 0 , 3 , 7 , 10 , 11 } ; /* rough guesses */
2005-04-17 02:20:36 +04:00
/* 0 1 2 3 4 5 6 7 8 9 10 11 */
static const u8 speedtab [ 3 ] [ 12 ] = {
2008-04-26 19:36:40 +04:00
{ 0x0f , 0x0b , 0x02 , 0x02 , 0x02 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x1 } ,
{ 0x03 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x1 } ,
{ 0xff , 0xcb , 0xc0 , 0x58 , 0x36 , 0x33 , 0x23 , 0x22 , 0x21 , 0x11 , 0x10 , 0x0 }
} ;
2005-04-17 02:20:36 +04:00
2008-04-26 19:36:40 +04:00
static void out_umc ( char port , char wert )
2005-04-17 02:20:36 +04:00
{
2008-04-26 19:36:40 +04:00
outb_p ( port , 0x108 ) ;
outb_p ( wert , 0x109 ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-26 19:36:40 +04:00
static inline u8 in_umc ( char port )
2005-04-17 02:20:36 +04:00
{
2008-04-26 19:36:40 +04:00
outb_p ( port , 0x108 ) ;
2005-04-17 02:20:36 +04:00
return inb_p ( 0x109 ) ;
}
2008-04-26 19:36:40 +04:00
static void umc_set_speeds ( u8 speeds [ ] )
2005-04-17 02:20:36 +04:00
{
int i , tmp ;
2008-04-26 19:36:40 +04:00
outb_p ( 0x5A , 0x108 ) ; /* enable umc */
2005-04-17 02:20:36 +04:00
2008-04-26 19:36:40 +04:00
out_umc ( 0xd7 , ( speedtab [ 0 ] [ speeds [ 2 ] ] | ( speedtab [ 0 ] [ speeds [ 3 ] ] < < 4 ) ) ) ;
out_umc ( 0xd6 , ( speedtab [ 0 ] [ speeds [ 0 ] ] | ( speedtab [ 0 ] [ speeds [ 1 ] ] < < 4 ) ) ) ;
2005-04-17 02:20:36 +04:00
tmp = 0 ;
2008-04-26 19:36:40 +04:00
for ( i = 3 ; i > = 0 ; i - - )
2005-04-17 02:20:36 +04:00
tmp = ( tmp < < 2 ) | speedtab [ 1 ] [ speeds [ i ] ] ;
2008-04-26 19:36:40 +04:00
out_umc ( 0xdc , tmp ) ;
for ( i = 0 ; i < 4 ; i + + ) {
out_umc ( 0xd0 + i , speedtab [ 2 ] [ speeds [ i ] ] ) ;
out_umc ( 0xd8 + i , speedtab [ 2 ] [ speeds [ i ] ] ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-26 19:36:40 +04:00
outb_p ( 0xa5 , 0x108 ) ; /* disable umc */
2005-04-17 02:20:36 +04:00
2008-04-26 19:36:40 +04:00
printk ( " umc8672: drive speeds [0 to 11]: %d %d %d %d \n " ,
2005-04-17 02:20:36 +04:00
speeds [ 0 ] , speeds [ 1 ] , speeds [ 2 ] , speeds [ 3 ] ) ;
}
2010-01-19 12:44:41 +03:00
static void umc_set_pio_mode ( ide_hwif_t * hwif , ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2010-01-19 12:44:41 +03:00
ide_hwif_t * mate = hwif - > mate ;
2008-12-29 22:27:31 +03:00
unsigned long uninitialized_var ( flags ) ;
2010-01-19 12:44:41 +03:00
const u8 pio = drive - > pio_mode - XFER_PIO_0 ;
2005-04-17 02:20:36 +04:00
printk ( " %s: setting umc8672 to PIO mode%d (speed %d) \n " ,
drive - > name , pio , pio_to_umc [ pio ] ) ;
2009-01-06 19:20:50 +03:00
if ( mate )
spin_lock_irqsave ( & mate - > lock , flags ) ;
if ( mate & & mate - > handler ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " umc8672: other interface is busy: exiting tune_umc() \n " ) ;
} else {
current_speeds [ drive - > name [ 2 ] - ' a ' ] = pio_to_umc [ pio ] ;
2008-04-26 19:36:40 +04:00
umc_set_speeds ( current_speeds ) ;
2005-04-17 02:20:36 +04:00
}
2009-01-06 19:20:50 +03:00
if ( mate )
spin_unlock_irqrestore ( & mate - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-27 00:25:14 +04:00
static const struct ide_port_ops umc8672_port_ops = {
. set_pio_mode = umc_set_pio_mode ,
} ;
2012-10-05 04:11:48 +04:00
static const struct ide_port_info umc8672_port_info __initconst = {
2008-04-27 00:25:18 +04:00
. name = DRV_NAME ,
2008-02-02 21:56:31 +03:00
. chipset = ide_umc8672 ,
2008-04-27 00:25:14 +04:00
. port_ops = & umc8672_port_ops ,
2008-04-27 17:38:29 +04:00
. host_flags = IDE_HFLAG_NO_DMA ,
2008-02-02 21:56:31 +03:00
. pio_mask = ATA_PIO4 ,
} ;
2005-04-17 02:20:36 +04:00
static int __init umc8672_probe ( void )
{
2007-10-20 02:32:31 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
if ( ! request_region ( 0x108 , 2 , " umc8672 " ) ) {
printk ( KERN_ERR " umc8672: ports 0x108-0x109 already in use. \n " ) ;
return 1 ;
}
local_irq_save ( flags ) ;
2008-04-26 19:36:40 +04:00
outb_p ( 0x5A , 0x108 ) ; /* enable umc */
2005-04-17 02:20:36 +04:00
if ( in_umc ( 0xd5 ) ! = 0xa0 ) {
local_irq_restore ( flags ) ;
printk ( KERN_ERR " umc8672: not found \n " ) ;
release_region ( 0x108 , 2 ) ;
2008-04-26 19:36:40 +04:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
2008-04-26 19:36:40 +04:00
outb_p ( 0xa5 , 0x108 ) ; /* disable umc */
2005-04-17 02:20:36 +04:00
2008-04-26 19:36:40 +04:00
umc_set_speeds ( current_speeds ) ;
2005-04-17 02:20:36 +04:00
local_irq_restore ( flags ) ;
2008-04-27 00:25:16 +04:00
return ide_legacy_device_add ( & umc8672_port_info , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2012-01-13 03:02:20 +04:00
static bool probe_umc8672 ;
2007-03-03 19:48:55 +03:00
module_param_named ( probe , probe_umc8672 , bool , 0 ) ;
MODULE_PARM_DESC ( probe , " probe for UMC8672 chipset " ) ;
2008-01-26 22:13:07 +03:00
static int __init umc8672_init ( void )
2005-04-17 02:20:36 +04:00
{
2007-03-03 19:48:55 +03:00
if ( probe_umc8672 = = 0 )
goto out ;
if ( umc8672_probe ( ) = = 0 )
2009-08-18 22:18:35 +04:00
return 0 ;
2007-03-03 19:48:55 +03:00
out :
2009-08-18 22:18:35 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
module_init ( umc8672_init ) ;
MODULE_AUTHOR ( " Wolfram Podien " ) ;
MODULE_DESCRIPTION ( " Support for UMC 8672 IDE chipset " ) ;
MODULE_LICENSE ( " GPL " ) ;