2005-04-16 15:20:36 -07:00
/* -*- mode: c; c-basic-offset: 8 -*- */
/* Copyright (C) 1999,2001
*
* Author : J . E . J . Bottomley @ HansenPartnership . com
*
* linux / arch / i386 / kernel / voyager_cat . c
*
* This file contains all the logic for manipulating the CAT bus
* in a level 5 machine .
*
* The CAT bus is a serial configuration and test bus . Its primary
* uses are to probe the initial configuration of the system and to
* diagnose error conditions when a system interrupt occurs . The low
* level interface is fairly primitive , so most of this file consists
* of bit shift manipulations to send and receive packets on the
* serial bus */
# include <linux/types.h>
# include <linux/completion.h>
# include <linux/sched.h>
# include <asm/voyager.h>
# include <asm/vic.h>
# include <linux/ioport.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <asm/io.h>
# ifdef VOYAGER_CAT_DEBUG
# define CDEBUG(x) printk x
# else
# define CDEBUG(x)
# endif
/* the CAT command port */
# define CAT_CMD (sspb + 0xe)
/* the CAT data port */
# define CAT_DATA (sspb + 0xd)
/* the internal cat functions */
2008-01-30 13:30:10 +01:00
static void cat_pack ( __u8 * msg , __u16 start_bit , __u8 * data , __u16 num_bits ) ;
static void cat_unpack ( __u8 * msg , __u16 start_bit , __u8 * data ,
2005-04-16 15:20:36 -07:00
__u16 num_bits ) ;
2008-01-30 13:30:10 +01:00
static void cat_build_header ( __u8 * header , const __u16 len ,
2005-04-16 15:20:36 -07:00
const __u16 smallest_reg_bits ,
const __u16 longest_reg_bits ) ;
2008-01-30 13:30:10 +01:00
static int cat_sendinst ( voyager_module_t * modp , voyager_asic_t * asicp ,
2005-04-16 15:20:36 -07:00
__u8 reg , __u8 op ) ;
2008-01-30 13:30:10 +01:00
static int cat_getdata ( voyager_module_t * modp , voyager_asic_t * asicp ,
__u8 reg , __u8 * value ) ;
static int cat_shiftout ( __u8 * data , __u16 data_bytes , __u16 header_bytes ,
2005-04-16 15:20:36 -07:00
__u8 pad_bits ) ;
2008-01-30 13:30:10 +01:00
static int cat_write ( voyager_module_t * modp , voyager_asic_t * asicp , __u8 reg ,
2005-04-16 15:20:36 -07:00
__u8 value ) ;
2008-01-30 13:30:10 +01:00
static int cat_read ( voyager_module_t * modp , voyager_asic_t * asicp , __u8 reg ,
__u8 * value ) ;
static int cat_subread ( voyager_module_t * modp , voyager_asic_t * asicp ,
2005-04-16 15:20:36 -07:00
__u16 offset , __u16 len , void * buf ) ;
2008-01-30 13:30:10 +01:00
static int cat_senddata ( voyager_module_t * modp , voyager_asic_t * asicp ,
2005-04-16 15:20:36 -07:00
__u8 reg , __u8 value ) ;
2008-01-30 13:30:10 +01:00
static int cat_disconnect ( voyager_module_t * modp , voyager_asic_t * asicp ) ;
static int cat_connect ( voyager_module_t * modp , voyager_asic_t * asicp ) ;
2005-04-16 15:20:36 -07:00
2008-01-30 13:30:10 +01:00
static inline const char * cat_module_name ( int module_id )
2005-04-16 15:20:36 -07:00
{
2008-01-30 13:30:10 +01:00
switch ( module_id ) {
2005-04-16 15:20:36 -07:00
case 0x10 :
return " Processor Slot 0 " ;
case 0x11 :
return " Processor Slot 1 " ;
case 0x12 :
return " Processor Slot 2 " ;
case 0x13 :
return " Processor Slot 4 " ;
case 0x14 :
return " Memory Slot 0 " ;
case 0x15 :
return " Memory Slot 1 " ;
case 0x18 :
return " Primary Microchannel " ;
case 0x19 :
return " Secondary Microchannel " ;
case 0x1a :
return " Power Supply Interface " ;
case 0x1c :
return " Processor Slot 5 " ;
case 0x1d :
return " Processor Slot 6 " ;
case 0x1e :
return " Processor Slot 7 " ;
case 0x1f :
return " Processor Slot 8 " ;
default :
return " Unknown Module " ;
}
}
static int sspb = 0 ; /* stores the super port location */
int voyager_8slot = 0 ; /* set to true if a 51xx monster */
voyager_module_t * voyager_cat_list ;
/* the I/O port assignments for the VIC and QIC */
static struct resource vic_res = {
2008-01-30 13:30:10 +01:00
. name = " Voyager Interrupt Controller " ,
. start = 0xFC00 ,
. end = 0xFC6F
2006-04-10 22:52:49 -07:00
} ;
2005-04-16 15:20:36 -07:00
static struct resource qic_res = {
2008-01-30 13:30:10 +01:00
. name = " Quad Interrupt Controller " ,
. start = 0xFC70 ,
. end = 0xFCFF
2006-04-10 22:52:49 -07:00
} ;
2005-04-16 15:20:36 -07:00
/* This function is used to pack a data bit stream inside a message.
* It writes num_bits of the data buffer in msg starting at start_bit .
* Note : This function assumes that any unused bit in the data stream
* is set to zero so that the ors will work correctly */
static void
2008-01-30 13:30:10 +01:00
cat_pack ( __u8 * msg , const __u16 start_bit , __u8 * data , const __u16 num_bits )
2005-04-16 15:20:36 -07:00
{
/* compute initial shift needed */
const __u16 offset = start_bit % BITS_PER_BYTE ;
__u16 len = num_bits / BITS_PER_BYTE ;
__u16 byte = start_bit / BITS_PER_BYTE ;
__u16 residue = ( num_bits % BITS_PER_BYTE ) + offset ;
int i ;
/* adjust if we have more than a byte of residue */
2008-01-30 13:30:10 +01:00
if ( residue > = BITS_PER_BYTE ) {
2005-04-16 15:20:36 -07:00
residue - = BITS_PER_BYTE ;
len + + ;
}
/* clear out the bits. We assume here that if len==0 then
* residue > = offset . This is always true for the catbus
* operations */
2008-01-30 13:30:10 +01:00
msg [ byte ] & = 0xff < < ( BITS_PER_BYTE - offset ) ;
2005-04-16 15:20:36 -07:00
msg [ byte + + ] | = data [ 0 ] > > offset ;
2008-01-30 13:30:10 +01:00
if ( len = = 0 )
2005-04-16 15:20:36 -07:00
return ;
2008-01-30 13:30:10 +01:00
for ( i = 1 ; i < len ; i + + )
msg [ byte + + ] = ( data [ i - 1 ] < < ( BITS_PER_BYTE - offset ) )
| ( data [ i ] > > offset ) ;
if ( residue ! = 0 ) {
2005-04-16 15:20:36 -07:00
__u8 mask = 0xff > > residue ;
2008-01-30 13:30:10 +01:00
__u8 last_byte = data [ i - 1 ] < < ( BITS_PER_BYTE - offset )
| ( data [ i ] > > offset ) ;
2005-04-16 15:20:36 -07:00
last_byte & = ~ mask ;
msg [ byte ] & = mask ;
msg [ byte ] | = last_byte ;
}
return ;
}
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
/* unpack the data again (same arguments as cat_pack()). data buffer
* must be zero populated .
*
* Function : given a message string move to start_bit and copy num_bits into
* data ( starting at bit 0 in data ) .
*/
static void
2008-01-30 13:30:10 +01:00
cat_unpack ( __u8 * msg , const __u16 start_bit , __u8 * data , const __u16 num_bits )
2005-04-16 15:20:36 -07:00
{
/* compute initial shift needed */
const __u16 offset = start_bit % BITS_PER_BYTE ;
__u16 len = num_bits / BITS_PER_BYTE ;
const __u8 last_bits = num_bits % BITS_PER_BYTE ;
__u16 byte = start_bit / BITS_PER_BYTE ;
int i ;
2008-01-30 13:30:10 +01:00
if ( last_bits ! = 0 )
2005-04-16 15:20:36 -07:00
len + + ;
/* special case: want < 8 bits from msg and we can get it from
* a single byte of the msg */
2008-01-30 13:30:10 +01:00
if ( len = = 0 & & BITS_PER_BYTE - offset > = num_bits ) {
2005-04-16 15:20:36 -07:00
data [ 0 ] = msg [ byte ] < < offset ;
data [ 0 ] & = 0xff > > ( BITS_PER_BYTE - num_bits ) ;
return ;
}
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < len ; i + + ) {
2005-04-16 15:20:36 -07:00
/* this annoying if has to be done just in case a read of
* msg one beyond the array causes a panic */
2008-01-30 13:30:10 +01:00
if ( offset ! = 0 ) {
2005-04-16 15:20:36 -07:00
data [ i ] = msg [ byte + + ] < < offset ;
data [ i ] | = msg [ byte ] > > ( BITS_PER_BYTE - offset ) ;
2008-01-30 13:30:10 +01:00
} else {
2005-04-16 15:20:36 -07:00
data [ i ] = msg [ byte + + ] ;
}
}
/* do we need to truncate the final byte */
2008-01-30 13:30:10 +01:00
if ( last_bits ! = 0 ) {
data [ i - 1 ] & = 0xff < < ( BITS_PER_BYTE - last_bits ) ;
2005-04-16 15:20:36 -07:00
}
return ;
}
static void
2008-01-30 13:30:10 +01:00
cat_build_header ( __u8 * header , const __u16 len , const __u16 smallest_reg_bits ,
2005-04-16 15:20:36 -07:00
const __u16 longest_reg_bits )
{
int i ;
__u16 start_bit = ( smallest_reg_bits - 1 ) % BITS_PER_BYTE ;
__u8 * last_byte = & header [ len - 1 ] ;
2008-01-30 13:30:10 +01:00
if ( start_bit = = 0 )
2005-04-16 15:20:36 -07:00
start_bit = 1 ; /* must have at least one bit in the hdr */
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < len ; i + + )
2005-04-16 15:20:36 -07:00
header [ i ] = 0 ;
2008-01-30 13:30:10 +01:00
for ( i = start_bit ; i > 0 ; i - - )
2005-04-16 15:20:36 -07:00
* last_byte = ( ( * last_byte ) < < 1 ) + 1 ;
}
static int
2008-01-30 13:30:10 +01:00
cat_sendinst ( voyager_module_t * modp , voyager_asic_t * asicp , __u8 reg , __u8 op )
2005-04-16 15:20:36 -07:00
{
__u8 parity , inst , inst_buf [ 4 ] = { 0 } ;
__u8 iseq [ VOYAGER_MAX_SCAN_PATH ] , hseq [ VOYAGER_MAX_REG_SIZE ] ;
__u16 ibytes , hbytes , padbits ;
int i ;
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
/*
* Parity is the parity of the register number + 1 ( READ_REGISTER
* and WRITE_REGISTER always add ' 1 ' to the number of bits = = 1 )
*/
2008-01-30 13:30:10 +01:00
parity = ( __u8 ) ( 1 + ( reg & 0x01 ) +
( ( __u8 ) ( reg & 0x02 ) > > 1 ) +
( ( __u8 ) ( reg & 0x04 ) > > 2 ) +
( ( __u8 ) ( reg & 0x08 ) > > 3 ) ) % 2 ;
2005-04-16 15:20:36 -07:00
inst = ( ( parity < < 7 ) | ( reg < < 2 ) | op ) ;
outb ( VOYAGER_CAT_IRCYC , CAT_CMD ) ;
2008-01-30 13:30:10 +01:00
if ( ! modp - > scan_path_connected ) {
if ( asicp - > asic_id ! = VOYAGER_CAT_ID ) {
printk
( " **WARNING***: cat_sendinst has disconnected scan path not to CAT asic \n " ) ;
2005-04-16 15:20:36 -07:00
return 1 ;
}
outb ( VOYAGER_CAT_HEADER , CAT_DATA ) ;
outb ( inst , CAT_DATA ) ;
2008-01-30 13:30:10 +01:00
if ( inb ( CAT_DATA ) ! = VOYAGER_CAT_HEADER ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " VOYAGER CAT: cat_sendinst failed to get CAT_HEADER \n " ) ) ;
return 1 ;
}
return 0 ;
}
ibytes = modp - > inst_bits / BITS_PER_BYTE ;
2008-01-30 13:30:10 +01:00
if ( ( padbits = modp - > inst_bits % BITS_PER_BYTE ) ! = 0 ) {
2005-04-16 15:20:36 -07:00
padbits = BITS_PER_BYTE - padbits ;
ibytes + + ;
}
hbytes = modp - > largest_reg / BITS_PER_BYTE ;
2008-01-30 13:30:10 +01:00
if ( modp - > largest_reg % BITS_PER_BYTE )
2005-04-16 15:20:36 -07:00
hbytes + + ;
CDEBUG ( ( " cat_sendinst: ibytes=%d, hbytes=%d \n " , ibytes , hbytes ) ) ;
/* initialise the instruction sequence to 0xff */
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < ibytes + hbytes ; i + + )
2005-04-16 15:20:36 -07:00
iseq [ i ] = 0xff ;
cat_build_header ( hseq , hbytes , modp - > smallest_reg , modp - > largest_reg ) ;
cat_pack ( iseq , modp - > inst_bits , hseq , hbytes * BITS_PER_BYTE ) ;
inst_buf [ 0 ] = inst ;
inst_buf [ 1 ] = 0xFF > > ( modp - > largest_reg % BITS_PER_BYTE ) ;
cat_pack ( iseq , asicp - > bit_location , inst_buf , asicp - > ireg_length ) ;
# ifdef VOYAGER_CAT_DEBUG
printk ( " ins = 0x%x, iseq: " , inst ) ;
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < ibytes + hbytes ; i + + )
2005-04-16 15:20:36 -07:00
printk ( " 0x%x " , iseq [ i ] ) ;
printk ( " \n " ) ;
# endif
2008-01-30 13:30:10 +01:00
if ( cat_shiftout ( iseq , ibytes , hbytes , padbits ) ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " VOYAGER CAT: cat_sendinst: cat_shiftout failed \n " ) ) ;
return 1 ;
}
CDEBUG ( ( " CAT SHIFTOUT DONE \n " ) ) ;
return 0 ;
}
static int
2008-01-30 13:30:10 +01:00
cat_getdata ( voyager_module_t * modp , voyager_asic_t * asicp , __u8 reg ,
__u8 * value )
2005-04-16 15:20:36 -07:00
{
2008-01-30 13:30:10 +01:00
if ( ! modp - > scan_path_connected ) {
if ( asicp - > asic_id ! = VOYAGER_CAT_ID ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " VOYAGER CAT: ERROR: cat_getdata to CAT asic with scan path connected \n " ) ) ;
return 1 ;
}
2008-01-30 13:30:10 +01:00
if ( reg > VOYAGER_SUBADDRHI )
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
outb ( VOYAGER_CAT_DRCYC , CAT_CMD ) ;
outb ( VOYAGER_CAT_HEADER , CAT_DATA ) ;
* value = inb ( CAT_DATA ) ;
outb ( 0xAA , CAT_DATA ) ;
2008-01-30 13:30:10 +01:00
if ( inb ( CAT_DATA ) ! = VOYAGER_CAT_HEADER ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_getdata: failed to get VOYAGER_CAT_HEADER \n " ) ) ;
return 1 ;
}
return 0 ;
2008-01-30 13:30:10 +01:00
} else {
__u16 sbits = modp - > num_asics - 1 + asicp - > ireg_length ;
2005-04-16 15:20:36 -07:00
__u16 sbytes = sbits / BITS_PER_BYTE ;
__u16 tbytes ;
2008-01-30 13:30:10 +01:00
__u8 string [ VOYAGER_MAX_SCAN_PATH ] ,
trailer [ VOYAGER_MAX_REG_SIZE ] ;
2005-04-16 15:20:36 -07:00
__u8 padbits ;
int i ;
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_DRCYC , CAT_CMD ) ;
2008-01-30 13:30:10 +01:00
if ( ( padbits = sbits % BITS_PER_BYTE ) ! = 0 ) {
2005-04-16 15:20:36 -07:00
padbits = BITS_PER_BYTE - padbits ;
sbytes + + ;
}
tbytes = asicp - > ireg_length / BITS_PER_BYTE ;
2008-01-30 13:30:10 +01:00
if ( asicp - > ireg_length % BITS_PER_BYTE )
2005-04-16 15:20:36 -07:00
tbytes + + ;
CDEBUG ( ( " cat_getdata: tbytes = %d, sbytes = %d, padbits = %d \n " ,
2008-01-30 13:30:10 +01:00
tbytes , sbytes , padbits ) ) ;
2005-04-16 15:20:36 -07:00
cat_build_header ( trailer , tbytes , 1 , asicp - > ireg_length ) ;
2008-01-30 13:30:10 +01:00
for ( i = tbytes - 1 ; i > = 0 ; i - - ) {
2005-04-16 15:20:36 -07:00
outb ( trailer [ i ] , CAT_DATA ) ;
string [ sbytes + i ] = inb ( CAT_DATA ) ;
}
2008-01-30 13:30:10 +01:00
for ( i = sbytes - 1 ; i > = 0 ; i - - ) {
2005-04-16 15:20:36 -07:00
outb ( 0xaa , CAT_DATA ) ;
string [ i ] = inb ( CAT_DATA ) ;
}
* value = 0 ;
2008-01-30 13:30:10 +01:00
cat_unpack ( string ,
padbits + ( tbytes * BITS_PER_BYTE ) +
asicp - > asic_location , value , asicp - > ireg_length ) ;
2005-04-16 15:20:36 -07:00
# ifdef VOYAGER_CAT_DEBUG
printk ( " value=0x%x, string: " , * value ) ;
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < tbytes + sbytes ; i + + )
2005-04-16 15:20:36 -07:00
printk ( " 0x%x " , string [ i ] ) ;
printk ( " \n " ) ;
# endif
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
/* sanity check the rest of the return */
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < tbytes ; i + + ) {
2005-04-16 15:20:36 -07:00
__u8 input = 0 ;
2008-01-30 13:30:10 +01:00
cat_unpack ( string , padbits + ( i * BITS_PER_BYTE ) ,
& input , BITS_PER_BYTE ) ;
if ( trailer [ i ] ! = input ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_getdata: failed to sanity check rest of ret(%d) 0x%x != 0x%x \n " , i , input , trailer [ i ] ) ) ;
return 1 ;
}
}
CDEBUG ( ( " cat_getdata DONE \n " ) ) ;
return 0 ;
}
}
static int
2008-01-30 13:30:10 +01:00
cat_shiftout ( __u8 * data , __u16 data_bytes , __u16 header_bytes , __u8 pad_bits )
2005-04-16 15:20:36 -07:00
{
int i ;
2008-01-30 13:30:10 +01:00
for ( i = data_bytes + header_bytes - 1 ; i > = header_bytes ; i - - )
2005-04-16 15:20:36 -07:00
outb ( data [ i ] , CAT_DATA ) ;
2008-01-30 13:30:10 +01:00
for ( i = header_bytes - 1 ; i > = 0 ; i - - ) {
2005-04-16 15:20:36 -07:00
__u8 header = 0 ;
__u8 input ;
outb ( data [ i ] , CAT_DATA ) ;
input = inb ( CAT_DATA ) ;
CDEBUG ( ( " cat_shiftout: returned 0x%x \n " , input ) ) ;
cat_unpack ( data , ( ( data_bytes + i ) * BITS_PER_BYTE ) - pad_bits ,
& header , BITS_PER_BYTE ) ;
2008-01-30 13:30:10 +01:00
if ( input ! = header ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " VOYAGER CAT: cat_shiftout failed to return header 0x%x != 0x%x \n " , input , header ) ) ;
return 1 ;
}
}
return 0 ;
}
static int
2008-01-30 13:30:10 +01:00
cat_senddata ( voyager_module_t * modp , voyager_asic_t * asicp ,
2005-04-16 15:20:36 -07:00
__u8 reg , __u8 value )
{
outb ( VOYAGER_CAT_DRCYC , CAT_CMD ) ;
2008-01-30 13:30:10 +01:00
if ( ! modp - > scan_path_connected ) {
if ( asicp - > asic_id ! = VOYAGER_CAT_ID ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " VOYAGER CAT: ERROR: scan path disconnected when asic != CAT \n " ) ) ;
return 1 ;
}
outb ( VOYAGER_CAT_HEADER , CAT_DATA ) ;
outb ( value , CAT_DATA ) ;
2008-01-30 13:30:10 +01:00
if ( inb ( CAT_DATA ) ! = VOYAGER_CAT_HEADER ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_senddata: failed to get correct header response to sent data \n " ) ) ;
return 1 ;
}
2008-01-30 13:30:10 +01:00
if ( reg > VOYAGER_SUBADDRHI ) {
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
}
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
return 0 ;
2008-01-30 13:30:10 +01:00
} else {
2005-04-16 15:20:36 -07:00
__u16 hbytes = asicp - > ireg_length / BITS_PER_BYTE ;
2008-01-30 13:30:10 +01:00
__u16 dbytes =
( modp - > num_asics - 1 + asicp - > ireg_length ) / BITS_PER_BYTE ;
__u8 padbits , dseq [ VOYAGER_MAX_SCAN_PATH ] ,
hseq [ VOYAGER_MAX_REG_SIZE ] ;
2005-04-16 15:20:36 -07:00
int i ;
2008-01-30 13:30:10 +01:00
if ( ( padbits = ( modp - > num_asics - 1
+ asicp - > ireg_length ) % BITS_PER_BYTE ) ! = 0 ) {
2005-04-16 15:20:36 -07:00
padbits = BITS_PER_BYTE - padbits ;
dbytes + + ;
}
2008-01-30 13:30:10 +01:00
if ( asicp - > ireg_length % BITS_PER_BYTE )
2005-04-16 15:20:36 -07:00
hbytes + + ;
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
cat_build_header ( hseq , hbytes , 1 , asicp - > ireg_length ) ;
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < dbytes + hbytes ; i + + )
2005-04-16 15:20:36 -07:00
dseq [ i ] = 0xff ;
CDEBUG ( ( " cat_senddata: dbytes=%d, hbytes=%d, padbits=%d \n " ,
dbytes , hbytes , padbits ) ) ;
cat_pack ( dseq , modp - > num_asics - 1 + asicp - > ireg_length ,
hseq , hbytes * BITS_PER_BYTE ) ;
2008-01-30 13:30:10 +01:00
cat_pack ( dseq , asicp - > asic_location , & value ,
2005-04-16 15:20:36 -07:00
asicp - > ireg_length ) ;
# ifdef VOYAGER_CAT_DEBUG
printk ( " dseq " ) ;
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < hbytes + dbytes ; i + + ) {
2005-04-16 15:20:36 -07:00
printk ( " 0x%x " , dseq [ i ] ) ;
}
printk ( " \n " ) ;
# endif
return cat_shiftout ( dseq , dbytes , hbytes , padbits ) ;
}
}
static int
2008-01-30 13:30:10 +01:00
cat_write ( voyager_module_t * modp , voyager_asic_t * asicp , __u8 reg , __u8 value )
2005-04-16 15:20:36 -07:00
{
2008-01-30 13:30:10 +01:00
if ( cat_sendinst ( modp , asicp , reg , VOYAGER_WRITE_CONFIG ) )
2005-04-16 15:20:36 -07:00
return 1 ;
return cat_senddata ( modp , asicp , reg , value ) ;
}
static int
2008-01-30 13:30:10 +01:00
cat_read ( voyager_module_t * modp , voyager_asic_t * asicp , __u8 reg ,
__u8 * value )
2005-04-16 15:20:36 -07:00
{
2008-01-30 13:30:10 +01:00
if ( cat_sendinst ( modp , asicp , reg , VOYAGER_READ_CONFIG ) )
2005-04-16 15:20:36 -07:00
return 1 ;
return cat_getdata ( modp , asicp , reg , value ) ;
}
static int
2008-01-30 13:30:10 +01:00
cat_subaddrsetup ( voyager_module_t * modp , voyager_asic_t * asicp , __u16 offset ,
2005-04-16 15:20:36 -07:00
__u16 len )
{
__u8 val ;
2008-01-30 13:30:10 +01:00
if ( len > 1 ) {
2005-04-16 15:20:36 -07:00
/* set auto increment */
__u8 newval ;
2008-01-30 13:30:10 +01:00
if ( cat_read ( modp , asicp , VOYAGER_AUTO_INC_REG , & val ) ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_subaddrsetup: read of VOYAGER_AUTO_INC_REG failed \n " ) ) ;
return 1 ;
}
2008-01-30 13:30:10 +01:00
CDEBUG ( ( " cat_subaddrsetup: VOYAGER_AUTO_INC_REG = 0x%x \n " ,
val ) ) ;
2005-04-16 15:20:36 -07:00
newval = val | VOYAGER_AUTO_INC ;
2008-01-30 13:30:10 +01:00
if ( newval ! = val ) {
if ( cat_write ( modp , asicp , VOYAGER_AUTO_INC_REG , val ) ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_subaddrsetup: write to VOYAGER_AUTO_INC_REG failed \n " ) ) ;
return 1 ;
}
}
}
2008-01-30 13:30:10 +01:00
if ( cat_write ( modp , asicp , VOYAGER_SUBADDRLO , ( __u8 ) ( offset & 0xff ) ) ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_subaddrsetup: write to SUBADDRLO failed \n " ) ) ;
return 1 ;
}
2008-01-30 13:30:10 +01:00
if ( asicp - > subaddr > VOYAGER_SUBADDR_LO ) {
if ( cat_write
( modp , asicp , VOYAGER_SUBADDRHI , ( __u8 ) ( offset > > 8 ) ) ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_subaddrsetup: write to SUBADDRHI failed \n " ) ) ;
return 1 ;
}
cat_read ( modp , asicp , VOYAGER_SUBADDRHI , & val ) ;
2008-01-30 13:30:10 +01:00
CDEBUG ( ( " cat_subaddrsetup: offset = %d, hi = %d \n " , offset ,
val ) ) ;
2005-04-16 15:20:36 -07:00
}
cat_read ( modp , asicp , VOYAGER_SUBADDRLO , & val ) ;
CDEBUG ( ( " cat_subaddrsetup: offset = %d, lo = %d \n " , offset , val ) ) ;
return 0 ;
}
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
static int
2008-01-30 13:30:10 +01:00
cat_subwrite ( voyager_module_t * modp , voyager_asic_t * asicp , __u16 offset ,
__u16 len , void * buf )
2005-04-16 15:20:36 -07:00
{
int i , retval ;
/* FIXME: need special actions for VOYAGER_CAT_ID here */
2008-01-30 13:30:10 +01:00
if ( asicp - > asic_id = = VOYAGER_CAT_ID ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_subwrite: ATTEMPT TO WRITE TO CAT ASIC \n " ) ) ;
/* FIXME -- This is supposed to be handled better
* There is a problem writing to the cat asic in the
* PSI . The 30u s delay seems to work , though */
udelay ( 30 ) ;
}
2008-01-30 13:30:10 +01:00
if ( ( retval = cat_subaddrsetup ( modp , asicp , offset , len ) ) ! = 0 ) {
2005-04-16 15:20:36 -07:00
printk ( " cat_subwrite: cat_subaddrsetup FAILED \n " ) ;
return retval ;
}
2008-01-30 13:30:10 +01:00
if ( cat_sendinst
( modp , asicp , VOYAGER_SUBADDRDATA , VOYAGER_WRITE_CONFIG ) ) {
2005-04-16 15:20:36 -07:00
printk ( " cat_subwrite: cat_sendinst FAILED \n " ) ;
return 1 ;
}
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < len ; i + + ) {
if ( cat_senddata ( modp , asicp , 0xFF , ( ( __u8 * ) buf ) [ i ] ) ) {
printk
( " cat_subwrite: cat_sendata element at %d FAILED \n " ,
i ) ;
2005-04-16 15:20:36 -07:00
return 1 ;
}
}
return 0 ;
}
static int
2008-01-30 13:30:10 +01:00
cat_subread ( voyager_module_t * modp , voyager_asic_t * asicp , __u16 offset ,
2005-04-16 15:20:36 -07:00
__u16 len , void * buf )
{
int i , retval ;
2008-01-30 13:30:10 +01:00
if ( ( retval = cat_subaddrsetup ( modp , asicp , offset , len ) ) ! = 0 ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_subread: cat_subaddrsetup FAILED \n " ) ) ;
return retval ;
}
2008-01-30 13:30:10 +01:00
if ( cat_sendinst ( modp , asicp , VOYAGER_SUBADDRDATA , VOYAGER_READ_CONFIG ) ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_subread: cat_sendinst failed \n " ) ) ;
return 1 ;
}
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < len ; i + + ) {
if ( cat_getdata ( modp , asicp , 0xFF , & ( ( __u8 * ) buf ) [ i ] ) ) {
CDEBUG ( ( " cat_subread: cat_getdata element %d failed \n " ,
i ) ) ;
2005-04-16 15:20:36 -07:00
return 1 ;
}
}
return 0 ;
}
/* buffer for storing EPROM data read in during initialisation */
static __initdata __u8 eprom_buf [ 0xFFFF ] ;
static voyager_module_t * voyager_initial_module ;
/* Initialise the cat bus components. We assume this is called by the
* boot cpu * after * all memory initialisation has been done ( so we can
* use kmalloc ) but before smp initialisation , so we can probe the SMP
* configuration and pick up necessary information . */
2008-01-30 13:30:10 +01:00
void __init voyager_cat_init ( void )
2005-04-16 15:20:36 -07:00
{
voyager_module_t * * modpp = & voyager_initial_module ;
voyager_asic_t * * asicpp ;
voyager_asic_t * qabc_asic = NULL ;
int i , j ;
unsigned long qic_addr = 0 ;
__u8 qabc_data [ 0x20 ] ;
__u8 num_submodules , val ;
2008-01-30 13:30:10 +01:00
voyager_eprom_hdr_t * eprom_hdr = ( voyager_eprom_hdr_t * ) & eprom_buf [ 0 ] ;
2005-04-16 15:20:36 -07:00
__u8 cmos [ 4 ] ;
unsigned long addr ;
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
/* initiallise the SUS mailbox */
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < sizeof ( cmos ) ; i + + )
2005-04-16 15:20:36 -07:00
cmos [ i ] = voyager_extended_cmos_read ( VOYAGER_DUMP_LOCATION + i ) ;
addr = * ( unsigned long * ) cmos ;
2008-01-30 13:30:10 +01:00
if ( ( addr & 0xff000000 ) ! = 0xff000000 ) {
printk ( KERN_ERR
" Voyager failed to get SUS mailbox (addr = 0x%lx \n " ,
addr ) ;
2005-04-16 15:20:36 -07:00
} else {
static struct resource res ;
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
res . name = " voyager SUS " ;
res . start = addr ;
2008-01-30 13:30:10 +01:00
res . end = addr + 0x3ff ;
2005-04-16 15:20:36 -07:00
request_resource ( & iomem_resource , & res ) ;
voyager_SUS = ( struct voyager_SUS * )
2008-01-30 13:30:10 +01:00
ioremap ( addr , 0x400 ) ;
2005-04-16 15:20:36 -07:00
printk ( KERN_NOTICE " Voyager SUS mailbox version 0x%x \n " ,
voyager_SUS - > SUS_version ) ;
voyager_SUS - > kernel_version = VOYAGER_MAILBOX_VERSION ;
voyager_SUS - > kernel_flags = VOYAGER_OS_HAS_SYSINT ;
}
/* clear the processor counts */
voyager_extended_vic_processors = 0 ;
voyager_quad_processors = 0 ;
printk ( " VOYAGER: beginning CAT bus probe \n " ) ;
/* set up the SuperSet Port Block which tells us where the
* CAT communication port is */
sspb = inb ( VOYAGER_SSPB_RELOCATION_PORT ) * 0x100 ;
VDEBUG ( ( " VOYAGER DEBUG: sspb = 0x%x \n " , sspb ) ) ;
/* now find out if were 8 slot or normal */
2008-01-30 13:30:10 +01:00
if ( ( inb ( VIC_PROC_WHO_AM_I ) & EIGHT_SLOT_IDENTIFIER )
= = EIGHT_SLOT_IDENTIFIER ) {
2005-04-16 15:20:36 -07:00
voyager_8slot = 1 ;
2008-01-30 13:30:10 +01:00
printk ( KERN_NOTICE
" Voyager: Eight slot 51xx configuration detected \n " ) ;
2005-04-16 15:20:36 -07:00
}
2008-01-30 13:30:10 +01:00
for ( i = VOYAGER_MIN_MODULE ; i < = VOYAGER_MAX_MODULE ; i + + ) {
2005-04-16 15:20:36 -07:00
__u8 input ;
int asic ;
__u16 eprom_size ;
__u16 sp_offset ;
outb ( VOYAGER_CAT_DESELECT , VOYAGER_CAT_CONFIG_PORT ) ;
outb ( i , VOYAGER_CAT_CONFIG_PORT ) ;
/* check the presence of the module */
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
outb ( VOYAGER_CAT_IRCYC , CAT_CMD ) ;
outb ( VOYAGER_CAT_HEADER , CAT_DATA ) ;
/* stream series of alternating 1's and 0's to stimulate
* response */
outb ( 0xAA , CAT_DATA ) ;
input = inb ( CAT_DATA ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
2008-01-30 13:30:10 +01:00
if ( input ! = VOYAGER_CAT_HEADER ) {
2005-04-16 15:20:36 -07:00
continue ;
}
CDEBUG ( ( " VOYAGER DEBUG: found module id 0x%x, %s \n " , i ,
cat_module_name ( i ) ) ) ;
2008-01-30 13:30:10 +01:00
* modpp = kmalloc ( sizeof ( voyager_module_t ) , GFP_KERNEL ) ; /*&voyager_module_storage[cat_count++]; */
if ( * modpp = = NULL ) {
2005-04-16 15:20:36 -07:00
printk ( " **WARNING** kmalloc failure in cat_init \n " ) ;
continue ;
}
memset ( * modpp , 0 , sizeof ( voyager_module_t ) ) ;
/* need temporary asic for cat_subread. It will be
* filled in correctly later */
2008-01-30 13:30:10 +01:00
( * modpp ) - > asic = kmalloc ( sizeof ( voyager_asic_t ) , GFP_KERNEL ) ; /*&voyager_asic_storage[asic_count]; */
if ( ( * modpp ) - > asic = = NULL ) {
2005-04-16 15:20:36 -07:00
printk ( " **WARNING** kmalloc failure in cat_init \n " ) ;
continue ;
}
memset ( ( * modpp ) - > asic , 0 , sizeof ( voyager_asic_t ) ) ;
( * modpp ) - > asic - > asic_id = VOYAGER_CAT_ID ;
( * modpp ) - > asic - > subaddr = VOYAGER_SUBADDR_HI ;
( * modpp ) - > module_addr = i ;
( * modpp ) - > scan_path_connected = 0 ;
2008-01-30 13:30:10 +01:00
if ( i = = VOYAGER_PSI ) {
2005-04-16 15:20:36 -07:00
/* Exception leg for modules with no EEPROM */
printk ( " Module \" %s \" \n " , cat_module_name ( i ) ) ;
continue ;
}
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_init: Reading eeprom for module 0x%x at offset %d \n " , i , VOYAGER_XSUM_END_OFFSET ) ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_disconnect ( * modpp , ( * modpp ) - > asic ) ;
2008-01-30 13:30:10 +01:00
if ( cat_subread ( * modpp , ( * modpp ) - > asic ,
VOYAGER_XSUM_END_OFFSET , sizeof ( eprom_size ) ,
& eprom_size ) ) {
printk
( " **WARNING**: Voyager couldn't read EPROM size for module 0x%x \n " ,
i ) ;
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
continue ;
}
2008-01-30 13:30:10 +01:00
if ( eprom_size > sizeof ( eprom_buf ) ) {
printk
( " **WARNING**: Voyager insufficient size to read EPROM data, module 0x%x. Need %d \n " ,
i , eprom_size ) ;
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
continue ;
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
2008-01-30 13:30:10 +01:00
CDEBUG ( ( " cat_init: module 0x%x, eeprom_size %d \n " , i ,
eprom_size ) ) ;
if ( cat_subread
( * modpp , ( * modpp ) - > asic , 0 , eprom_size , eprom_buf ) ) {
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
continue ;
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
printk ( " Module \" %s \" , version 0x%x, tracer 0x%x, asics %d \n " ,
cat_module_name ( i ) , eprom_hdr - > version_id ,
2008-01-30 13:30:10 +01:00
* ( ( __u32 * ) eprom_hdr - > tracer ) , eprom_hdr - > num_asics ) ;
2005-04-16 15:20:36 -07:00
( * modpp ) - > ee_size = eprom_hdr - > ee_size ;
( * modpp ) - > num_asics = eprom_hdr - > num_asics ;
asicpp = & ( ( * modpp ) - > asic ) ;
sp_offset = eprom_hdr - > scan_path_offset ;
/* All we really care about are the Quad cards. We
2008-01-30 13:30:10 +01:00
* identify them because they are in a processor slot
* and have only four asics */
if ( ( i < 0x10 | | ( i > = 0x14 & & i < 0x1c ) | | i > 0x1f ) ) {
2005-04-16 15:20:36 -07:00
modpp = & ( ( * modpp ) - > next ) ;
continue ;
}
/* Now we know it's in a processor slot, does it have
* a quad baseboard submodule */
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_read ( * modpp , ( * modpp ) - > asic , VOYAGER_SUBMODPRESENT ,
& num_submodules ) ;
/* lowest two bits, active low */
num_submodules = ~ ( 0xfc | num_submodules ) ;
2008-01-30 13:30:10 +01:00
CDEBUG ( ( " VOYAGER CAT: %d submodules present \n " ,
num_submodules ) ) ;
if ( num_submodules = = 0 ) {
2005-04-16 15:20:36 -07:00
/* fill in the dyadic extended processors */
__u8 cpu = i & 0x07 ;
printk ( " Module \" %s \" : Dyadic Processor Card \n " ,
cat_module_name ( i ) ) ;
2008-01-30 13:30:10 +01:00
voyager_extended_vic_processors | = ( 1 < < cpu ) ;
2005-04-16 15:20:36 -07:00
cpu + = 4 ;
2008-01-30 13:30:10 +01:00
voyager_extended_vic_processors | = ( 1 < < cpu ) ;
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
continue ;
}
/* now we want to read the asics on the first submodule,
* which should be the quad base board */
cat_read ( * modpp , ( * modpp ) - > asic , VOYAGER_SUBMODSELECT , & val ) ;
CDEBUG ( ( " cat_init: SUBMODSELECT value = 0x%x \n " , val ) ) ;
val = ( val & 0x7c ) | VOYAGER_QUAD_BASEBOARD ;
cat_write ( * modpp , ( * modpp ) - > asic , VOYAGER_SUBMODSELECT , val ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
CDEBUG ( ( " cat_init: Reading eeprom for module 0x%x at offset %d \n " , i , VOYAGER_XSUM_END_OFFSET ) ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_disconnect ( * modpp , ( * modpp ) - > asic ) ;
2008-01-30 13:30:10 +01:00
if ( cat_subread ( * modpp , ( * modpp ) - > asic ,
VOYAGER_XSUM_END_OFFSET , sizeof ( eprom_size ) ,
& eprom_size ) ) {
printk
( " **WARNING**: Voyager couldn't read EPROM size for module 0x%x \n " ,
i ) ;
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
continue ;
}
2008-01-30 13:30:10 +01:00
if ( eprom_size > sizeof ( eprom_buf ) ) {
printk
( " **WARNING**: Voyager insufficient size to read EPROM data, module 0x%x. Need %d \n " ,
i , eprom_size ) ;
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
continue ;
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
2008-01-30 13:30:10 +01:00
CDEBUG ( ( " cat_init: module 0x%x, eeprom_size %d \n " , i ,
eprom_size ) ) ;
if ( cat_subread
( * modpp , ( * modpp ) - > asic , 0 , eprom_size , eprom_buf ) ) {
2005-04-16 15:20:36 -07:00
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
continue ;
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
/* Now do everything for the QBB submodule 1 */
( * modpp ) - > ee_size = eprom_hdr - > ee_size ;
( * modpp ) - > num_asics = eprom_hdr - > num_asics ;
asicpp = & ( ( * modpp ) - > asic ) ;
sp_offset = eprom_hdr - > scan_path_offset ;
/* get rid of the dummy CAT asic and read the real one */
kfree ( ( * modpp ) - > asic ) ;
2008-01-30 13:30:10 +01:00
for ( asic = 0 ; asic < ( * modpp ) - > num_asics ; asic + + ) {
2005-04-16 15:20:36 -07:00
int j ;
2008-01-30 13:30:10 +01:00
voyager_asic_t * asicp = * asicpp = kzalloc ( sizeof ( voyager_asic_t ) , GFP_KERNEL ) ; /*&voyager_asic_storage[asic_count++]; */
2005-04-16 15:20:36 -07:00
voyager_sp_table_t * sp_table ;
voyager_at_t * asic_table ;
voyager_jtt_t * jtag_table ;
2008-01-30 13:30:10 +01:00
if ( asicp = = NULL ) {
printk
( " **WARNING** kmalloc failure in cat_init \n " ) ;
2005-04-16 15:20:36 -07:00
continue ;
}
asicpp = & ( asicp - > next ) ;
asicp - > asic_location = asic ;
2008-01-30 13:30:10 +01:00
sp_table =
( voyager_sp_table_t * ) ( eprom_buf + sp_offset ) ;
2005-04-16 15:20:36 -07:00
asicp - > asic_id = sp_table - > asic_id ;
2008-01-30 13:30:10 +01:00
asic_table =
( voyager_at_t * ) ( eprom_buf +
sp_table - > asic_data_offset ) ;
for ( j = 0 ; j < 4 ; j + + )
2005-04-16 15:20:36 -07:00
asicp - > jtag_id [ j ] = asic_table - > jtag_id [ j ] ;
2008-01-30 13:30:10 +01:00
jtag_table =
( voyager_jtt_t * ) ( eprom_buf +
asic_table - > jtag_offset ) ;
2005-04-16 15:20:36 -07:00
asicp - > ireg_length = jtag_table - > ireg_len ;
asicp - > bit_location = ( * modpp ) - > inst_bits ;
( * modpp ) - > inst_bits + = asicp - > ireg_length ;
2008-01-30 13:30:10 +01:00
if ( asicp - > ireg_length > ( * modpp ) - > largest_reg )
2005-04-16 15:20:36 -07:00
( * modpp ) - > largest_reg = asicp - > ireg_length ;
if ( asicp - > ireg_length < ( * modpp ) - > smallest_reg | |
( * modpp ) - > smallest_reg = = 0 )
( * modpp ) - > smallest_reg = asicp - > ireg_length ;
CDEBUG ( ( " asic 0x%x, ireg_length=%d, bit_location=%d \n " ,
asicp - > asic_id , asicp - > ireg_length ,
asicp - > bit_location ) ) ;
2008-01-30 13:30:10 +01:00
if ( asicp - > asic_id = = VOYAGER_QUAD_QABC ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " VOYAGER CAT: QABC ASIC found \n " ) ) ;
qabc_asic = asicp ;
}
sp_offset + = sizeof ( voyager_sp_table_t ) ;
}
2008-01-30 13:30:10 +01:00
CDEBUG ( ( " Module inst_bits = %d, largest_reg = %d, smallest_reg=%d \n " , ( * modpp ) - > inst_bits , ( * modpp ) - > largest_reg , ( * modpp ) - > smallest_reg ) ) ;
2005-04-16 15:20:36 -07:00
/* OK, now we have the QUAD ASICs set up, use them.
* we need to :
*
* 1. Find the Memory area for the Quad CPIs .
* 2. Find the Extended VIC processor
* 3. Configure a second extended VIC processor ( This
* cannot be done for the 51 xx .
* */
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_connect ( * modpp , ( * modpp ) - > asic ) ;
CDEBUG ( ( " CAT CONNECTED!! \n " ) ) ;
cat_subread ( * modpp , qabc_asic , 0 , sizeof ( qabc_data ) , qabc_data ) ;
qic_addr = qabc_data [ 5 ] < < 8 ;
qic_addr = ( qic_addr | qabc_data [ 6 ] ) < < 8 ;
qic_addr = ( qic_addr | qabc_data [ 7 ] ) < < 8 ;
2008-01-30 13:30:10 +01:00
printk
( " Module \" %s \" : Quad Processor Card; CPI 0x%lx, SET=0x%x \n " ,
cat_module_name ( i ) , qic_addr , qabc_data [ 8 ] ) ;
2005-04-16 15:20:36 -07:00
#if 0 /* plumbing fails---FIXME */
2008-01-30 13:30:10 +01:00
if ( ( qabc_data [ 8 ] & 0xf0 ) = = 0 ) {
2005-04-16 15:20:36 -07:00
/* FIXME: 32 way 8 CPU slot monster cannot be
* plumbed this way - - - need to check for it */
printk ( " Plumbing second Extended Quad Processor \n " ) ;
/* second VIC line hardwired to Quad CPU 1 */
qabc_data [ 8 ] | = 0x20 ;
cat_subwrite ( * modpp , qabc_asic , 8 , 1 , & qabc_data [ 8 ] ) ;
# ifdef VOYAGER_CAT_DEBUG
/* verify plumbing */
cat_subread ( * modpp , qabc_asic , 8 , 1 , & qabc_data [ 8 ] ) ;
2008-01-30 13:30:10 +01:00
if ( ( qabc_data [ 8 ] & 0xf0 ) = = 0 ) {
CDEBUG ( ( " PLUMBING FAILED: 0x%x \n " ,
qabc_data [ 8 ] ) ) ;
2005-04-16 15:20:36 -07:00
}
# endif
}
# endif
{
2008-01-30 13:30:10 +01:00
struct resource * res =
kzalloc ( sizeof ( struct resource ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
res - > name = kmalloc ( 128 , GFP_KERNEL ) ;
2008-01-30 13:30:10 +01:00
sprintf ( ( char * ) res - > name , " Voyager %s Quad CPI " ,
cat_module_name ( i ) ) ;
2005-04-16 15:20:36 -07:00
res - > start = qic_addr ;
res - > end = qic_addr + 0x3ff ;
request_resource ( & iomem_resource , res ) ;
}
qic_addr = ( unsigned long ) ioremap ( qic_addr , 0x400 ) ;
2008-01-30 13:30:10 +01:00
for ( j = 0 ; j < 4 ; j + + ) {
2005-04-16 15:20:36 -07:00
__u8 cpu ;
2008-01-30 13:30:10 +01:00
if ( voyager_8slot ) {
2005-04-16 15:20:36 -07:00
/* 8 slot has a different mapping,
* each slot has only one vic line , so
* 1 cpu in each slot must be < 8 */
2008-01-30 13:30:10 +01:00
cpu = ( i & 0x07 ) + j * 8 ;
2005-04-16 15:20:36 -07:00
} else {
2008-01-30 13:30:10 +01:00
cpu = ( i & 0x03 ) + j * 4 ;
2005-04-16 15:20:36 -07:00
}
2008-01-30 13:30:10 +01:00
if ( ( qabc_data [ 8 ] & ( 1 < < j ) ) ) {
voyager_extended_vic_processors | = ( 1 < < cpu ) ;
2005-04-16 15:20:36 -07:00
}
2008-01-30 13:30:10 +01:00
if ( qabc_data [ 8 ] & ( 1 < < ( j + 4 ) ) ) {
2005-04-16 15:20:36 -07:00
/* Second SET register plumbed: Quad
* card has two VIC connected CPUs .
* Secondary cannot be booted as a VIC
* CPU */
2008-01-30 13:30:10 +01:00
voyager_extended_vic_processors | = ( 1 < < cpu ) ;
voyager_allowed_boot_processors & =
( ~ ( 1 < < cpu ) ) ;
2005-04-16 15:20:36 -07:00
}
2008-01-30 13:30:10 +01:00
voyager_quad_processors | = ( 1 < < cpu ) ;
2005-04-16 15:20:36 -07:00
voyager_quad_cpi_addr [ cpu ] = ( struct voyager_qic_cpi * )
2008-01-30 13:30:10 +01:00
( qic_addr + ( j < < 8 ) ) ;
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " CPU%d: CPI address 0x%lx \n " , cpu ,
( unsigned long ) voyager_quad_cpi_addr [ cpu ] ) ) ;
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
* asicpp = NULL ;
modpp = & ( ( * modpp ) - > next ) ;
}
* modpp = NULL ;
2008-01-30 13:30:10 +01:00
printk
( " CAT Bus Initialisation finished: extended procs 0x%x, quad procs 0x%x, allowed vic boot = 0x%x \n " ,
voyager_extended_vic_processors , voyager_quad_processors ,
voyager_allowed_boot_processors ) ;
2005-04-16 15:20:36 -07:00
request_resource ( & ioport_resource , & vic_res ) ;
2008-01-30 13:30:10 +01:00
if ( voyager_quad_processors )
2005-04-16 15:20:36 -07:00
request_resource ( & ioport_resource , & qic_res ) ;
/* set up the front power switch */
}
2008-01-30 13:30:10 +01:00
int voyager_cat_readb ( __u8 module , __u8 asic , int reg )
2005-04-16 15:20:36 -07:00
{
return 0 ;
}
2008-01-30 13:30:10 +01:00
static int cat_disconnect ( voyager_module_t * modp , voyager_asic_t * asicp )
2005-04-16 15:20:36 -07:00
{
__u8 val ;
int err = 0 ;
2008-01-30 13:30:10 +01:00
if ( ! modp - > scan_path_connected )
2005-04-16 15:20:36 -07:00
return 0 ;
2008-01-30 13:30:10 +01:00
if ( asicp - > asic_id ! = VOYAGER_CAT_ID ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_disconnect: ASIC is not CAT \n " ) ) ;
return 1 ;
}
err = cat_read ( modp , asicp , VOYAGER_SCANPATH , & val ) ;
2008-01-30 13:30:10 +01:00
if ( err ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_disconnect: failed to read SCANPATH \n " ) ) ;
return err ;
}
val & = VOYAGER_DISCONNECT_ASIC ;
err = cat_write ( modp , asicp , VOYAGER_SCANPATH , val ) ;
2008-01-30 13:30:10 +01:00
if ( err ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_disconnect: failed to write SCANPATH \n " ) ) ;
return err ;
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
modp - > scan_path_connected = 0 ;
return 0 ;
}
2008-01-30 13:30:10 +01:00
static int cat_connect ( voyager_module_t * modp , voyager_asic_t * asicp )
2005-04-16 15:20:36 -07:00
{
__u8 val ;
int err = 0 ;
2008-01-30 13:30:10 +01:00
if ( modp - > scan_path_connected )
2005-04-16 15:20:36 -07:00
return 0 ;
2008-01-30 13:30:10 +01:00
if ( asicp - > asic_id ! = VOYAGER_CAT_ID ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_connect: ASIC is not CAT \n " ) ) ;
return 1 ;
}
err = cat_read ( modp , asicp , VOYAGER_SCANPATH , & val ) ;
2008-01-30 13:30:10 +01:00
if ( err ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_connect: failed to read SCANPATH \n " ) ) ;
return err ;
}
val | = VOYAGER_CONNECT_ASIC ;
err = cat_write ( modp , asicp , VOYAGER_SCANPATH , val ) ;
2008-01-30 13:30:10 +01:00
if ( err ) {
2005-04-16 15:20:36 -07:00
CDEBUG ( ( " cat_connect: failed to write SCANPATH \n " ) ) ;
return err ;
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
modp - > scan_path_connected = 1 ;
return 0 ;
}
2008-01-30 13:30:10 +01:00
void voyager_cat_power_off ( void )
2005-04-16 15:20:36 -07:00
{
/* Power the machine off by writing to the PSI over the CAT
2008-01-30 13:30:10 +01:00
* bus */
2005-04-16 15:20:36 -07:00
__u8 data ;
voyager_module_t psi = { 0 } ;
voyager_asic_t psi_asic = { 0 } ;
psi . asic = & psi_asic ;
psi . asic - > asic_id = VOYAGER_CAT_ID ;
psi . asic - > subaddr = VOYAGER_SUBADDR_HI ;
psi . module_addr = VOYAGER_PSI ;
psi . scan_path_connected = 0 ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
/* Connect the PSI to the CAT Bus */
outb ( VOYAGER_CAT_DESELECT , VOYAGER_CAT_CONFIG_PORT ) ;
outb ( VOYAGER_PSI , VOYAGER_CAT_CONFIG_PORT ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_disconnect ( & psi , & psi_asic ) ;
/* Read the status */
cat_subread ( & psi , & psi_asic , VOYAGER_PSI_GENERAL_REG , 1 , & data ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
CDEBUG ( ( " PSI STATUS 0x%x \n " , data ) ) ;
/* These two writes are power off prep and perform */
data = PSI_CLEAR ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_subwrite ( & psi , & psi_asic , VOYAGER_PSI_GENERAL_REG , 1 , & data ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
data = PSI_POWER_DOWN ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_subwrite ( & psi , & psi_asic , VOYAGER_PSI_GENERAL_REG , 1 , & data ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
}
struct voyager_status voyager_status = { 0 } ;
2008-01-30 13:30:10 +01:00
void voyager_cat_psi ( __u8 cmd , __u16 reg , __u8 * data )
2005-04-16 15:20:36 -07:00
{
voyager_module_t psi = { 0 } ;
voyager_asic_t psi_asic = { 0 } ;
psi . asic = & psi_asic ;
psi . asic - > asic_id = VOYAGER_CAT_ID ;
psi . asic - > subaddr = VOYAGER_SUBADDR_HI ;
psi . module_addr = VOYAGER_PSI ;
psi . scan_path_connected = 0 ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
/* Connect the PSI to the CAT Bus */
outb ( VOYAGER_CAT_DESELECT , VOYAGER_CAT_CONFIG_PORT ) ;
outb ( VOYAGER_PSI , VOYAGER_CAT_CONFIG_PORT ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_disconnect ( & psi , & psi_asic ) ;
2008-01-30 13:30:10 +01:00
switch ( cmd ) {
2005-04-16 15:20:36 -07:00
case VOYAGER_PSI_READ :
cat_read ( & psi , & psi_asic , reg , data ) ;
break ;
case VOYAGER_PSI_WRITE :
cat_write ( & psi , & psi_asic , reg , * data ) ;
break ;
case VOYAGER_PSI_SUBREAD :
cat_subread ( & psi , & psi_asic , reg , 1 , data ) ;
break ;
case VOYAGER_PSI_SUBWRITE :
cat_subwrite ( & psi , & psi_asic , reg , 1 , data ) ;
break ;
default :
printk ( KERN_ERR " Voyager PSI, unrecognised command %d \n " , cmd ) ;
break ;
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
}
2008-01-30 13:30:10 +01:00
void voyager_cat_do_common_interrupt ( void )
2005-04-16 15:20:36 -07:00
{
/* This is caused either by a memory parity error or something
* in the PSI */
__u8 data ;
voyager_module_t psi = { 0 } ;
voyager_asic_t psi_asic = { 0 } ;
struct voyager_psi psi_reg ;
int i ;
2008-01-30 13:30:10 +01:00
re_read :
2005-04-16 15:20:36 -07:00
psi . asic = & psi_asic ;
psi . asic - > asic_id = VOYAGER_CAT_ID ;
psi . asic - > subaddr = VOYAGER_SUBADDR_HI ;
psi . module_addr = VOYAGER_PSI ;
psi . scan_path_connected = 0 ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
/* Connect the PSI to the CAT Bus */
outb ( VOYAGER_CAT_DESELECT , VOYAGER_CAT_CONFIG_PORT ) ;
outb ( VOYAGER_PSI , VOYAGER_CAT_CONFIG_PORT ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_disconnect ( & psi , & psi_asic ) ;
/* Read the status. NOTE: Need to read *all* the PSI regs here
* otherwise the cmn int will be reasserted */
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < sizeof ( psi_reg . regs ) ; i + + ) {
cat_read ( & psi , & psi_asic , i , & ( ( __u8 * ) & psi_reg . regs ) [ i ] ) ;
2005-04-16 15:20:36 -07:00
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
2008-01-30 13:30:10 +01:00
if ( ( psi_reg . regs . checkbit & 0x02 ) = = 0 ) {
2005-04-16 15:20:36 -07:00
psi_reg . regs . checkbit | = 0x02 ;
cat_write ( & psi , & psi_asic , 5 , psi_reg . regs . checkbit ) ;
printk ( " VOYAGER RE-READ PSI \n " ) ;
goto re_read ;
}
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < sizeof ( psi_reg . subregs ) ; i + + ) {
2005-04-16 15:20:36 -07:00
/* This looks strange, but the PSI doesn't do auto increment
* correctly */
2008-01-30 13:30:10 +01:00
cat_subread ( & psi , & psi_asic , VOYAGER_PSI_SUPPLY_REG + i ,
1 , & ( ( __u8 * ) & psi_reg . subregs ) [ i ] ) ;
2005-04-16 15:20:36 -07:00
}
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
# ifdef VOYAGER_CAT_DEBUG
printk ( " VOYAGER PSI: " ) ;
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < sizeof ( psi_reg . regs ) ; i + + )
printk ( " %02x " , ( ( __u8 * ) & psi_reg . regs ) [ i ] ) ;
2005-04-16 15:20:36 -07:00
printk ( " \n " ) ;
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < sizeof ( psi_reg . subregs ) ; i + + )
printk ( " %02x " , ( ( __u8 * ) & psi_reg . subregs ) [ i ] ) ;
2005-04-16 15:20:36 -07:00
printk ( " \n " ) ;
# endif
2008-01-30 13:30:10 +01:00
if ( psi_reg . regs . intstatus & PSI_MON ) {
2005-04-16 15:20:36 -07:00
/* switch off or power fail */
2008-01-30 13:30:10 +01:00
if ( psi_reg . subregs . supply & PSI_SWITCH_OFF ) {
if ( voyager_status . switch_off ) {
printk ( KERN_ERR
" Voyager front panel switch turned off again---Immediate power off! \n " ) ;
2005-04-16 15:20:36 -07:00
voyager_cat_power_off ( ) ;
/* not reached */
} else {
2008-01-30 13:30:10 +01:00
printk ( KERN_ERR
" Voyager front panel switch turned off \n " ) ;
2005-04-16 15:20:36 -07:00
voyager_status . switch_off = 1 ;
voyager_status . request_from_kernel = 1 ;
2007-04-22 20:30:43 +01:00
wake_up_process ( voyager_thread ) ;
2005-04-16 15:20:36 -07:00
}
/* Tell the hardware we're taking care of the
* shutdown , otherwise it will power the box off
* within 3 seconds of the switch being pressed and ,
* which is much more important to us , continue to
* assert the common interrupt */
data = PSI_CLR_SWITCH_OFF ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_subwrite ( & psi , & psi_asic , VOYAGER_PSI_SUPPLY_REG ,
1 , & data ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
} else {
VDEBUG ( ( " Voyager ac fail reg 0x%x \n " ,
psi_reg . subregs . ACfail ) ) ;
2008-01-30 13:30:10 +01:00
if ( ( psi_reg . subregs . ACfail & AC_FAIL_STAT_CHANGE ) = = 0 ) {
2005-04-16 15:20:36 -07:00
/* No further update */
return ;
}
#if 0
/* Don't bother trying to find out who failed.
* FIXME : This probably makes the code incorrect on
* anything other than a 345 x */
2008-01-30 13:30:10 +01:00
for ( i = 0 ; i < 5 ; i + + ) {
if ( psi_reg . subregs . ACfail & ( 1 < < i ) ) {
2005-04-16 15:20:36 -07:00
break ;
}
}
printk ( KERN_NOTICE " AC FAIL IN SUPPLY %d \n " , i ) ;
# endif
/* DON'T do this: it shuts down the AC PSI
2008-01-30 13:30:10 +01:00
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
data = PSI_MASK_MASK | i ;
cat_subwrite ( & psi , & psi_asic , VOYAGER_PSI_MASK ,
1 , & data ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
*/
2005-04-16 15:20:36 -07:00
printk ( KERN_ERR " Voyager AC power failure \n " ) ;
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
data = PSI_COLD_START ;
cat_subwrite ( & psi , & psi_asic , VOYAGER_PSI_GENERAL_REG ,
1 , & data ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
voyager_status . power_fail = 1 ;
voyager_status . request_from_kernel = 1 ;
2007-04-22 20:30:43 +01:00
wake_up_process ( voyager_thread ) ;
2005-04-16 15:20:36 -07:00
}
2008-01-30 13:30:10 +01:00
} else if ( psi_reg . regs . intstatus & PSI_FAULT ) {
2005-04-16 15:20:36 -07:00
/* Major fault! */
2008-01-30 13:30:10 +01:00
printk ( KERN_ERR
" Voyager PSI Detected major fault, immediate power off! \n " ) ;
2005-04-16 15:20:36 -07:00
voyager_cat_power_off ( ) ;
/* not reached */
2008-01-30 13:30:10 +01:00
} else if ( psi_reg . regs . intstatus & ( PSI_DC_FAIL | PSI_ALARM
| PSI_CURRENT | PSI_DVM
| PSI_PSCFAULT | PSI_STAT_CHG ) ) {
2005-04-16 15:20:36 -07:00
/* other psi fault */
printk ( KERN_WARNING " Voyager PSI status 0x%x \n " , data ) ;
/* clear the PSI fault */
outb ( VOYAGER_CAT_RUN , CAT_CMD ) ;
cat_write ( & psi , & psi_asic , VOYAGER_PSI_STATUS_REG , 0 ) ;
outb ( VOYAGER_CAT_END , CAT_CMD ) ;
}
}