aboutsummaryrefslogblamecommitdiffstats
path: root/drivers/block/paride/epia.c
blob: 0f2e0c292d8245c680b41a6d4128c691b06c594b (plain) (tree)



























































































































































































































































































































                                                                                
/* 
        epia.c    (c) 1997-8  Grant R. Guenther <grant@torque.net>
                              Under the terms of the GNU General Public License.

        epia.c is a low-level protocol driver for Shuttle Technologies 
	EPIA parallel to IDE adapter chip.  This device is now obsolete
	and has been replaced with the EPAT chip, which is supported
	by epat.c, however, some devices based on EPIA are still
	available.

*/

/* Changes:

        1.01    GRG 1998.05.06 init_proto, release_proto
	1.02    GRG 1998.06.17 support older versions of EPIA

*/

#define EPIA_VERSION      "1.02"

#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <asm/io.h>

#include "paride.h"

/* mode codes:  0  nybble reads on port 1, 8-bit writes
                1  5/3 reads on ports 1 & 2, 8-bit writes
                2  8-bit reads and writes
                3  8-bit EPP mode
		4  16-bit EPP
		5  32-bit EPP
*/

#define j44(a,b)                (((a>>4)&0x0f)+(b&0xf0))
#define j53(a,b)                (((a>>3)&0x1f)+((b<<4)&0xe0))

/* cont =  0   IDE register file
   cont =  1   IDE control registers
*/

static int cont_map[2] = { 0, 0x80 };

static int epia_read_regr( PIA *pi, int cont, int regr )

{       int     a, b, r;

	regr += cont_map[cont];

        switch (pi->mode)  {

        case 0: r = regr^0x39;
                w0(r); w2(1); w2(3); w0(r);
                a = r1(); w2(1); b = r1(); w2(4);
                return j44(a,b);

        case 1: r = regr^0x31;
                w0(r); w2(1); w0(r&0x37); 
                w2(3); w2(5); w0(r|0xf0);
                a = r1(); b = r2(); w2(4);
                return j53(a,b);

        case 2: r = regr^0x29;
                w0(r); w2(1); w2(0X21); w2(0x23); 
                a = r0(); w2(4);
                return a;

	case 3:
	case 4:
        case 5: w3(regr); w2(0x24); a = r4(); w2(4);
                return a;

        }
        return -1;
}       

static void epia_write_regr( PIA *pi, int cont, int regr, int val)

{       int  r;

	regr += cont_map[cont];

        switch (pi->mode)  {

        case 0:
        case 1:
        case 2: r = regr^0x19;
                w0(r); w2(1); w0(val); w2(3); w2(4);
                break;

	case 3:
	case 4:
        case 5: r = regr^0x40;
                w3(r); w4(val); w2(4);
                break;
        }
}

#define WR(r,v)         epia_write_regr(pi,0,r,v)
#define RR(r)           (epia_read_regr(pi,0,r))

/* The use of register 0x84 is entirely unclear - it seems to control
   some EPP counters ...  currently we know about 3 different block
   sizes:  the standard 512 byte reads and writes, 12 byte writes and 
   2048 byte reads (the last two being used in the CDrom drivers.
*/

static void epia_connect ( PIA *pi  )

{       pi->saved_r0 = r0();
        pi->saved_r2 = r2();

        w2(4); w0(0xa0); w0(0x50); w0(0xc0); w0(0x30); w0(0xa0); w0(0);
        w2(1); w2(4);
        if (pi->mode >= 3) { 
                w0(0xa); w2(1); w2(4); w0(0x82); w2(4); w2(0xc); w2(4);
                w2(0x24); w2(0x26); w2(4);
        }
        WR(0x86,8);  
}

static void epia_disconnect ( PIA *pi )

{       /* WR(0x84,0x10); */
        w0(pi->saved_r0);
        w2(1); w2(4);
        w0(pi->saved_r0);
        w2(pi->saved_r2);
} 

static void epia_read_block( PIA *pi, char * buf, int count )

