2005-04-17 02:20:36 +04:00
/*
2007-02-06 03:28:25 +03:00
* TURBOchannel bus services .
2005-04-17 02:20:36 +04:00
*
2007-02-06 03:28:25 +03:00
* Copyright ( c ) Harald Koerfgen , 1998
* Copyright ( c ) 2001 , 2003 , 2005 , 2006 Maciej W . Rozycki
* Copyright ( c ) 2005 James Simmons
2005-04-17 02:20:36 +04:00
*
2007-02-06 03:28:25 +03:00
* 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 .
2005-04-17 02:20:36 +04:00
*/
2007-02-06 03:28:25 +03:00
# include <linux/compiler.h>
# include <linux/errno.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
2007-02-06 03:28:25 +03:00
# include <linux/ioport.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
2007-02-06 03:28:25 +03:00
# include <linux/list.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
2005-07-01 20:10:40 +04:00
# include <linux/string.h>
2007-02-06 03:28:25 +03:00
# include <linux/tc.h>
2005-07-01 20:10:40 +04:00
# include <linux/types.h>
2005-04-17 02:20:36 +04:00
2005-07-01 20:10:40 +04:00
# include <asm/io.h>
2007-02-06 03:28:25 +03:00
static struct tc_bus tc_bus = {
. name = " TURBOchannel " ,
} ;
2005-04-17 02:20:36 +04:00
/*
2007-02-06 03:28:25 +03:00
* Probing for TURBOchannel modules .
2005-04-17 02:20:36 +04:00
*/
2007-02-06 03:28:25 +03:00
static void __init tc_bus_add_devices ( struct tc_bus * tbus )
2005-04-17 02:20:36 +04:00
{
2007-02-06 03:28:25 +03:00
resource_size_t slotsize = tbus - > info . slot_size < < 20 ;
resource_size_t extslotsize = tbus - > ext_slot_size ;
resource_size_t slotaddr ;
resource_size_t extslotaddr ;
resource_size_t devsize ;
void __iomem * module ;
struct tc_dev * tdev ;
2005-04-17 02:20:36 +04:00
int i , slot , err ;
2005-07-01 20:10:40 +04:00
u8 pattern [ 4 ] ;
2007-02-06 03:28:25 +03:00
long offset ;
2005-04-17 02:20:36 +04:00
2007-02-06 03:28:25 +03:00
for ( slot = 0 ; slot < tbus - > num_tcslots ; slot + + ) {
slotaddr = tbus - > slot_base + slot * slotsize ;
extslotaddr = tbus - > ext_slot_base + slot * extslotsize ;
module = ioremap_nocache ( slotaddr , slotsize ) ;
2005-07-01 20:10:40 +04:00
BUG_ON ( ! module ) ;
2005-04-17 02:20:36 +04:00
2007-02-06 03:28:25 +03:00
offset = TC_OLDCARD ;
2005-04-17 02:20:36 +04:00
err = 0 ;
2007-02-06 03:28:25 +03:00
err | = tc_preadb ( pattern + 0 , module + offset + TC_PATTERN0 ) ;
err | = tc_preadb ( pattern + 1 , module + offset + TC_PATTERN1 ) ;
err | = tc_preadb ( pattern + 2 , module + offset + TC_PATTERN2 ) ;
err | = tc_preadb ( pattern + 3 , module + offset + TC_PATTERN3 ) ;
if ( err )
goto out_err ;
2005-04-17 02:20:36 +04:00
if ( pattern [ 0 ] ! = 0x55 | | pattern [ 1 ] ! = 0x00 | |
pattern [ 2 ] ! = 0xaa | | pattern [ 3 ] ! = 0xff ) {
2007-02-06 03:28:25 +03:00
offset = TC_NEWCARD ;
2005-04-17 02:20:36 +04:00
err = 0 ;
2007-02-06 03:28:25 +03:00
err | = tc_preadb ( pattern + 0 ,
module + offset + TC_PATTERN0 ) ;
err | = tc_preadb ( pattern + 1 ,
module + offset + TC_PATTERN1 ) ;
err | = tc_preadb ( pattern + 2 ,
module + offset + TC_PATTERN2 ) ;
err | = tc_preadb ( pattern + 3 ,
module + offset + TC_PATTERN3 ) ;
if ( err )
goto out_err ;
2005-04-17 02:20:36 +04:00
}
if ( pattern [ 0 ] ! = 0x55 | | pattern [ 1 ] ! = 0x00 | |
2007-02-06 03:28:25 +03:00
pattern [ 2 ] ! = 0xaa | | pattern [ 3 ] ! = 0xff )
goto out_err ;
/* Found a board, allocate it an entry in the list */
tdev = kzalloc ( sizeof ( * tdev ) , GFP_KERNEL ) ;
if ( ! tdev ) {
printk ( KERN_ERR " tc%x: unable to allocate tc_dev \n " ,
slot ) ;
goto out_err ;
2005-07-01 20:10:40 +04:00
}
2007-02-06 03:28:25 +03:00
sprintf ( tdev - > dev . bus_id , " tc%x " , slot ) ;
tdev - > bus = tbus ;
tdev - > dev . parent = & tbus - > dev ;
tdev - > dev . bus = & tc_bus_type ;
tdev - > slot = slot ;
2005-04-17 02:20:36 +04:00
2005-07-01 20:10:40 +04:00
for ( i = 0 ; i < 8 ; i + + ) {
2007-02-06 03:28:25 +03:00
tdev - > firmware [ i ] =
readb ( module + offset + TC_FIRM_VER + 4 * i ) ;
tdev - > vendor [ i ] =
readb ( module + offset + TC_VENDOR + 4 * i ) ;
tdev - > name [ i ] =
readb ( module + offset + TC_MODULE + 4 * i ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-06 03:28:25 +03:00
tdev - > firmware [ 8 ] = 0 ;
tdev - > vendor [ 8 ] = 0 ;
tdev - > name [ 8 ] = 0 ;
pr_info ( " %s: %s %s %s \n " , tdev - > dev . bus_id , tdev - > vendor ,
tdev - > name , tdev - > firmware ) ;
devsize = readb ( module + offset + TC_SLOT_SIZE ) ;
devsize < < = 22 ;
if ( devsize < = slotsize ) {
tdev - > resource . start = slotaddr ;
tdev - > resource . end = slotaddr + devsize - 1 ;
} else if ( devsize < = extslotsize ) {
tdev - > resource . start = extslotaddr ;
tdev - > resource . end = extslotaddr + devsize - 1 ;
} else {
printk ( KERN_ERR " %s: Cannot provide slot space "
" (%dMiB required, up to %dMiB supported) \n " ,
tdev - > dev . bus_id , devsize > > 20 ,
max ( slotsize , extslotsize ) > > 20 ) ;
kfree ( tdev ) ;
goto out_err ;
2005-04-17 02:20:36 +04:00
}
2007-02-06 03:28:25 +03:00
tdev - > resource . name = tdev - > name ;
tdev - > resource . flags = IORESOURCE_MEM ;
tc_device_get_irq ( tdev ) ;
2005-07-01 20:10:40 +04:00
2007-02-06 03:28:25 +03:00
device_register ( & tdev - > dev ) ;
list_add_tail ( & tdev - > node , & tbus - > devices ) ;
out_err :
2005-07-01 20:10:40 +04:00
iounmap ( module ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
2007-02-06 03:28:25 +03:00
* The main entry .
2005-04-17 02:20:36 +04:00
*/
2005-06-17 00:37:40 +04:00
static int __init tc_init ( void )
2005-04-17 02:20:36 +04:00
{
2007-02-06 03:28:25 +03:00
/* Initialize the TURBOchannel bus */
if ( tc_bus_get_info ( & tc_bus ) )
2005-06-17 00:37:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2007-02-06 03:28:25 +03:00
INIT_LIST_HEAD ( & tc_bus . devices ) ;
strcpy ( tc_bus . dev . bus_id , " tc " ) ;
device_register ( & tc_bus . dev ) ;
if ( tc_bus . info . slot_size ) {
unsigned int tc_clock = tc_get_speed ( & tc_bus ) / 100000 ;
pr_info ( " tc: TURBOchannel rev. %d at %d.%d MHz "
" (with%s parity) \n " , tc_bus . info . revision ,
tc_clock / 10 , tc_clock % 10 ,
tc_bus . info . parity ? " " : " out " ) ;
tc_bus . resource [ 0 ] . start = tc_bus . slot_base ;
tc_bus . resource [ 0 ] . end = tc_bus . slot_base +
( tc_bus . info . slot_size < < 20 ) *
2007-02-06 03:28:26 +03:00
tc_bus . num_tcslots - 1 ;
2007-02-06 03:28:25 +03:00
tc_bus . resource [ 0 ] . name = tc_bus . name ;
tc_bus . resource [ 0 ] . flags = IORESOURCE_MEM ;
if ( request_resource ( & iomem_resource ,
& tc_bus . resource [ 0 ] ) < 0 ) {
printk ( KERN_ERR " tc: Cannot reserve resource \n " ) ;
return 0 ;
}
if ( tc_bus . ext_slot_size ) {
tc_bus . resource [ 1 ] . start = tc_bus . ext_slot_base ;
tc_bus . resource [ 1 ] . end = tc_bus . ext_slot_base +
tc_bus . ext_slot_size *
2007-02-06 03:28:26 +03:00
tc_bus . num_tcslots - 1 ;
2007-02-06 03:28:25 +03:00
tc_bus . resource [ 1 ] . name = tc_bus . name ;
tc_bus . resource [ 1 ] . flags = IORESOURCE_MEM ;
if ( request_resource ( & iomem_resource ,
& tc_bus . resource [ 1 ] ) < 0 ) {
printk ( KERN_ERR
" tc: Cannot reserve resource \n " ) ;
release_resource ( & tc_bus . resource [ 0 ] ) ;
return 0 ;
}
2005-07-01 20:10:40 +04:00
}
2007-02-06 03:28:25 +03:00
tc_bus_add_devices ( & tc_bus ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-17 00:37:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
subsys_initcall ( tc_init ) ;