1 /* $NetBSD: mii_bitbang.c,v 1.12 2008/05/04 17:06:09 xtraeme Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 1999 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 11 * NASA Ames Research Center. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following didevlaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following didevlaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * Common module for bit-bang'ing the MII. 37 */ 38 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/module.h> 45 46 #include <dev/mii/mii.h> 47 #include <dev/mii/mii_bitbang.h> 48 49 MODULE_VERSION(mii_bitbang, 1); 50 51 static void mii_bitbang_sendbits(device_t dev, mii_bitbang_ops_t ops, 52 uint32_t data, int nbits); 53 54 #define MWRITE(x) \ 55 do { \ 56 ops->mbo_write(dev, (x)); \ 57 DELAY(1); \ 58 } while (/* CONSTCOND */ 0) 59 60 #define MREAD ops->mbo_read(dev) 61 62 #define MDO ops->mbo_bits[MII_BIT_MDO] 63 #define MDI ops->mbo_bits[MII_BIT_MDI] 64 #define MDC ops->mbo_bits[MII_BIT_MDC] 65 #define MDIRPHY ops->mbo_bits[MII_BIT_DIR_HOST_PHY] 66 #define MDIRHOST ops->mbo_bits[MII_BIT_DIR_PHY_HOST] 67 68 /* 69 * mii_bitbang_sync: 70 * 71 * Synchronize the MII. 72 */ 73 void 74 mii_bitbang_sync(device_t dev, mii_bitbang_ops_t ops) 75 { 76 int i; 77 uint32_t v; 78 79 v = MDIRPHY | MDO; 80 81 MWRITE(v); 82 for (i = 0; i < 32; i++) { 83 MWRITE(v | MDC); 84 MWRITE(v); 85 } 86 } 87 88 /* 89 * mii_bitbang_sendbits: 90 * 91 * Send a series of bits to the MII. 92 */ 93 static void 94 mii_bitbang_sendbits(device_t dev, mii_bitbang_ops_t ops, uint32_t data, 95 int nbits) 96 { 97 int i; 98 uint32_t v; 99 100 v = MDIRPHY; 101 MWRITE(v); 102 103 for (i = 1 << (nbits - 1); i != 0; i >>= 1) { 104 if (data & i) 105 v |= MDO; 106 else 107 v &= ~MDO; 108 MWRITE(v); 109 MWRITE(v | MDC); 110 MWRITE(v); 111 } 112 } 113 114 /* 115 * mii_bitbang_readreg: 116 * 117 * Read a PHY register by bit-bang'ing the MII. 118 */ 119 int 120 mii_bitbang_readreg(device_t dev, mii_bitbang_ops_t ops, int phy, int reg) 121 { 122 int i, error, val; 123 124 mii_bitbang_sync(dev, ops); 125 126 mii_bitbang_sendbits(dev, ops, MII_COMMAND_START, 2); 127 mii_bitbang_sendbits(dev, ops, MII_COMMAND_READ, 2); 128 mii_bitbang_sendbits(dev, ops, phy, 5); 129 mii_bitbang_sendbits(dev, ops, reg, 5); 130 131 /* Switch direction to PHY->host, without a clock transition. */ 132 MWRITE(MDIRHOST); 133 134 /* Turnaround clock. */ 135 MWRITE(MDIRHOST | MDC); 136 MWRITE(MDIRHOST); 137 138 /* Check for error. */ 139 error = MREAD & MDI; 140 141 /* Idle clock. */ 142 MWRITE(MDIRHOST | MDC); 143 MWRITE(MDIRHOST); 144 145 val = 0; 146 for (i = 0; i < 16; i++) { 147 val <<= 1; 148 /* Read data prior to clock low-high transition. */ 149 if (error == 0 && (MREAD & MDI) != 0) 150 val |= 1; 151 152 MWRITE(MDIRHOST | MDC); 153 MWRITE(MDIRHOST); 154 } 155 156 /* Set direction to host->PHY, without a clock transition. */ 157 MWRITE(MDIRPHY); 158 159 return (error != 0 ? 0 : val); 160 } 161 162 /* 163 * mii_bitbang_writereg: 164 * 165 * Write a PHY register by bit-bang'ing the MII. 166 */ 167 void 168 mii_bitbang_writereg(device_t dev, mii_bitbang_ops_t ops, int phy, int reg, 169 int val) 170 { 171 172 mii_bitbang_sync(dev, ops); 173 174 mii_bitbang_sendbits(dev, ops, MII_COMMAND_START, 2); 175 mii_bitbang_sendbits(dev, ops, MII_COMMAND_WRITE, 2); 176 mii_bitbang_sendbits(dev, ops, phy, 5); 177 mii_bitbang_sendbits(dev, ops, reg, 5); 178 mii_bitbang_sendbits(dev, ops, MII_COMMAND_ACK, 2); 179 mii_bitbang_sendbits(dev, ops, val, 16); 180 181 MWRITE(MDIRPHY); 182 } 183