3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Hartmut Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/unistd.h>
36 #include <sys/kernel.h>
37 #include <sys/kthread.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
42 #include <sys/sysctl.h>
44 #include <sys/mutex.h>
45 #include <sys/socket.h>
48 #include <net/if_var.h>
49 #include <net/if_media.h>
50 #include <net/if_atm.h>
52 #include <dev/utopia/idtphy.h>
53 #include <dev/utopia/utopia.h>
54 #include <dev/utopia/utopia_priv.h>
57 * Reset IDT77105. There is really no way to reset this thing by acessing
58 * the registers. Load the registers with default values.
61 idt77105_reset(struct utopia *utp)
67 err |= UTP_WRITEREG(utp, IDTPHY_REGO_MCR, 0xff,
68 IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI);
70 err |= UTP_READREGS(utp, IDTPHY_REGO_ISTAT, val, &n);
71 err |= UTP_WRITEREG(utp, IDTPHY_REGO_DIAG, 0xff, 0);
72 err |= UTP_WRITEREG(utp, IDTPHY_REGO_LHEC, 0xff, 0);
74 err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC);
76 err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n);
78 err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX);
80 err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n);
82 err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX);
84 err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n);
86 err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE);
88 err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n);
90 err |= UTP_WRITEREG(utp, IDTPHY_REGO_MCR, IDTPHY_REGM_MCR_DREC,
91 IDTPHY_REGM_MCR_DREC);
92 err |= UTP_WRITEREG(utp, IDTPHY_REGO_DIAG, IDTPHY_REGM_DIAG_RFLUSH,
93 IDTPHY_REGM_DIAG_RFLUSH);
96 err |= utopia_set_loopback(utp, utp->loopback);
98 /* update carrier state */
99 err |= utopia_update_carrier(utp);
101 return (err ? EIO : 0);
105 idt77105_inval(struct utopia *utp, int what __unused)
112 idt77105_update_carrier(struct utopia *utp)
118 if ((err = UTP_READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) {
119 utp->carrier = UTP_CARR_UNKNOWN;
122 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
127 idt77105_set_loopback(struct utopia *utp, u_int mode)
133 err = UTP_WRITEREG(utp, IDTPHY_REGO_DIAG,
134 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE);
138 err = UTP_WRITEREG(utp, IDTPHY_REGO_DIAG,
139 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY);
143 err = UTP_WRITEREG(utp, IDTPHY_REGO_DIAG,
144 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE);
152 utp->loopback = mode;
157 * Handle interrupt on IDT77105 chip
160 idt77105_intr(struct utopia *utp)
166 /* Interrupt status and ack the interrupt */
167 if ((err = UTP_READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) {
168 printf("IDT77105 read error %d\n", err);
171 /* check for signal condition */
172 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
176 idt77105_update_stats(struct utopia *utp)
183 #define UDIAG(F,A,B) printf(F, A, B)
185 #define UDIAG(F,A,B) do { } while (0)
188 #define UPD(FIELD, CODE, N, MASK) \
189 err = UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, CODE); \
191 UDIAG("%s: cannot write CNTS: %d\n", __func__, err); \
195 err = UTP_READREGS(utp, IDTPHY_REGO_CNT, regs, &n); \
197 UDIAG("%s: cannot read CNT: %d\n", __func__, err); \
201 UDIAG("%s: got only %u registers\n", __func__, n); \
205 utp->stats.FIELD += (regs[0] & MASK); \
207 utp->stats.FIELD += (regs[0] | (regs[1] << 8)) & MASK;
209 UPD(rx_symerr, IDTPHY_REGM_CNTS_SEC, 1, 0xff);
210 UPD(tx_cells, IDTPHY_REGM_CNTS_TX, 2, 0xffff);
211 UPD(rx_cells, IDTPHY_REGM_CNTS_RX, 2, 0xffff);
212 UPD(rx_uncorr, IDTPHY_REGM_CNTS_HECE, 1, 0x1f);
218 struct utopia_chip utopia_chip_idt77105 = {
226 idt77105_update_carrier,
227 idt77105_set_loopback,
229 idt77105_update_stats,
233 * Update the carrier status
236 idt77155_update_carrier(struct utopia *utp)
242 if ((err = UTP_READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) {
243 utp->carrier = UTP_CARR_UNKNOWN;
246 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
251 * Handle interrupt on IDT77155 chip
254 idt77155_intr(struct utopia *utp)
260 if ((err = UTP_READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) {
261 printf("IDT77105 read error %d\n", err);
264 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
271 idt77155_set_sdh(struct utopia *utp, int sdh)
276 err = UTP_WRITEREG(utp, IDTPHY_REGO_PTRM,
277 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH);
279 err = UTP_WRITEREG(utp, IDTPHY_REGO_PTRM,
280 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET);
284 utp->state &= ~UTP_ST_SDH;
286 utp->state |= UTP_ST_SDH;
292 * set idle/unassigned cells
295 idt77155_set_unass(struct utopia *utp, int unass)
300 err = UTP_WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0);
302 err = UTP_WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1);
306 utp->state &= ~UTP_ST_UNASS;
308 utp->state |= UTP_ST_UNASS;
314 * enable/disable scrambling
317 idt77155_set_noscramb(struct utopia *utp, int noscramb)
322 err = UTP_WRITEREG(utp, IDTPHY_REGO_TCC,
323 IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR);
326 err = UTP_WRITEREG(utp, IDTPHY_REGO_RCC,
327 IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR);
330 utp->state |= UTP_ST_NOSCRAMB;
332 err = UTP_WRITEREG(utp, IDTPHY_REGO_TCC,
333 IDTPHY_REGM_TCC_DSCR, 0);
336 err = UTP_WRITEREG(utp, IDTPHY_REGO_RCC,
337 IDTPHY_REGM_RCC_DSCR, 0);
340 utp->state &= ~UTP_ST_NOSCRAMB;
346 * Set loopback mode for the 77155
349 idt77155_set_loopback(struct utopia *utp, u_int mode)
357 if (mode & UTP_LOOP_TIME) {
358 nmode &= ~UTP_LOOP_TIME;
359 val |= IDTPHY_REGM_MCTL_TLOOP;
361 if (mode & UTP_LOOP_DIAG) {
362 nmode &= ~UTP_LOOP_DIAG;
363 val |= IDTPHY_REGM_MCTL_DLOOP;
365 if (mode & UTP_LOOP_LINE) {
366 nmode &= ~UTP_LOOP_LINE;
367 val |= IDTPHY_REGM_MCTL_LLOOP;
372 err = UTP_WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP |
373 IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val);
376 utp->loopback = mode;
382 * Set the chip to reflect the current state in utopia.
383 * Assume, that the chip has been reset.
386 idt77155_set_chip(struct utopia *utp)
391 err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH);
393 /* unassigned or idle cells */
394 err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS);
397 err |= idt77155_set_loopback(utp, utp->loopback);
399 /* update carrier state */
400 err |= idt77155_update_carrier(utp);
402 /* enable interrupts on LOS */
403 err |= UTP_WRITEREG(utp, IDTPHY_REGO_INT,
404 IDTPHY_REGM_INT_RXSOHI, IDTPHY_REGM_INT_RXSOHI);
405 err |= UTP_WRITEREG(utp, IDTPHY_REGO_RSOC,
406 IDTPHY_REGM_RSOC_LOSI, IDTPHY_REGM_RSOC_LOSI);
408 return (err ? EIO : 0);
412 * Reset the chip to reflect the current state of utopia.
415 idt77155_reset(struct utopia *utp)
419 if (!(utp->flags & UTP_FL_NORESET)) {
420 err |= UTP_WRITEREG(utp, IDTPHY_REGO_MRID,
421 IDTPHY_REGM_MRID_RESET, IDTPHY_REGM_MRID_RESET);
422 err |= UTP_WRITEREG(utp, IDTPHY_REGO_MRID,
423 IDTPHY_REGM_MRID_RESET, 0);
426 err |= idt77155_set_chip(utp);
428 return (err ? EIO : 0);
432 * Update statistics from a IDT77155
433 * This appears to be the same as for the Suni/Lite and Ultra. IDT however
434 * makes no assessment about the transfer time. Assume 7us.
437 idt77155_update_stats(struct utopia *utp)
441 /* write to the master if we can */
442 if (!(utp->flags & UTP_FL_NORESET)) {
443 err = UTP_WRITEREG(utp, IDTPHY_REGO_MRID, 0, 0);
445 err = UTP_WRITEREG(utp, IDTPHY_REGO_BIPC, 0, 0);
446 err |= UTP_WRITEREG(utp, IDTPHY_REGO_B2EC, 0, 0);
447 err |= UTP_WRITEREG(utp, IDTPHY_REGO_B3EC, 0, 0);
448 err |= UTP_WRITEREG(utp, IDTPHY_REGO_CEC, 0, 0);
449 err |= UTP_WRITEREG(utp, IDTPHY_REGO_TXCNT, 0, 0);
454 printf("%s: register write error %s: %d\n", __func__,
455 utp->chip->name, err);
462 utp->stats.rx_sbip += utopia_update(utp,
463 IDTPHY_REGO_BIPC, 2, 0xffff);
464 utp->stats.rx_lbip += utopia_update(utp,
465 IDTPHY_REGO_B2EC, 3, 0xfffff);
466 utp->stats.rx_lfebe += utopia_update(utp,
467 IDTPHY_REGO_FEBEC, 3, 0xfffff);
468 utp->stats.rx_pbip += utopia_update(utp,
469 IDTPHY_REGO_B3EC, 2, 0xffff);
470 utp->stats.rx_pfebe += utopia_update(utp,
471 IDTPHY_REGO_PFEBEC, 2, 0xffff);
472 utp->stats.rx_corr += utopia_update(utp,
473 IDTPHY_REGO_CEC, 1, 0xff);
474 utp->stats.rx_uncorr += utopia_update(utp,
475 IDTPHY_REGO_UEC, 1, 0xff);
476 utp->stats.rx_cells += utopia_update(utp,
477 IDTPHY_REGO_RCCNT, 3, 0x7ffff);
478 utp->stats.tx_cells += utopia_update(utp,
479 IDTPHY_REGO_TXCNT, 3, 0x7ffff);
482 const struct utopia_chip utopia_chip_idt77155 = {
489 idt77155_set_noscramb,
490 idt77155_update_carrier,
491 idt77155_set_loopback,
493 idt77155_update_stats,