{       int     k, ph, a, b;

        switch (pi->mode) {

        case 0: w0(0x81); w2(1); w2(3); w0(0xc1);
                ph = 1;
                for (k=0;k<count;k++) {
                        w2(2+ph); a = r1();
                        w2(4+ph); b = r1();
                        buf[k] = j44(a,b);
                        ph = 1 - ph;
                } 
                w0(0); w2(4);
                break;

        case 1: w0(0x91); w2(1); w0(0x10); w2(3); 
                w0(0x51); w2(5); w0(0xd1); 
                ph = 1;
                for (k=0;k<count;k++) {
                        w2(4+ph);
                        a = r1(); b = r2();
                        buf[k] = j53(a,b);
                        ph = 1 - ph;
                }
                w0(0); w2(4);
                break;

        case 2: w0(0x89); w2(1); w2(0x23); w2(0x21); 
                ph = 1;
                for (k=0;k<count;k++) {
                        w2(0x24+ph);
                        buf[k] = r0();
                        ph = 1 - ph;
                }
                w2(6); w2(4);
                break;

        case 3: if (count > 512) WR(0x84,3);
		w3(0); w2(0x24);
                for (k=0;k<count;k++) buf[k] = r4();
                w2(4); WR(0x84,0);
                break;

        case 4: if (count > 512) WR(0x84,3);
		w3(0); w2(0x24);
		for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w();
                w2(4); WR(0x84,0);
                break;

        case 5: if (count > 512) WR(0x84,3);
		w3(0); w2(0x24);
                for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l();
                w2(4); WR(0x84,0);
                break;

        }
}

static void epia_write_block( PIA *pi, char * buf, int count )

{       int     ph, k, last, d;

        switch (pi->mode) {

        case 0:
        case 1:
        case 2: w0(0xa1); w2(1); w2(3); w2(1); w2(5);
                ph = 0;  last = 0x8000;
                for (k=0;k<count;k++) {
                        d = buf[k];
                        if (d != last) { last = d; w0(d); }
                        w2(4+ph);
                        ph = 1 - ph;
                }
                w2(7); w2(4);
                break;

        case 3: if (count < 512) WR(0x84,1);
		w3(0x40);
                for (k=0;k<count;k++) w4(buf[k]);
		if (count < 512) WR(0x84,0);
                break;

        case 4: if (count < 512) WR(0x84,1);
		w3(0x40);
                for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
		if (count < 512) WR(0x84,0);
                break;

        case 5: if (count < 512) WR(0x84,1);
		w3(0x40);
                for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
		if (count < 512) WR(0x84,0);
                break;

        }

}

static int epia_test_proto( PIA *pi, char * scratch, int verbose )

{       int     j, k, f;
	int	e[2] = {0,0};

        epia_connect(pi);
        for (j=0;j<2;j++) {
            WR(6,0xa0+j*0x10);
            for (k=0;k<256;k++) {
                WR(2,k^0xaa);
                WR(3,k^0x55);
                if (RR(2) != (k^0xaa)) e[j]++;
                }
	    WR(2,1); WR(3,1);
            }
        epia_disconnect(pi);

        f = 0;
        epia_connect(pi);
        WR(0x84,8);
        epia_read_block(pi,scratch,512);
        for (k=0;k<256;k++) {
            if ((scratch[2*k] & 0xff) != ((k+1) & 0xff)) f++;
            if ((scratch[2*k+1] & 0xff) != ((-2-k) & 0xff)) f++;
        }
        WR(0x84,0);
        epia_disconnect(pi);

        if (verbose)  {
            printk("%s: epia: port 0x%x, mode %d, test=(%d,%d,%d)\n",
                   pi->device,pi->port,pi->mode,e[0],e[1],f);
        }
        
        return (e[0] && e[1]) || f;

}


static void epia_log_adapter( PIA *pi, char * scratch, int verbose )

{       char    *mode_string[6] = {"4-bit","5/3","8-bit",
				   "EPP-8","EPP-16","EPP-32"};

        printk("%s: epia %s, Shuttle EPIA at 0x%x, ",
                pi->device,EPIA_VERSION,pi->port);
        printk("mode %d (%s), delay %d\n",pi->mode,
		mode_string[pi->mode],pi->delay);

}

