2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 1995 - 2000 Linus Torvalds & author ( see below )
*/
/*
* HT - 6560 B EIDE - controller support
* To activate controller support use kernel parameter " ide0=ht6560b " .
* Use hdparm utility to enable PIO mode support .
*
* Author : Mikko Ala - Fossi < maf @ iki . fi >
2008-07-25 00:53:35 +04:00
* Jan Evert van Grootheest < j . e . van . grootheest @ caiway . nl >
2005-04-17 02:20:36 +04:00
*
* Try : http : //www.maf.iki.fi/~maf/ht6560b/
*/
2008-04-26 19:36:35 +04:00
# define DRV_NAME "ht6560b"
2008-02-19 03:41:26 +03:00
# define HT6560B_VERSION "v0.08"
2005-04-17 02:20:36 +04:00
# 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>
/* #define DEBUG */ /* remove comments for DEBUG messages */
/*
* The special i / o - port that HT - 6560 B uses to configuration :
* bit0 ( 0x01 ) : " 1 " selects secondary interface
* bit2 ( 0x04 ) : " 1 " enables FIFO function
* bit5 ( 0x20 ) : " 1 " enables prefetched data read function ( ? ? ? )
*
* The special i / o - port that HT - 6560 A uses to configuration :
* bit0 ( 0x01 ) : " 1 " selects secondary interface
* bit1 ( 0x02 ) : " 1 " enables prefetched data read function
* bit2 ( 0x04 ) : " 0 " enables multi - master system ( ? )
* bit3 ( 0x08 ) : " 1 " 3 cycle time , " 0 " 2 cycle time ( ? )
*/
# define HT_CONFIG_PORT 0x3e6
# define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8)
/*
* FIFO + PREFETCH ( both a / b - model )
*/
# define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
# define HT_SECONDARY_IF 0x01
# define HT_PREFETCH_MODE 0x20
/*
* ht6560b Timing values :
*
* I reviewed some assembler source listings of htide drivers and found
* out how they setup those cycle time interfacing values , as they at Holtek
* call them . IDESETUP . COM that is supplied with the drivers figures out
* optimal values and fetches those values to drivers . I found out that
2008-04-18 02:46:26 +04:00
* they use Select register to fetch timings to the ide board right after
2005-04-17 02:20:36 +04:00
* interface switching . After that it was quite easy to add code to
* ht6560b . c .
*
* IDESETUP . COM gave me values 0x24 , 0x45 , 0xaa , 0xff that worked fine
* for hda and hdc . But hdb needed higher values to work , so I guess
* that sometimes it is necessary to give higher value than IDESETUP
* gives . [ see cmd640 . c for an extreme example of this . - ml ]
*
* Perhaps I should explain something about these timing values :
* The higher nibble of value is the Recovery Time ( rt ) and the lower nibble
* of the value is the Active Time ( at ) . Minimum value 2 is the fastest and
* the maximum value 15 is the slowest . Default values should be 15 for both .
* So 0x24 means 2 for rt and 4 for at . Each of the drives should have
* both values , and IDESETUP gives automatically rt = 15 st = 15 for CDROMs or
* similar . If value is too small there will be all sorts of failures .
*
* Timing byte consists of
* High nibble : Recovery Cycle Time ( rt )
* The valid values range from 2 to 15. The default is 15.
*
* Low nibble : Active Cycle Time ( at )
* The valid values range from 2 to 15. The default is 15.
*
* You can obtain optimized timing values by running Holtek IDESETUP . COM
* for DOS . DOS drivers get their timing values from command line , where
* the first value is the Recovery Time and the second value is the
* Active Time for each drive . Smaller value gives higher speed .
* In case of failures you should probably fall back to a higher value .
*/
# define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff)
# define HT_TIMING_DEFAULT 0xff
/*
* This routine handles interface switching for the peculiar hardware design
* on the F . G . I . / Holtek HT - 6560 B VLB IDE interface .
* The HT - 6560 B can only enable one IDE port at a time , and requires a
* silly sequence ( below ) whenever we switch between primary and secondary .
*/
/*
* This routine is invoked from ide . c to prepare for access to a given drive .
*/
static void ht6560b_selectproc ( ide_drive_t * drive )
{
2008-04-18 02:46:26 +04:00
ide_hwif_t * hwif = drive - > hwif ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
static u8 current_select = 0 ;
static u8 current_timing = 0 ;
u8 select , timing ;
local_irq_save ( flags ) ;
2008-02-19 03:41:26 +03:00
2005-04-17 02:20:36 +04:00
select = HT_CONFIG ( drive ) ;
timing = HT_TIMING ( drive ) ;
2008-02-19 03:41:26 +03:00
/*
* Need to enforce prefetch sometimes because otherwise
* it ' ll hang ( hard ) .
*/
2008-10-13 23:39:36 +04:00
if ( drive - > media ! = ide_disk | |
( drive - > dev_flags & IDE_DFLAG_PRESENT ) = = 0 )
2008-02-19 03:41:26 +03:00
select | = HT_PREFETCH_MODE ;
2005-04-17 02:20:36 +04:00
if ( select ! = current_select | | timing ! = current_timing ) {
current_select = select ;
current_timing = timing ;
2007-02-17 04:40:25 +03:00
( void ) inb ( HT_CONFIG_PORT ) ;
( void ) inb ( HT_CONFIG_PORT ) ;
( void ) inb ( HT_CONFIG_PORT ) ;
( void ) inb ( HT_CONFIG_PORT ) ;
outb ( select , HT_CONFIG_PORT ) ;
2005-04-17 02:20:36 +04:00
/*
* Set timing for this drive :
*/
2008-04-27 17:38:32 +04:00
outb ( timing , hwif - > io_ports . device_addr ) ;
( void ) inb ( hwif - > io_ports . status_addr ) ;
2005-04-17 02:20:36 +04:00
# ifdef DEBUG
printk ( " ht6560b: %s: select=%#x timing=%#x \n " ,
drive - > name , select , timing ) ;
# endif
}
local_irq_restore ( flags ) ;
}
/*
* Autodetection and initialization of ht6560b
*/
static int __init try_to_init_ht6560b ( void )
{
u8 orig_value ;
int i ;
/* Autodetect ht6560b */
if ( ( orig_value = inb ( HT_CONFIG_PORT ) ) = = 0xff )
return 0 ;
for ( i = 3 ; i > 0 ; i - - ) {
outb ( 0x00 , HT_CONFIG_PORT ) ;
if ( ! ( ( ~ inb ( HT_CONFIG_PORT ) ) & 0x3f ) ) {
outb ( orig_value , HT_CONFIG_PORT ) ;
return 0 ;
}
}
outb ( 0x00 , HT_CONFIG_PORT ) ;
if ( ( ~ inb ( HT_CONFIG_PORT ) ) & 0x3f ) {
outb ( orig_value , HT_CONFIG_PORT ) ;
return 0 ;
}
/*
* Ht6560b autodetected
*/
outb ( HT_CONFIG_DEFAULT , HT_CONFIG_PORT ) ;
2008-04-18 02:46:26 +04:00
outb ( HT_TIMING_DEFAULT , 0x1f6 ) ; /* Select register */
( void ) inb ( 0x1f7 ) ; /* Status register */
2008-02-19 03:41:26 +03:00
printk ( " ht6560b " HT6560B_VERSION
2005-04-17 02:20:36 +04:00
" : chipset detected and initialized "
# ifdef DEBUG
" with debug enabled "
# endif
2008-02-19 03:41:26 +03:00
" \n "
2005-04-17 02:20:36 +04:00
) ;
return 1 ;
}
2007-10-12 01:54:00 +04:00
static u8 ht_pio2timings ( ide_drive_t * drive , const u8 pio )
2005-04-17 02:20:36 +04:00
{
int active_time , recovery_time ;
int active_cycles , recovery_cycles ;
2008-07-15 23:21:46 +04:00
int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50 ;
2008-04-27 17:38:29 +04:00
2005-04-17 02:20:36 +04:00
if ( pio ) {
2007-07-20 03:11:56 +04:00
unsigned int cycle_time ;
2008-07-16 22:33:37 +04:00
struct ide_timing * t = ide_timing_find_mode ( XFER_PIO_0 + pio ) ;
2007-07-20 03:11:56 +04:00
cycle_time = ide_pio_cycle_time ( drive , pio ) ;
2005-04-17 02:20:36 +04:00
/*
* Just like opti621 . c we try to calculate the
* actual cycle time for recovery and activity
* according system bus speed .
*/
2008-07-16 22:33:37 +04:00
active_time = t - > active ;
recovery_time = cycle_time - active_time - t - > setup ;
2005-04-17 02:20:36 +04:00
/*
* Cycle times should be Vesa bus cycles
*/
active_cycles = ( active_time * bus_speed + 999 ) / 1000 ;
recovery_cycles = ( recovery_time * bus_speed + 999 ) / 1000 ;
/*
* Upper and lower limits
*/
if ( active_cycles < 2 ) active_cycles = 2 ;
if ( recovery_cycles < 2 ) recovery_cycles = 2 ;
if ( active_cycles > 15 ) active_cycles = 15 ;
if ( recovery_cycles > 15 ) recovery_cycles = 0 ; /* 0==16 */
# ifdef DEBUG
printk ( " ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns) \n " , drive - > name , pio , recovery_cycles , recovery_time , active_cycles , active_time ) ;
# endif
return ( u8 ) ( ( recovery_cycles < < 4 ) | active_cycles ) ;
} else {
# ifdef DEBUG
printk ( " ht6560b: drive %s setting pio=0 \n " , drive - > name ) ;
# endif
return HT_TIMING_DEFAULT ; /* default setting */
}
}
2007-10-20 02:32:35 +04:00
static DEFINE_SPINLOCK ( ht6560b_lock ) ;
2005-04-17 02:20:36 +04:00
/*
* Enable / Disable so called prefetch mode
*/
static void ht_set_prefetch ( ide_drive_t * drive , u8 state )
{
unsigned long flags ;
int t = HT_PREFETCH_MODE < < 8 ;
2007-10-20 02:32:35 +04:00
spin_lock_irqsave ( & ht6560b_lock , flags ) ;
2005-04-17 02:20:36 +04:00
/*
* Prefetch mode and unmask irq seems to conflict
*/
if ( state ) {
drive - > drive_data | = t ; /* enable prefetch mode */
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_NO_UNMASK ;
drive - > dev_flags & = ~ IDE_DFLAG_UNMASK ;
2005-04-17 02:20:36 +04:00
} else {
drive - > drive_data & = ~ t ; /* disable prefetch mode */
2008-10-13 23:39:36 +04:00
drive - > dev_flags & = ~ IDE_DFLAG_NO_UNMASK ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 02:32:35 +04:00
spin_unlock_irqrestore ( & ht6560b_lock , flags ) ;
2005-04-17 02:20:36 +04:00
# ifdef DEBUG
printk ( " ht6560b: drive %s prefetch mode %sabled \n " , drive - > name , ( state ? " en " : " dis " ) ) ;
# endif
}
2007-10-12 01:54:00 +04:00
static void ht6560b_set_pio_mode ( ide_drive_t * drive , const u8 pio )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
u8 timing ;
switch ( pio ) {
case 8 : /* set prefetch off */
case 9 : /* set prefetch on */
ht_set_prefetch ( drive , pio & 1 ) ;
return ;
}
2007-10-20 02:32:35 +04:00
2005-04-17 02:20:36 +04:00
timing = ht_pio2timings ( drive , pio ) ;
2007-10-20 02:32:35 +04:00
spin_lock_irqsave ( & ht6560b_lock , flags ) ;
2005-04-17 02:20:36 +04:00
drive - > drive_data & = 0xff00 ;
drive - > drive_data | = timing ;
2007-10-20 02:32:35 +04:00
spin_unlock_irqrestore ( & ht6560b_lock , flags ) ;
2005-04-17 02:20:36 +04:00
# ifdef DEBUG
printk ( " ht6560b: drive %s tuned to pio mode %#x timing=%#x \n " , drive - > name , pio , timing ) ;
# endif
}
2008-07-16 22:33:42 +04:00
static void __init ht6560b_init_dev ( ide_drive_t * drive )
2008-02-02 21:56:40 +03:00
{
2008-07-16 22:33:42 +04:00
ide_hwif_t * hwif = drive - > hwif ;
2008-02-02 21:56:40 +03:00
/* Setting default configurations for drives. */
int t = ( HT_CONFIG_DEFAULT < < 8 ) | HT_TIMING_DEFAULT ;
if ( hwif - > channel )
t | = ( HT_SECONDARY_IF < < 8 ) ;
2008-07-16 22:33:42 +04:00
drive - > drive_data = t ;
2008-02-02 21:56:40 +03:00
}
2008-04-27 17:38:24 +04:00
static int probe_ht6560b ;
2007-03-03 19:48:55 +03:00
module_param_named ( probe , probe_ht6560b , bool , 0 ) ;
MODULE_PARM_DESC ( probe , " probe for HT6560B chipset " ) ;
2008-04-27 00:25:14 +04:00
static const struct ide_port_ops ht6560b_port_ops = {
2008-07-16 22:33:42 +04:00
. init_dev = ht6560b_init_dev ,
2008-04-27 00:25:14 +04:00
. set_pio_mode = ht6560b_set_pio_mode ,
. selectproc = ht6560b_selectproc ,
} ;
2008-02-02 21:56:31 +03:00
static const struct ide_port_info ht6560b_port_info __initdata = {
2008-04-27 00:25:18 +04:00
. name = DRV_NAME ,
2008-02-02 21:56:31 +03:00
. chipset = ide_ht6560b ,
2008-04-27 00:25:14 +04:00
. port_ops = & ht6560b_port_ops ,
2008-02-02 21:56:31 +03:00
. host_flags = IDE_HFLAG_SERIALIZE | /* is this needed? */
IDE_HFLAG_NO_DMA |
IDE_HFLAG_ABUSE_PREFETCH ,
2008-02-19 03:41:26 +03:00
. pio_mask = ATA_PIO4 ,
2008-02-02 21:56:31 +03:00
} ;
2008-01-26 22:13:07 +03:00
static int __init ht6560b_init ( void )
2005-04-17 02:20:36 +04:00
{
2007-03-03 19:48:55 +03:00
if ( probe_ht6560b = = 0 )
return - ENODEV ;
2008-04-26 19:36:35 +04:00
if ( ! request_region ( HT_CONFIG_PORT , 1 , DRV_NAME ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_NOTICE " %s: HT_CONFIG_PORT not found \n " ,
2008-04-27 00:25:20 +04:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
if ( ! try_to_init_ht6560b ( ) ) {
2008-04-27 00:25:20 +04:00
printk ( KERN_NOTICE " %s: HBA not found \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
goto release_region ;
}
2008-04-27 00:25:16 +04:00
return ide_legacy_device_add ( & ht6560b_port_info , 0 ) ;
2005-04-17 02:20:36 +04:00
release_region :
release_region ( HT_CONFIG_PORT , 1 ) ;
return - ENODEV ;
}
module_init ( ht6560b_init ) ;
MODULE_AUTHOR ( " See Local File " ) ;
MODULE_DESCRIPTION ( " HT-6560B EIDE-controller support " ) ;
MODULE_LICENSE ( " GPL " ) ;