2005-04-17 02:20:36 +04:00
/*
2008-02-02 01:09:33 +03:00
* Q40 I / O port IDE Driver
2005-04-17 02:20:36 +04:00
*
* ( c ) Richard Zidlicky
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of this archive for
* more details .
*
*
*/
# include <linux/types.h>
# include <linux/mm.h>
# include <linux/interrupt.h>
# include <linux/blkdev.h>
# include <linux/ide.h>
2011-07-03 21:41:29 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
2009-04-08 16:12:48 +04:00
# include <asm/ide.h>
2005-04-17 02:20:36 +04:00
/*
* Bases of the IDE interfaces
*/
# define Q40IDE_NUM_HWIFS 2
# define PCIDE_BASE1 0x1f0
# define PCIDE_BASE2 0x170
# define PCIDE_BASE3 0x1e8
# define PCIDE_BASE4 0x168
# define PCIDE_BASE5 0x1e0
# define PCIDE_BASE6 0x160
static const unsigned long pcide_bases [ Q40IDE_NUM_HWIFS ] = {
PCIDE_BASE1 , PCIDE_BASE2 , /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5,
PCIDE_BASE6 */
} ;
static int q40ide_default_irq ( unsigned long base )
{
switch ( base ) {
case 0x1f0 : return 14 ;
case 0x170 : return 15 ;
case 0x1e8 : return 11 ;
default :
return 0 ;
}
}
/*
2008-02-06 04:57:50 +03:00
* Addresses are pretranslated for Q40 ISA access .
2005-04-17 02:20:36 +04:00
*/
2009-06-15 20:52:58 +04:00
static void q40_ide_setup_ports ( struct ide_hw * hw , unsigned long base , int irq )
2005-04-17 02:20:36 +04:00
{
2009-05-17 21:12:25 +04:00
memset ( hw , 0 , sizeof ( * hw ) ) ;
2008-04-28 09:59:35 +04:00
/* BIG FAT WARNING:
assumption : only DATA port is ever used in 16 bit mode */
hw - > io_ports . data_addr = Q40_ISA_IO_W ( base ) ;
hw - > io_ports . error_addr = Q40_ISA_IO_B ( base + 1 ) ;
hw - > io_ports . nsect_addr = Q40_ISA_IO_B ( base + 2 ) ;
hw - > io_ports . lbal_addr = Q40_ISA_IO_B ( base + 3 ) ;
hw - > io_ports . lbam_addr = Q40_ISA_IO_B ( base + 4 ) ;
hw - > io_ports . lbah_addr = Q40_ISA_IO_B ( base + 5 ) ;
hw - > io_ports . device_addr = Q40_ISA_IO_B ( base + 6 ) ;
hw - > io_ports . status_addr = Q40_ISA_IO_B ( base + 7 ) ;
hw - > io_ports . ctl_addr = Q40_ISA_IO_B ( base + 0x206 ) ;
2007-10-20 02:32:32 +04:00
2005-04-17 02:20:36 +04:00
hw - > irq = irq ;
}
2009-03-27 14:46:38 +03:00
static void q40ide_input_data ( ide_drive_t * drive , struct ide_cmd * cmd ,
2008-04-29 01:44:36 +04:00
void * buf , unsigned int len )
2008-04-29 01:44:36 +04:00
{
2008-04-29 01:44:36 +04:00
unsigned long data_addr = drive - > hwif - > io_ports . data_addr ;
2008-04-29 01:44:36 +04:00
2009-04-08 16:12:48 +04:00
if ( drive - > media = = ide_disk & & cmd & & ( cmd - > tf_flags & IDE_TFLAG_FS ) ) {
__ide_mm_insw ( data_addr , buf , ( len + 1 ) / 2 ) ;
return ;
}
2008-04-29 01:44:36 +04:00
2009-03-27 14:46:23 +03:00
raw_insw_swapw ( ( u16 * ) data_addr , buf , ( len + 1 ) / 2 ) ;
2008-04-29 01:44:36 +04:00
}
2009-03-27 14:46:38 +03:00
static void q40ide_output_data ( ide_drive_t * drive , struct ide_cmd * cmd ,
2008-04-29 01:44:36 +04:00
void * buf , unsigned int len )
2008-04-29 01:44:36 +04:00
{
2008-04-29 01:44:36 +04:00
unsigned long data_addr = drive - > hwif - > io_ports . data_addr ;
2009-04-08 16:12:48 +04:00
if ( drive - > media = = ide_disk & & cmd & & ( cmd - > tf_flags & IDE_TFLAG_FS ) ) {
__ide_mm_outsw ( data_addr , buf , ( len + 1 ) / 2 ) ;
return ;
}
2008-04-29 01:44:36 +04:00
2009-03-27 14:46:23 +03:00
raw_outsw_swapw ( ( u16 * ) data_addr , buf , ( len + 1 ) / 2 ) ;
2008-04-29 01:44:36 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-23 21:55:56 +04:00
/* Q40 has a byte-swapped IDE interface */
static const struct ide_tp_ops q40ide_tp_ops = {
. exec_command = ide_exec_command ,
. read_status = ide_read_status ,
. read_altstatus = ide_read_altstatus ,
2009-03-31 22:15:30 +04:00
. write_devctl = ide_write_devctl ,
2008-07-23 21:55:56 +04:00
2009-03-31 22:15:32 +04:00
. dev_select = ide_dev_select ,
2008-07-23 21:55:56 +04:00
. tf_load = ide_tf_load ,
. tf_read = ide_tf_read ,
. input_data = q40ide_input_data ,
. output_data = q40ide_output_data ,
} ;
static const struct ide_port_info q40ide_port_info = {
. tp_ops = & q40ide_tp_ops ,
2009-03-27 14:46:23 +03:00
. host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA ,
2009-03-27 14:46:27 +03:00
. irq_flags = IRQF_SHARED ,
2009-05-17 21:12:22 +04:00
. chipset = ide_generic ,
2008-07-23 21:55:56 +04:00
} ;
2005-04-17 02:20:36 +04:00
/*
* the static array is needed to have the name reported in / proc / ioports ,
2007-10-20 01:21:04 +04:00
* hwif - > name unfortunately isn ' t available yet
2005-04-17 02:20:36 +04:00
*/
static const char * q40_ide_names [ Q40IDE_NUM_HWIFS ] = {
" ide0 " , " ide1 "
} ;
/*
* Probe for Q40 IDE interfaces
*/
2008-01-26 22:13:07 +03:00
static int __init q40ide_init ( void )
2005-04-17 02:20:36 +04:00
{
int i ;
2009-05-17 21:12:25 +04:00
struct ide_hw hw [ Q40IDE_NUM_HWIFS ] , * hws [ ] = { NULL , NULL } ;
2005-04-17 02:20:36 +04:00
if ( ! MACH_IS_Q40 )
2008-01-26 22:13:07 +03:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2008-01-26 22:13:09 +03:00
printk ( KERN_INFO " ide: Q40 IDE controller \n " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < Q40IDE_NUM_HWIFS ; i + + ) {
2008-07-23 21:55:50 +04:00
const char * name = q40_ide_names [ i ] ;
2005-04-17 02:20:36 +04:00
if ( ! request_region ( pcide_bases [ i ] , 8 , name ) ) {
printk ( " could not reserve ports %lx-%lx for %s \n " ,
pcide_bases [ i ] , pcide_bases [ i ] + 8 , name ) ;
continue ;
}
if ( ! request_region ( pcide_bases [ i ] + 0x206 , 1 , name ) ) {
printk ( " could not reserve port %lx for %s \n " ,
pcide_bases [ i ] + 0x206 , name ) ;
release_region ( pcide_bases [ i ] , 8 ) ;
continue ;
}
2009-06-15 20:52:58 +04:00
q40_ide_setup_ports ( & hw [ i ] , pcide_bases [ i ] ,
2005-04-17 02:20:36 +04:00
q40ide_default_irq ( pcide_bases [ i ] ) ) ;
2008-01-26 22:13:06 +03:00
2008-07-23 21:55:57 +04:00
hws [ i ] = & hw [ i ] ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 22:13:06 +03:00
2009-05-17 21:12:24 +04:00
return ide_host_add ( & q40ide_port_info , hws , Q40IDE_NUM_HWIFS , NULL ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 22:13:07 +03:00
module_init ( q40ide_init ) ;
2008-04-02 23:22:04 +04:00
MODULE_LICENSE ( " GPL " ) ;