/* * Clock a series of bits through the MII. */ void ste_mii_send(struct ste_softc *sc, u_int32_t bits, int cnt) { int i; MII_CLR(STE_PHYCTL_MCLK); for (i = (0x1 << (cnt - 1)); i; i >>= 1) { if (bits & i) { MII_SET(STE_PHYCTL_MDATA); } else { MII_CLR(STE_PHYCTL_MDATA); } DELAY(1); MII_CLR(STE_PHYCTL_MCLK); DELAY(1); MII_SET(STE_PHYCTL_MCLK); } }
/* * Write to a PHY register through the MII. */ int ste_mii_writereg(struct ste_softc *sc, struct ste_mii_frame *frame) { int s; s = splnet(); /* * Set up frame for TX. */ frame->mii_stdelim = STE_MII_STARTDELIM; frame->mii_opcode = STE_MII_WRITEOP; frame->mii_turnaround = STE_MII_TURNAROUND; /* * Turn on data output. */ MII_SET(STE_PHYCTL_MDIR); ste_mii_sync(sc); ste_mii_send(sc, frame->mii_stdelim, 2); ste_mii_send(sc, frame->mii_opcode, 2); ste_mii_send(sc, frame->mii_phyaddr, 5); ste_mii_send(sc, frame->mii_regaddr, 5); ste_mii_send(sc, frame->mii_turnaround, 2); ste_mii_send(sc, frame->mii_data, 16); /* Idle bit. */ MII_SET(STE_PHYCTL_MCLK); DELAY(1); MII_CLR(STE_PHYCTL_MCLK); DELAY(1); /* * Turn off xmit. */ MII_CLR(STE_PHYCTL_MDIR); splx(s); return(0); }
/* * Clock a series of bits through the MII. */ static void rtk_mii_send(struct rtk_softc *sc, uint32_t bits, int cnt) { int i; MII_CLR(RTK_MII_CLK); for (i = cnt; i > 0; i--) { if (bits & (1 << (i - 1))) { MII_SET(RTK_MII_DATAOUT); } else { MII_CLR(RTK_MII_DATAOUT); } DELAY(1); MII_CLR(RTK_MII_CLK); DELAY(1); MII_SET(RTK_MII_CLK); } }
/* * Sync the PHYs by setting data bit and strobing the clock 32 times. */ void ste_mii_sync(struct ste_softc *sc) { int i; MII_SET(STE_PHYCTL_MDIR|STE_PHYCTL_MDATA); for (i = 0; i < 32; i++) { MII_SET(STE_PHYCTL_MCLK); DELAY(1); MII_CLR(STE_PHYCTL_MCLK); DELAY(1); } }
/* * Sync the PHYs by setting data bit and strobing the clock 32 times. */ static void rtk_mii_sync(struct rtk_softc *sc) { int i; MII_SET(RTK_MII_DIR|RTK_MII_DATAOUT); for (i = 0; i < 32; i++) { MII_SET(RTK_MII_CLK); DELAY(1); MII_CLR(RTK_MII_CLK); DELAY(1); } }
/* * Read an PHY register through the MII. */ int ste_mii_readreg(struct ste_softc *sc, struct ste_mii_frame *frame) { int ack, i, s; s = splnet(); /* * Set up frame for RX. */ frame->mii_stdelim = STE_MII_STARTDELIM; frame->mii_opcode = STE_MII_READOP; frame->mii_turnaround = 0; frame->mii_data = 0; CSR_WRITE_2(sc, STE_PHYCTL, 0); /* * Turn on data xmit. */ MII_SET(STE_PHYCTL_MDIR); ste_mii_sync(sc); /* * Send command/address info. */ ste_mii_send(sc, frame->mii_stdelim, 2); ste_mii_send(sc, frame->mii_opcode, 2); ste_mii_send(sc, frame->mii_phyaddr, 5); ste_mii_send(sc, frame->mii_regaddr, 5); /* Turn off xmit. */ MII_CLR(STE_PHYCTL_MDIR); /* Idle bit */ MII_CLR((STE_PHYCTL_MCLK|STE_PHYCTL_MDATA)); DELAY(1); MII_SET(STE_PHYCTL_MCLK); DELAY(1); /* Check for ack */ MII_CLR(STE_PHYCTL_MCLK); DELAY(1); ack = CSR_READ_2(sc, STE_PHYCTL) & STE_PHYCTL_MDATA; MII_SET(STE_PHYCTL_MCLK); DELAY(1); /* * Now try reading data bits. If the ack failed, we still * need to clock through 16 cycles to keep the PHY(s) in sync. */ if (ack) { for(i = 0; i < 16; i++) { MII_CLR(STE_PHYCTL_MCLK); DELAY(1); MII_SET(STE_PHYCTL_MCLK); DELAY(1); } goto fail; } for (i = 0x8000; i; i >>= 1) { MII_CLR(STE_PHYCTL_MCLK); DELAY(1); if (!ack) { if (CSR_READ_2(sc, STE_PHYCTL) & STE_PHYCTL_MDATA) frame->mii_data |= i; DELAY(1); } MII_SET(STE_PHYCTL_MCLK); DELAY(1); } fail: MII_CLR(STE_PHYCTL_MCLK); DELAY(1); MII_SET(STE_PHYCTL_MCLK); DELAY(1); splx(s); if (ack) return(1); return(0); }
/* * Read an PHY register through the MII. */ static int rtk_mii_readreg(struct rtk_softc *sc, struct rtk_mii_frame *frame) { int i, ack, s; s = splnet(); /* * Set up frame for RX. */ frame->mii_stdelim = RTK_MII_STARTDELIM; frame->mii_opcode = RTK_MII_READOP; frame->mii_turnaround = 0; frame->mii_data = 0; CSR_WRITE_2(sc, RTK_MII, 0); /* * Turn on data xmit. */ MII_SET(RTK_MII_DIR); rtk_mii_sync(sc); /* * Send command/address info. */ rtk_mii_send(sc, frame->mii_stdelim, 2); rtk_mii_send(sc, frame->mii_opcode, 2); rtk_mii_send(sc, frame->mii_phyaddr, 5); rtk_mii_send(sc, frame->mii_regaddr, 5); /* Idle bit */ MII_CLR((RTK_MII_CLK|RTK_MII_DATAOUT)); DELAY(1); MII_SET(RTK_MII_CLK); DELAY(1); /* Turn off xmit. */ MII_CLR(RTK_MII_DIR); /* Check for ack */ MII_CLR(RTK_MII_CLK); DELAY(1); ack = CSR_READ_2(sc, RTK_MII) & RTK_MII_DATAIN; MII_SET(RTK_MII_CLK); DELAY(1); /* * Now try reading data bits. If the ack failed, we still * need to clock through 16 cycles to keep the PHY(s) in sync. */ if (ack) { for (i = 0; i < 16; i++) { MII_CLR(RTK_MII_CLK); DELAY(1); MII_SET(RTK_MII_CLK); DELAY(1); } goto fail; } for (i = 16; i > 0; i--) { MII_CLR(RTK_MII_CLK); DELAY(1); if (!ack) { if (CSR_READ_2(sc, RTK_MII) & RTK_MII_DATAIN) frame->mii_data |= 1 << (i - 1); DELAY(1); } MII_SET(RTK_MII_CLK); DELAY(1); } fail: MII_CLR(RTK_MII_CLK); DELAY(1); MII_SET(RTK_MII_CLK); DELAY(1); splx(s); if (ack) return 1; return 0; }