static struct pi_protocol epia = {
	.owner		= THIS_MODULE,
	.name		= "epia",
	.max_mode	= 6,
	.epp_first	= 3,
	.default_delay	= 1,
	.max_units	= 1,
	.write_regr	= epia_write_regr,
	.read_regr	= epia_read_regr,
	.write_block	= epia_write_block,
	.read_block	= epia_read_block,
	.connect	= epia_connect,
	.disconnect	= epia_disconnect,
	.test_proto	= epia_test_proto,
	.log_adapter	= epia_log_adapter,
};

static int __init epia_init(void)
{
	return pi_register(&epia)-1;
}

static void __exit epia_exit(void)
{
	pi_unregister(&epia);
}

MODULE_LICENSE("GPL");
module_init(epia_init)
module_exit(epia_exit)
efine PA_ENET_TXD ((ushort)0x0008) #define PA_ENET_TCLK ((ushort)0x0200) #define PA_ENET_RCLK ((ushort)0x0800) #define PB_ENET_TENA ((uint)0x00002000) #define PC_ENET_CLSN ((ushort)0x0040) #define PC_ENET_RENA ((ushort)0x0080) #define SICR_ENET_MASK ((uint)0x0000ff00) #define SICR_ENET_CLKRT ((uint)0x00003d00) #endif #ifdef CONFIG_BSEIP /* This ENET stuff is for the MPC823 with ethernet on SCC2. * This is unique to the BSE ip-Engine board. */ #define PA_ENET_RXD ((ushort)0x0004) #define PA_ENET_TXD ((ushort)0x0008) #define PA_ENET_TCLK ((ushort)0x0100) #define PA_ENET_RCLK ((ushort)0x0200) #define PB_ENET_TENA ((uint)0x00002000) #define PC_ENET_CLSN ((ushort)0x0040) #define PC_ENET_RENA ((ushort)0x0080) /* BSE uses port B and C bits for PHY control also. */ #define PB_BSE_POWERUP ((uint)0x00000004) #define PB_BSE_FDXDIS ((uint)0x00008000) #define PC_BSE_LOOPBACK ((ushort)0x0800) #define SICR_ENET_MASK ((uint)0x0000ff00) #define SICR_ENET_CLKRT ((uint)0x00002c00) #endif #ifdef CONFIG_RPXCLASSIC /* Bits in parallel I/O port registers that have to be set/cleared * to configure the pins for SCC1 use. */ #define PA_ENET_RXD ((ushort)0x0001) #define PA_ENET_TXD ((ushort)0x0002) #define PA_ENET_TCLK ((ushort)0x0200) #define PA_ENET_RCLK ((ushort)0x0800) #define PB_ENET_TENA ((uint)0x00001000) #define PC_ENET_CLSN ((ushort)0x0010) #define PC_ENET_RENA ((ushort)0x0020) /* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. */ #define SICR_ENET_MASK ((uint)0x000000ff) #define SICR_ENET_CLKRT ((uint)0x0000003d) #endif /* SCC Event register as used by Ethernet. */ #define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ #define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */ #define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */ #define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */ #define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ #define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ /* SCC Mode Register (PMSR) as used by Ethernet. */ #define SCC_PMSR_HBC ((ushort)0x8000) /* Enable heartbeat */ #define SCC_PMSR_FC ((ushort)0x4000) /* Force collision */ #define SCC_PMSR_RSH ((ushort)0x2000) /* Receive short frames */ #define SCC_PMSR_IAM ((ushort)0x1000) /* Check individual hash */ #define SCC_PMSR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ #define SCC_PMSR_PRO ((ushort)0x0200) /* Promiscuous mode */ #define SCC_PMSR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ #define SCC_PMSR_SBT ((ushort)0x0080) /* Special backoff timer */ #define SCC_PMSR_LPB ((ushort)0x0040) /* Set Loopback mode */ #define SCC_PMSR_SIP ((ushort)0x0020) /* Sample Input Pins */ #define SCC_PMSR_LCW ((ushort)0x0010) /* Late collision window */ #define SCC_PMSR_NIB22 ((ushort)0x000a) /* Start frame search */ #define SCC_PMSR_FDE ((ushort)0x0001) /* Full duplex enable */ /* Buffer descriptor control/status used by Ethernet receive. */ #define BD_ENET_RX_EMPTY ((ushort)0x8000) #define BD_ENET_RX_WRAP ((ushort)0x2000) #define BD_ENET_RX_INTR ((ushort)0x1000) #define BD_ENET_RX_LAST ((ushort)0x0800) #define BD_ENET_RX_FIRST ((ushort)0x0400) #define BD_ENET_RX_MISS ((ushort)0x0100) #define BD_ENET_RX_LG ((ushort)0x0020) #define BD_ENET_RX_NO ((ushort)0x0010) #define BD_ENET_RX_SH ((ushort)0x0008) #define BD_ENET_RX_CR ((ushort)0x0004) #define BD_ENET_RX_OV ((ushort)0x0002) #define BD_ENET_RX_CL ((ushort)0x0001) #define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ /* Buffer descriptor control/status used by Ethernet transmit. */ #define BD_ENET_TX_READY ((ushort)0x8000) #define BD_ENET_TX_PAD ((ushort)0x4000) #define BD_ENET_TX_WRAP ((ushort)0x2000) #define BD_ENET_TX_INTR ((ushort)0x1000) #define BD_ENET_TX_LAST ((ushort)0x0800) #define BD_ENET_TX_TC ((ushort)0x0400) #define BD_ENET_TX_DEF ((ushort)0x0200) #define BD_ENET_TX_HB ((ushort)0x0100) #define BD_ENET_TX_LC ((ushort)0x0080) #define BD_ENET_TX_RL ((ushort)0x0040) #define BD_ENET_TX_RCMASK ((ushort)0x003c) #define BD_ENET_TX_UN ((ushort)0x0002) #define BD_ENET_TX_CSL ((ushort)0x0001) #define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ /* SCC as UART */ typedef struct scc_uart { sccp_t scc_genscc; uint scc_res1; /* Reserved */ uint scc_res2; /* Reserved */ ushort scc_maxidl; /* Maximum idle chars */ ushort scc_idlc; /* temp idle counter */ ushort scc_brkcr; /* Break count register */ ushort scc_parec; /* receive parity error counter */ ushort scc_frmec; /* receive framing error counter */ ushort scc_nosec; /* receive noise counter */ ushort scc_brkec; /* receive break condition counter */ ushort scc_brkln; /* last received break length */ ushort scc_uaddr1; /* UART address character 1 */ ushort scc_uaddr2; /* UART address character 2 */ ushort scc_rtemp; /* Temp storage */ ushort scc_toseq; /* Transmit out of sequence char */ ushort scc_char1; /* control character 1 */ ushort scc_char2; /* control character 2 */ ushort scc_char3; /* control character 3 */ ushort scc_char4; /* control character 4 */ ushort scc_char5; /* control character 5 */ ushort scc_char6; /* control character 6 */ ushort scc_char7; /* control character 7 */ ushort scc_char8; /* control character 8 */ ushort scc_rccm; /* receive control character mask */ ushort scc_rccr; /* receive control character register */ ushort scc_rlbc; /* receive last break character */ } scc_uart_t; /* SCC Event and Mask registers when it is used as a UART. */ #define UART_SCCM_GLR ((ushort)0x1000) #define UART_SCCM_GLT ((ushort)0x0800) #define UART_SCCM_AB ((ushort)0x0200) #define UART_SCCM_IDL ((ushort)0x0100) #define UART_SCCM_GRA ((ushort)0x0080) #define UART_SCCM_BRKE ((ushort)0x0040) #define UART_SCCM_BRKS ((ushort)0x0020) #define UART_SCCM_CCR ((ushort)0x0008) #define UART_SCCM_BSY ((ushort)0x0004) #define UART_SCCM_TX ((ushort)0x0002) #define UART_SCCM_RX ((ushort)0x0001) /* The SCC PMSR when used as a UART. */ #define SCU_PMSR_FLC ((ushort)0x8000) #define SCU_PMSR_SL ((ushort)0x4000) #define SCU_PMSR_CL ((ushort)0x3000) #define SCU_PMSR_UM ((ushort)0x0c00) #define SCU_PMSR_FRZ ((ushort)0x0200) #define SCU_PMSR_RZS ((ushort)0x0100) #define SCU_PMSR_SYN ((ushort)0x0080) #define SCU_PMSR_DRT ((ushort)0x0040) #define SCU_PMSR_PEN ((ushort)0x0010) #define SCU_PMSR_RPM ((ushort)0x000c) #define SCU_PMSR_REVP ((ushort)0x0008) #define SCU_PMSR_TPM ((ushort)0x0003) #define SCU_PMSR_TEVP ((ushort)0x0003) /* CPM Transparent mode SCC. */ typedef struct scc_trans { sccp_t st_genscc; uint st_cpres; /* Preset CRC */ uint st_cmask; /* Constant mask for CRC */ } scc_trans_t; #define BD_SCC_TX_LAST ((ushort)0x0800) /* CPM interrupts. There are nearly 32 interrupts generated by CPM * channels or devices. All of these are presented to the PPC core * as a single interrupt. The CPM interrupt handler dispatches its * own handlers, in a similar fashion to the PPC core handler. We * use the table as defined in the manuals (i.e. no special high * priority and SCC1 == SCCa, etc...). */ /* #define CPMVEC_NR 32 */ /* #define CPMVEC_PIO_PC15 ((ushort)0x1f) */ /* #define CPMVEC_SCC1 ((ushort)0x1e) */ /* #define CPMVEC_SCC2 ((ushort)0x1d) */ /* #define CPMVEC_SCC3 ((ushort)0x1c) */ /* #define CPMVEC_SCC4 ((ushort)0x1b) */ /* #define CPMVEC_PIO_PC14 ((ushort)0x1a) */ /* #define CPMVEC_TIMER1 ((ushort)0x19) */ /* #define CPMVEC_PIO_PC13 ((ushort)0x18) */ /* #define CPMVEC_PIO_PC12 ((ushort)0x17) */ /* #define CPMVEC_SDMA_CB_ERR ((ushort)0x16) */ /* #define CPMVEC_IDMA1 ((ushort)0x15) */ /* #define CPMVEC_IDMA2 ((ushort)0x14) */ /* #define CPMVEC_TIMER2 ((ushort)0x12) */ /* #define CPMVEC_RISCTIMER ((ushort)0x11) */ /* #define CPMVEC_I2C ((ushort)0x10) */ /* #define CPMVEC_PIO_PC11 ((ushort)0x0f) */ /* #define CPMVEC_PIO_PC10 ((ushort)0x0e) */ /* #define CPMVEC_TIMER3 ((ushort)0x0c) */ /* #define CPMVEC_PIO_PC9 ((ushort)0x0b) */ /* #define CPMVEC_PIO_PC8 ((ushort)0x0a) */ /* #define CPMVEC_PIO_PC7 ((ushort)0x09) */ /* #define CPMVEC_TIMER4 ((ushort)0x07) */ /* #define CPMVEC_PIO_PC6 ((ushort)0x06) */ /* #define CPMVEC_SPI ((ushort)0x05) */ /* #define CPMVEC_SMC1 ((ushort)0x04) */ /* #define CPMVEC_SMC2 ((ushort)0x03) */ /* #define CPMVEC_PIO_PC5 ((ushort)0x02) */ /* #define CPMVEC_PIO_PC4 ((ushort)0x01) */ /* #define CPMVEC_ERROR ((ushort)0x00) */ extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); /* CPM interrupt configuration vector. */ #define CICR_SCD_SCC4 ((uint)0x00c00000) /* SCC4 @ SCCd */ #define CICR_SCC_SCC3 ((uint)0x00200000) /* SCC3 @ SCCc */ #define CICR_SCB_SCC2 ((uint)0x00040000) /* SCC2 @ SCCb */ #define CICR_SCA_SCC1 ((uint)0x00000000) /* SCC1 @ SCCa */ #define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrupt */ #define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */ #define CICR_IEN ((uint)0x00000080) /* Int. enable */ #define CICR_SPS ((uint)0x00000001) /* SCC Spread */ #endif /* __CPM_360__ */