From 272c3271b3f9a21aa6a10e9806830288c1eb6212 Mon Sep 17 00:00:00 2001 From: harti Date: Thu, 24 Feb 2005 16:56:36 +0000 Subject: Split the chip-specific code from the generic Utopia code. This simplifies adding of new physical chips. Now one just needs to add a .h and a .c file for the new chip and add one line to utopia.c for that chip. --- sys/dev/utopia/idtphy.c | 494 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 sys/dev/utopia/idtphy.c (limited to 'sys/dev/utopia/idtphy.c') diff --git a/sys/dev/utopia/idtphy.c b/sys/dev/utopia/idtphy.c new file mode 100644 index 0000000..5aaa576 --- /dev/null +++ b/sys/dev/utopia/idtphy.c @@ -0,0 +1,494 @@ +/*- + * Copyright (c) 2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Hartmut Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +/* + * Reset IDT77105. There is really no way to reset this thing by acessing + * the registers. Load the registers with default values. + */ +static int +idt77105_reset(struct utopia *utp) +{ + int err = 0; + u_int n; + uint8_t val[2]; + + err |= UTP_WRITEREG(utp, IDTPHY_REGO_MCR, 0xff, + IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI); + n = 1; + err |= UTP_READREGS(utp, IDTPHY_REGO_ISTAT, val, &n); + err |= UTP_WRITEREG(utp, IDTPHY_REGO_DIAG, 0xff, 0); + err |= UTP_WRITEREG(utp, IDTPHY_REGO_LHEC, 0xff, 0); + + err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC); + n = 2; + err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n); + + err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX); + n = 2; + err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n); + + err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX); + n = 2; + err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n); + + err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE); + n = 2; + err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n); + + err |= UTP_WRITEREG(utp, IDTPHY_REGO_MCR, IDTPHY_REGM_MCR_DREC, + IDTPHY_REGM_MCR_DREC); + err |= UTP_WRITEREG(utp, IDTPHY_REGO_DIAG, IDTPHY_REGM_DIAG_RFLUSH, + IDTPHY_REGM_DIAG_RFLUSH); + + /* loopback */ + err |= utopia_set_loopback(utp, utp->loopback); + + /* update carrier state */ + err |= utopia_update_carrier(utp); + + return (err ? EIO : 0); +} + +static int +idt77105_inval(struct utopia *utp, int what __unused) +{ + + return (EINVAL); +} + +static int +idt77105_update_carrier(struct utopia *utp) +{ + int err; + uint8_t reg; + u_int n = 1; + + if ((err = UTP_READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) { + utp->carrier = UTP_CARR_UNKNOWN; + return (err); + } + utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD); + return (0); +} + +static int +idt77105_set_loopback(struct utopia *utp, u_int mode) +{ + int err; + + switch (mode) { + case UTP_LOOP_NONE: + err = UTP_WRITEREG(utp, IDTPHY_REGO_DIAG, + IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE); + break; + + case UTP_LOOP_DIAG: + err = UTP_WRITEREG(utp, IDTPHY_REGO_DIAG, + IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY); + break; + + case UTP_LOOP_LINE: + err = UTP_WRITEREG(utp, IDTPHY_REGO_DIAG, + IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE); + break; + + default: + return (EINVAL); + } + if (err) + return (err); + utp->loopback = mode; + return (0); +} + +/* + * Handle interrupt on IDT77105 chip + */ +static void +idt77105_intr(struct utopia *utp) +{ + uint8_t reg; + u_int n = 1; + int err; + + /* Interrupt status and ack the interrupt */ + if ((err = UTP_READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) { + printf("IDT77105 read error %d\n", err); + return; + } + /* check for signal condition */ + utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD); +} + +static void +idt77105_update_stats(struct utopia *utp) +{ + int err = 0; + uint8_t regs[2]; + u_int n; + +#ifdef DIAGNOSTIC +#define UDIAG(F,A,B) printf(F, A, B) +#else +#define UDIAG(F,A,B) do { } while (0) +#endif + +#define UPD(FIELD, CODE, N, MASK) \ + err = UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, CODE); \ + if (err != 0) { \ + UDIAG("%s: cannot write CNTS: %d\n", __func__, err); \ + return; \ + } \ + n = N; \ + err = UTP_READREGS(utp, IDTPHY_REGO_CNT, regs, &n); \ + if (err != 0) { \ + UDIAG("%s: cannot read CNT: %d\n", __func__, err); \ + return; \ + } \ + if (n != N) { \ + UDIAG("%s: got only %u registers\n", __func__, n); \ + return; \ + } \ + if (N == 1) \ + utp->stats.FIELD += (regs[0] & MASK); \ + else \ + utp->stats.FIELD += (regs[0] | (regs[1] << 8)) & MASK; + + UPD(rx_symerr, IDTPHY_REGM_CNTS_SEC, 1, 0xff); + UPD(tx_cells, IDTPHY_REGM_CNTS_TX, 2, 0xffff); + UPD(rx_cells, IDTPHY_REGM_CNTS_RX, 2, 0xffff); + UPD(rx_uncorr, IDTPHY_REGM_CNTS_HECE, 1, 0x1f); + +#undef UDIAG +#undef UPD +} + +struct utopia_chip utopia_chip_idt77105 = { + UTP_TYPE_IDT77105, + "IDT77105", + 7, + idt77105_reset, + idt77105_inval, + idt77105_inval, + idt77105_inval, + idt77105_update_carrier, + idt77105_set_loopback, + idt77105_intr, + idt77105_update_stats, +}; + +/* + * Update the carrier status + */ +static int +idt77155_update_carrier(struct utopia *utp) +{ + int err; + uint8_t reg; + u_int n = 1; + + if ((err = UTP_READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) { + utp->carrier = UTP_CARR_UNKNOWN; + return (err); + } + utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS)); + return (0); +} + +/* + * Handle interrupt on IDT77155 chip + */ +static void +idt77155_intr(struct utopia *utp) +{ + uint8_t reg; + u_int n = 1; + int err; + + if ((err = UTP_READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) { + printf("IDT77105 read error %d\n", err); + return; + } + utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS)); +} + +/* + * set SONET/SDH mode + */ +static int +idt77155_set_sdh(struct utopia *utp, int sdh) +{ + int err; + + if (sdh) + err = UTP_WRITEREG(utp, IDTPHY_REGO_PTRM, + IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH); + else + err = UTP_WRITEREG(utp, IDTPHY_REGO_PTRM, + IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET); + if (err != 0) + return (err); + + utp->state &= ~UTP_ST_SDH; + if (sdh) + utp->state |= UTP_ST_SDH; + + return (0); +} + +/* + * set idle/unassigned cells + */ +static int +idt77155_set_unass(struct utopia *utp, int unass) +{ + int err; + + if (unass) + err = UTP_WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0); + else + err = UTP_WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1); + if (err != 0) + return (err); + + utp->state &= ~UTP_ST_UNASS; + if (unass) + utp->state |= UTP_ST_UNASS; + + return (0); +} + +/* + * enable/disable scrambling + */ +static int +idt77155_set_noscramb(struct utopia *utp, int noscramb) +{ + int err; + + if (noscramb) { + err = UTP_WRITEREG(utp, IDTPHY_REGO_TCC, + IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR); + if (err) + return (err); + err = UTP_WRITEREG(utp, IDTPHY_REGO_RCC, + IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR); + if (err) + return (err); + utp->state |= UTP_ST_NOSCRAMB; + } else { + err = UTP_WRITEREG(utp, IDTPHY_REGO_TCC, + IDTPHY_REGM_TCC_DSCR, 0); + if (err) + return (err); + err = UTP_WRITEREG(utp, IDTPHY_REGO_RCC, + IDTPHY_REGM_RCC_DSCR, 0); + if (err) + return (err); + utp->state &= ~UTP_ST_NOSCRAMB; + } + return (0); +} + +/* + * Set loopback mode for the 77155 + */ +static int +idt77155_set_loopback(struct utopia *utp, u_int mode) +{ + int err; + uint32_t val; + u_int nmode; + + val = 0; + nmode = mode; + if (mode & UTP_LOOP_TIME) { + nmode &= ~UTP_LOOP_TIME; + val |= IDTPHY_REGM_MCTL_TLOOP; + } + if (mode & UTP_LOOP_DIAG) { + nmode &= ~UTP_LOOP_DIAG; + val |= IDTPHY_REGM_MCTL_DLOOP; + } + if (mode & UTP_LOOP_LINE) { + nmode &= ~UTP_LOOP_LINE; + val |= IDTPHY_REGM_MCTL_LLOOP; + } + if (nmode != 0) + return (EINVAL); + + err = UTP_WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP | + IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val); + if (err) + return (err); + utp->loopback = mode; + + return (0); +} + +/* + * Set the chip to reflect the current state in utopia. + * Assume, that the chip has been reset. + */ +static int +idt77155_set_chip(struct utopia *utp) +{ + int err = 0; + + /* set sonet/sdh */ + err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH); + + /* unassigned or idle cells */ + err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS); + + /* loopback */ + err |= idt77155_set_loopback(utp, utp->loopback); + + /* update carrier state */ + err |= idt77155_update_carrier(utp); + + /* enable interrupts on LOS */ + err |= UTP_WRITEREG(utp, IDTPHY_REGO_INT, + IDTPHY_REGM_INT_RXSOHI, IDTPHY_REGM_INT_RXSOHI); + err |= UTP_WRITEREG(utp, IDTPHY_REGO_RSOC, + IDTPHY_REGM_RSOC_LOSI, IDTPHY_REGM_RSOC_LOSI); + + return (err ? EIO : 0); +} + +/* + * Reset the chip to reflect the current state of utopia. + */ +static int +idt77155_reset(struct utopia *utp) +{ + int err = 0; + + if (!(utp->flags & UTP_FL_NORESET)) { + err |= UTP_WRITEREG(utp, IDTPHY_REGO_MRID, + IDTPHY_REGM_MRID_RESET, IDTPHY_REGM_MRID_RESET); + err |= UTP_WRITEREG(utp, IDTPHY_REGO_MRID, + IDTPHY_REGM_MRID_RESET, 0); + } + + err |= idt77155_set_chip(utp); + + return (err ? EIO : 0); +} + +/* + * Update statistics from a IDT77155 + * This appears to be the same as for the Suni/Lite and Ultra. IDT however + * makes no assessment about the transfer time. Assume 7us. + */ +static void +idt77155_update_stats(struct utopia *utp) +{ + int err; + + /* write to the master if we can */ + if (!(utp->flags & UTP_FL_NORESET)) { + err = UTP_WRITEREG(utp, IDTPHY_REGO_MRID, 0, 0); + } else { + err = UTP_WRITEREG(utp, IDTPHY_REGO_BIPC, 0, 0); + err |= UTP_WRITEREG(utp, IDTPHY_REGO_B2EC, 0, 0); + err |= UTP_WRITEREG(utp, IDTPHY_REGO_B3EC, 0, 0); + err |= UTP_WRITEREG(utp, IDTPHY_REGO_CEC, 0, 0); + err |= UTP_WRITEREG(utp, IDTPHY_REGO_TXCNT, 0, 0); + + } + if (err) { +#ifdef DIAGNOSTIC + printf("%s: register write error %s: %d\n", __func__, + utp->chip->name, err); +#endif + return; + } + + DELAY(8); + + utp->stats.rx_sbip += utopia_update(utp, + IDTPHY_REGO_BIPC, 2, 0xffff); + utp->stats.rx_lbip += utopia_update(utp, + IDTPHY_REGO_B2EC, 3, 0xfffff); + utp->stats.rx_lfebe += utopia_update(utp, + IDTPHY_REGO_FEBEC, 3, 0xfffff); + utp->stats.rx_pbip += utopia_update(utp, + IDTPHY_REGO_B3EC, 2, 0xffff); + utp->stats.rx_pfebe += utopia_update(utp, + IDTPHY_REGO_PFEBEC, 2, 0xffff); + utp->stats.rx_corr += utopia_update(utp, + IDTPHY_REGO_CEC, 1, 0xff); + utp->stats.rx_uncorr += utopia_update(utp, + IDTPHY_REGO_UEC, 1, 0xff); + utp->stats.rx_cells += utopia_update(utp, + IDTPHY_REGO_RCCNT, 3, 0x7ffff); + utp->stats.tx_cells += utopia_update(utp, + IDTPHY_REGO_TXCNT, 3, 0x7ffff); +} + +const struct utopia_chip utopia_chip_idt77155 = { + UTP_TYPE_IDT77155, + "IDT77155", + 0x80, + idt77155_reset, + idt77155_set_sdh, + idt77155_set_unass, + idt77155_set_noscramb, + idt77155_update_carrier, + idt77155_set_loopback, + idt77155_intr, + idt77155_update_stats, +}; -- cgit v1.1