patch-2.4.19 linux-2.4.19/drivers/net/wan/8253x/8253xmcs.c
Next file: linux-2.4.19/drivers/net/wan/8253x/8253xmcs.h
Previous file: linux-2.4.19/drivers/net/wan/8253x/8253xioc.h
Back to the patch index
Back to the overall index
- Lines: 638
- Date:
Fri Aug 2 17:39:44 2002
- Orig file:
linux-2.4.18/drivers/net/wan/8253x/8253xmcs.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN linux-2.4.18/drivers/net/wan/8253x/8253xmcs.c linux-2.4.19/drivers/net/wan/8253x/8253xmcs.c
@@ -0,0 +1,637 @@
+/* -*- linux-c -*- */
+/*
+ * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ **/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/pgtable.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include "Reg9050.h"
+#include "8253xctl.h"
+#include "ring.h"
+#include "8253x.h"
+#include "crc32dcl.h"
+#include "8253xmcs.h"
+#include "sp502.h"
+
+/* Just to guarantee that strings are null terminated */
+#define MEMCPY(dest, src, cnt) \
+{ \
+ memcpy((dest), (src), (cnt)); \
+ (dest)[cnt] = 0; \
+}
+
+static unsigned char sp502progbyte[] =
+{
+ SP502_OFF,
+ SP502_RS232,
+ SP502_RS422,
+ SP502_RS485,
+ SP502_RS449,
+ SP502_EIA530,
+ SP502_V35
+};
+
+/*
+ * The following routines are the multichannel server I2C serial EPROM routines.
+ */
+
+/*
+ * Set the clock and the data lines of the SEP.
+ */
+static void
+mcs_sep_set(mcs_sep_t *msp, unsigned sdavalid, unsigned sda,
+ unsigned sclvalid, unsigned scl)
+{
+#ifdef MAX
+#undef MAX
+#endif /* MAX */
+
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+
+ unsigned char csr;
+ unsigned int sleeptime;
+
+ /*
+ * Ensure sufficient clock
+ */
+
+ sleeptime = 0;
+
+ if (sclvalid)
+ {
+ if (msp->s_scl && !scl)
+ { /* do we have a downgoing transition? */
+ sleeptime = MAX(1, sleeptime);
+ }
+ else if (!msp->s_scl && scl)
+ { /* upgoing */
+ sleeptime = MAX(2, sleeptime);
+ }
+ msp->s_scl = scl;
+ }
+
+ if (sdavalid)
+ {
+ if ((msp->s_sda && !sda) || (!msp->s_sda && sda))
+ {
+ sleeptime = MAX(1, sleeptime);
+ }
+
+ msp->s_sda = sda;
+ }
+
+ if (sleeptime > 0)
+ {
+ udelay(sleeptime);
+ }
+
+ /*
+ * Construct the CSR byte.
+ */
+ csr = 0;
+ if (msp->s_sda)
+ {
+ csr |= CIMCMD_CIMCSR_SDA;
+ }
+
+ if (msp->s_scl)
+ {
+ csr |= CIMCMD_CIMCSR_SCL;
+ }
+
+ writeb((unsigned char) csr, msp->s_wrptr);
+}
+
+static void
+mcs_sep_start(mcs_sep_t *msp)
+{
+ /*
+ * Generate a START condition
+ */
+ mcs_sep_set(msp, TRUE, TRUE, TRUE, TRUE);
+ mcs_sep_set(msp, TRUE, FALSE, TRUE, TRUE);
+}
+
+static void
+mcs_sep_stop(mcs_sep_t *msp)
+{
+ /*
+ * Generate a STOP condition
+ */
+ mcs_sep_set(msp, TRUE, FALSE, TRUE, TRUE);
+ mcs_sep_set(msp, TRUE, TRUE, TRUE, TRUE);
+}
+
+/*
+ * Send out a single byte.
+ */
+static void
+mcs_sep_byte(mcs_sep_t *msp, unsigned char val)
+{
+ register int bitcount;
+
+ /* Clock may be high ... lower the clock */
+ mcs_sep_set(msp, TRUE, FALSE, TRUE, FALSE);
+
+ bitcount = 8;
+
+ while (TRUE)
+ {
+ mcs_sep_set(msp, TRUE, (val & 0x80) != 0, TRUE, FALSE);
+ mcs_sep_set(msp, TRUE, (val & 0x80) != 0, TRUE, TRUE);
+
+ bitcount--;
+ if (bitcount == 0)
+ {
+ break;
+ }
+ val <<= 1;
+ }
+
+ /* Clock is high ... lower the clock */
+ mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE);
+}
+
+/*
+ * Wait for an acknowledge cycle. Expects the clock to be low.
+ */
+static unsigned
+mcs_sep_waitsep(mcs_sep_t *msp)
+{
+ int loopcount;
+ unsigned char cimcsr;
+
+ /* Stop driving SDA */
+ mcs_sep_set(msp, TRUE, TRUE, FALSE, FALSE);
+ /* Raise the clock */
+ mcs_sep_set(msp, FALSE, FALSE, TRUE, TRUE);
+
+ loopcount = 1000;
+ while (loopcount != 0)
+ {
+ cimcsr = readb(msp->s_rdptr);
+
+ if ((cimcsr & CIMCMD_CIMCSR_SDA) == 0)
+ {
+ break;
+ }
+ loopcount--;
+ }
+
+ /* Lower the clock */
+ mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE);
+
+ if (loopcount == 0)
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+/*
+ * Read the given CIM's SEP, starting at the given address, into
+ * the given buffer, for the given length.
+ *
+ * Returns -1 if there was a failure, otherwise the byte count.
+ */
+
+static int
+mcs_sep_read(mcs_sep_t *msp, unsigned short addr,
+ unsigned char *buf, unsigned int nbytes)
+{
+ unsigned char cmdaddr, val, cimcsr;
+ unsigned int bytecount, bitcount;
+
+ mcs_sep_start(msp);
+
+ /*
+ * First, send out a dummy WRITE command with no data.
+ */
+
+ cmdaddr = 0xa0 | (((addr >> 8) & 0x7) << 1) | 0x0;
+
+ mcs_sep_byte(msp, cmdaddr);
+
+ if (!mcs_sep_waitsep(msp))
+ {
+ return -1;
+ }
+
+ /*
+ * Now, send the reset of the address.
+ */
+
+ mcs_sep_byte(msp, (unsigned char) addr);
+
+ if (!mcs_sep_waitsep(msp))
+ {
+ return -1;
+ }
+
+ /*
+ * Now, restart with a read command.
+ */
+
+ mcs_sep_start(msp);
+
+ cmdaddr = 0xa0 | (((addr >> 8) & 0x7) << 1) | 0x1;
+
+ mcs_sep_byte(msp, cmdaddr);
+
+ if (!mcs_sep_waitsep(msp))
+ {
+ return -1;
+ }
+
+ /*
+ * Now, start reading the bytes.
+ */
+ bytecount = 0;
+ while (TRUE)
+ {
+ bitcount = 8;
+ val = 0;
+ while (TRUE)
+ {
+ mcs_sep_set(msp, TRUE, TRUE, TRUE, TRUE);
+
+ cimcsr = readb(msp->s_rdptr);
+
+ if ((cimcsr & CIMCMD_CIMCSR_SDA) != 0)
+ {
+ val |= 0x01;
+ }
+
+ mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE);
+ bitcount--;
+
+ if (bitcount == 0)
+ {
+ break;
+ }
+ val <<= 1;
+ }
+
+ *buf++ = val;
+ bytecount++;
+ nbytes--;
+
+ if (nbytes == 0)
+ {
+ break;
+ }
+
+ /*
+ * Send the acknowledge.
+ */
+
+ mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE);
+ mcs_sep_set(msp, TRUE, FALSE, TRUE, TRUE);
+ mcs_sep_set(msp, FALSE, FALSE, TRUE, FALSE);
+ }
+
+ mcs_sep_stop(msp);
+
+ return (int) bytecount;
+}
+
+
+unsigned int mcs_ciminit(SAB_BOARD *bptr, AURA_CIM *cim)
+{
+ mcs_sep_t ms;
+
+ ms.s_rdptr = (unsigned char *)
+ (bptr->CIMCMD_REG + (CIMCMD_RDCIMCSR | (cim->ci_num << CIMCMD_CIMSHIFT)));
+ ms.s_wrptr = (unsigned char *)
+ (bptr->CIMCMD_REG + (CIMCMD_WRCIMCSR | (cim->ci_num << CIMCMD_CIMSHIFT)));
+ ms.s_scl = ms.s_sda = FALSE;
+
+ if (mcs_sep_read(&ms, (unsigned short) 0, &(cim->ci_sep[0]),
+ sizeof(cim->ci_sep)) != sizeof(cim->ci_sep)
+ || cim->ci_sep[MCS_SEP_MAGIC] != MCS_SEP_MAGICVAL)
+ {
+
+ if (cim->ci_sep[MCS_SEP_MAGIC] != MCS_SEP_MAGICVAL)
+ {
+ DEBUGPRINT((KERN_ALERT
+ "auraXX20: invalid CIM %d serial EPROM on board %d",
+ cim->ci_num, bptr->board_number));
+ }
+ else
+ {
+ DEBUGPRINT((KERN_ALERT
+ "auraXX20: error reading CIM %d serial EPROM on board %d",
+ cim->ci_num, bptr->board_number));
+ }
+
+ cim->ci_clkspeed = WANMCS_CLKSPEED;
+ cim->ci_clkspdsrc = -1;
+ cim->ci_spdgrd = 10;
+ cim->ci_spdgrdsrc = -1;
+ cim->ci_flags = 0;
+ cim->ci_rev[0] = '\0';
+ cim->ci_sn[0] = '\0';
+ cim->ci_mfgdate[0] = '\0';
+ cim->ci_mfgloc[0] = '\0';
+
+ /*
+ * Diddle the port setup registers to determine if this
+ * CIM was built up for RS232 or SP502.
+ */
+
+ writew((unsigned short) 0xffff, (unsigned short *)
+ (bptr->CIMCMD_REG +
+ (CIMCMD_WRSETUP | (cim->ci_num << CIMCMD_CIMSHIFT))));
+
+#ifdef RICHARD_DELAY
+ udelay(1);
+#endif /* RICHARD_DELAY */
+
+ if (readw((unsigned short *)
+ (bptr->CIMCMD_REG +
+ (CIMCMD_RDSETUP | (cim->ci_num << CIMCMD_CIMSHIFT)))) == 0xffff)
+ {
+
+ writew(0, (unsigned short *)
+ (bptr->CIMCMD_REG +
+ (CIMCMD_WRSETUP | (cim->ci_num << CIMCMD_CIMSHIFT))));
+
+#ifdef RICHARD_DELAY
+ udelay(1);
+#endif /* RICHARD_DELAY */
+
+ if (readw((unsigned short *)
+ (bptr->CIMCMD_REG +
+ (CIMCMD_RDSETUP | (cim->ci_num << CIMCMD_CIMSHIFT)))) == 0)
+ {
+
+ cim->ci_type = CIM_SP502;
+ }
+ else
+ {
+ cim->ci_type = CIM_RS232;
+ }
+ }
+ else
+ {
+ cim->ci_type = CIM_RS232;
+ }
+
+ if (cim->ci_type == CIM_SP502)
+ {
+ cim->ci_flags |= CIM_SYNC;
+ }
+ }
+ else
+ {
+ /*
+ * Pick through the serial EPROM contents and derive
+ * the values we need.
+ */
+ MEMCPY(&(cim->ci_rev[0]), &(cim->ci_sep[MCS_SEP_REV]),
+ MCS_SEP_REVLEN);
+ MEMCPY(&(cim->ci_sn[0]), &(cim->ci_sep[MCS_SEP_SN]),
+ MCS_SEP_SNLEN);
+ MEMCPY(&(cim->ci_mfgdate[0]), &(cim->ci_sep[MCS_SEP_MFGDATE]),
+ MCS_SEP_MFGDATELEN);
+ MEMCPY(&(cim->ci_mfgloc[0]), &(cim->ci_sep[MCS_SEP_MFGLOC]),
+ MCS_SEP_MFGLOCLEN);
+
+ cim->ci_clkspeed = (unsigned long) cim->ci_sep[MCS_SEP_CLKSPD]
+ | ((unsigned long) cim->ci_sep[MCS_SEP_CLKSPD + 1] << 8)
+ | ((unsigned long) cim->ci_sep[MCS_SEP_CLKSPD + 2] << 16)
+ | ((unsigned long) cim->ci_sep[MCS_SEP_CLKSPD + 3] << 24);
+
+ cim->ci_clkspdsrc = SEPROM;
+
+ cim->ci_spdgrd = (int) cim->ci_sep[MCS_SEP_SPDGRD];
+ cim->ci_spdgrdsrc = SEPROM;
+
+ cim->ci_flags = (unsigned long) cim->ci_sep[MCS_SEP_FLAGS];
+
+ cim->ci_type = (int) cim->ci_sep[MCS_SEP_TYPE];
+ }
+
+ /*
+ * Possibly initialize the port setup registers.
+ */
+
+ if (cim->ci_type == CIM_SP502)
+ {
+ unsigned short alloff;
+#ifdef DEBUG_VERBOSE
+ unsigned short readback;
+#endif
+ int offset;
+
+ /*
+ * Turn off all of the electrical interfaces. The
+ * hardware *should* initialize to this state, but the
+ * prototype, at least, does not. Note that this setting
+ * is reflected in the SIF_OFF setting of l_interface in
+ * mustard_lineinit, above.
+ */
+
+ alloff = (unsigned short) SP502_OFF
+ | ((unsigned short) SP502_OFF << 4)
+ | ((unsigned short) SP502_OFF << 8)
+ | ((unsigned short) SP502_OFF << 12);
+ for (offset = 0; offset < 8; offset++)
+ {
+#ifdef DEBUG_VERBOSE
+ DEBUGPRINT((KERN_ALERT "cim %d setup reg #%d: writing 0x%x to 0x%x",
+ cim->ci_num, offset, (unsigned) alloff,
+ (CIMCMD_WRSETUP | (offset << 1) |
+ (cim->ci_num << CIMCMD_CIMSHIFT))));
+#endif /* DEBUG_VERBOSE */
+
+ writew((unsigned short) alloff, (unsigned short *)
+ (bptr->CIMCMD_REG +
+ (CIMCMD_WRSETUP | (offset << 1) |
+ (cim->ci_num << CIMCMD_CIMSHIFT))));
+#ifdef RICHARD_DELAY
+ udelay(1);
+#endif /* RICHARD_DELAY */
+#ifdef DEBUG_VERBOSE
+ readback = readw((unsigned short *)
+ (bptr->CIMCMD_REG +
+ (CIMCMD_RDSETUP | (offset << 1) |
+ (cim->ci_num << CIMCMD_CIMSHIFT))));
+ if (readback != alloff)
+ {
+ DEBUGPRINT((KERN_ALERT "cim %d setup reg #%d: readback (0x%x) should be 0x%x",
+ cim->ci_num, offset, readback, alloff));
+ }
+#endif /* DEBUG_VERBOSE */
+ }
+ }
+
+ /*
+ * Clear out the CIM CSR with the exception of the LED.
+ */
+
+ writeb((unsigned char) 0,
+ (unsigned char *) (bptr->CIMCMD_REG +
+ (CIMCMD_WRCIMCSR | (cim->ci_num << CIMCMD_CIMSHIFT))));
+
+ return TRUE;
+}
+
+
+int wanmcs_reset(SAB_BOARD* bptr) /* note the board is the host card not the
+ * individual extension boards
+ */
+{
+ int counter;
+
+#if 0 /* from the ASE driver */
+ /*
+ * Program the AMCC to deactivate the write FIFO.
+ */
+
+ ASE_PUT32(cboard->b_bridgehandle,
+ (aseuint32_t *) (cboard->b_bridge + AMCC_PTCR),
+ ((aseuint32_t) (AMCC_PTMODE | AMCC_WRFIFODIS) << 24) |
+ ((aseuint32_t) (AMCC_PTMODE | AMCC_WRFIFODIS) << 16) |
+ ((aseuint32_t) (AMCC_PTMODE | AMCC_WRFIFODIS) << 8) |
+ (aseuint32_t) (AMCC_PTMODE | AMCC_WRFIFODIS));
+#endif /* 0 */
+
+ /*
+ * First thing: do a reset of the local bus on the MIC
+ * by diddling the Add-On Reset bit in the RCR.
+ */
+
+ writel((unsigned int) AMCC_AORESET,
+ (unsigned int *)(bptr->AMCC_REG + AMCC_RCR));
+
+ udelay(10); /* wait for 10 us. */
+
+ writel((unsigned int) 0,
+ (unsigned int *)(bptr->AMCC_REG + AMCC_RCR));
+
+ udelay(10); /* wait for 10 us. */
+
+ /*
+ * Now the PCI bridge is reset. Try to establish
+ * a link through the Glink chipset.
+ */
+
+ for (counter = 1000; counter != 0; counter--)
+ {
+ writeb(0, (unsigned char*) (bptr->MICCMD_REG + MICCMD_MICCSR));
+
+ udelay(5);
+
+ if((readb((unsigned char*)
+ (bptr->MICCMD_REG + MICCMD_MICCSR)) & MICCMD_MICCSR_GLE) == 0)
+ {
+ break;
+ }
+ }
+
+ /*
+ * Did we run out of time?
+ */
+
+ if (counter == 0)
+ {
+ printk(KERN_ALERT
+ "AMCC5920: board %p: GLink did not reset -- is the MEB on?",
+ bptr);
+
+ return FALSE;
+ }
+
+ /*
+ * Now, hit the reset in the MEB.
+ */
+
+ writeb(0, (unsigned int *) (bptr->CIMCMD_REG + CIMCMD_RESETENA));
+
+ udelay(5);
+
+ writeb(0, (unsigned int *) (bptr->CIMCMD_REG + CIMCMD_RESETDIS));
+
+ /*
+ * And we're done!
+ */
+
+ return TRUE;
+}
+
+void aura_sp502_program(SAB_PORT *port, register unsigned int sigindex)
+{
+ register unsigned char prognibble;
+ SAB_BOARD *bptr;
+ unsigned int cimnum;
+ unsigned int chipno;
+ unsigned int portno;
+ unsigned int rdaddressreceiver;
+ unsigned int rdaddresstransmitter;
+ unsigned int wraddressreceiver;
+ unsigned int wraddresstransmitter;
+ unsigned short datareceiver;
+ unsigned short datatransmitter;
+
+ bptr = port->board;
+ cimnum = port->chip->c_cim->ci_num;
+ chipno = (port->chip->c_chipno & 1); /* chip number relative to EB not MCS */
+ portno = (port->portno + (8 * chipno)); /* portno on a per EB basis */
+
+ prognibble = (sp502progbyte[sigindex] & 0x0F);
+
+ /* first 4 shorts contain receiver control bits */
+ rdaddressreceiver =
+ (((unsigned int)bptr->CIMCMD_REG) +
+ ((cimnum << CIMCMD_CIMSHIFT) | CIMCMD_RDSETUP | ((portno/4) << CIMCMD_CTRLSHIFT)));
+ /* second 4 shorts contain transmitter control bits */
+ rdaddresstransmitter =
+ (((unsigned int)bptr->CIMCMD_REG) +
+ ((cimnum << CIMCMD_CIMSHIFT) | CIMCMD_RDSETUP | ((4+(portno/4)) << CIMCMD_CTRLSHIFT)));
+
+ wraddressreceiver =
+ (((unsigned int)bptr->CIMCMD_REG) +
+ ((cimnum << CIMCMD_CIMSHIFT) | CIMCMD_WRSETUP | ((portno/4) << CIMCMD_CTRLSHIFT)));
+ wraddresstransmitter =
+ (((unsigned int)bptr->CIMCMD_REG) +
+ ((cimnum << CIMCMD_CIMSHIFT) | CIMCMD_WRSETUP | ((4+(portno/4)) << CIMCMD_CTRLSHIFT)));
+
+ /* read out the current receiver status */
+ datareceiver = readw((unsigned short*) rdaddressreceiver);
+ /* clear out nibble that corresponds to current port */
+ datareceiver &= (unsigned short) ~(0x0F << ((3 - (portno % 4)) * 4));
+ /* or in new receiver control field */
+ datareceiver |= (prognibble << ((3 - (portno % 4)) * 4));
+ /* write back the short that corresponds to 4 ports */
+ writew(datareceiver, (unsigned short*) wraddressreceiver);
+
+ /* just as above except that next 4 shorts correspond to transmitters */
+ datatransmitter = readw((unsigned short*) rdaddresstransmitter);
+ datatransmitter &= (unsigned short) ~(0x0F << ((3 - (portno % 4)) * 4));
+ datatransmitter |= (prognibble << ((3 - (portno % 4)) * 4));
+ writew(datatransmitter, (unsigned short*) wraddresstransmitter);
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)