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/param.h> 40 #include <sys/systm.h> 41 #include <sys/module.h> 42 43 #include <dev/mii/mii.h> 44 #include <dev/mii/mii_bitbang.h> 45 46 MODULE_VERSION(mii_bitbang, 1); 47 48 static void mii_bitbang_sendbits(device_t dev, mii_bitbang_ops_t ops, 49 uint32_t data, int nbits); 50 51 #define MWRITE(x) \ 52 do { \ 53 ops->mbo_write(dev, (x)); \ 54 DELAY(1); \ 55 } while (/* CONSTCOND */ 0) 56 57 #define MREAD ops->mbo_read(dev) 58 59 #define MDO ops->mbo_bits[MII_BIT_MDO] 60 #define MDI ops->mbo_bits[MII_BIT_MDI] 61 #define MDC ops->mbo_bits[MII_BIT_MDC] 62 #define MDIRPHY ops->mbo_bits[MII_BIT_DIR_HOST_PHY] 63 #define MDIRHOST ops->mbo_bits[MII_BIT_DIR_PHY_HOST] 64 65 /* 66 * mii_bitbang_sync: 67 * 68 * Synchronize the MII. 69 */ 70 void 71 mii_bitbang_sync(device_t dev, mii_bitbang_ops_t ops) 72 { 73 int i; 74 uint32_t v; 75 76 v = MDIRPHY | MDO; 77 78 MWRITE(v); 79 for (i = 0; i < 32; i++) { 80 MWRITE(v | MDC); 81 MWRITE(v); 82 } 83 } 84 85 /* 86 * mii_bitbang_sendbits: 87 * 88 * Send a series of bits to the MII. 89 */ 90 static void 91 mii_bitbang_sendbits(device_t dev, mii_bitbang_ops_t ops, uint32_t data, 92 int nbits) 93 { 94 int i; 95 uint32_t v; 96 97 v = MDIRPHY; 98 MWRITE(v); 99 100 for (i = 1 << (nbits - 1); i != 0; i >>= 1) { 101 if (data & i) 102 v |= MDO; 103 else 104 v &= ~MDO; 105 MWRITE(v); 106 MWRITE(v | MDC); 107 MWRITE(v); 108 } 109 } 110 111 /* 112 * mii_bitbang_readreg: 113 * 114 * Read a PHY register by bit-bang'ing the MII. 115 */ 116 int 117 mii_bitbang_readreg(device_t dev, mii_bitbang_ops_t ops, int phy, int reg) 118 { 119 int i, error, val; 120 121 mii_bitbang_sync(dev, ops); 122 123 mii_bitbang_sendbits(dev, ops, MII_COMMAND_START, 2); 124 mii_bitbang_sendbits(dev, ops, MII_COMMAND_READ, 2); 125 mii_bitbang_sendbits(dev, ops, phy, 5); 126 mii_bitbang_sendbits(dev, ops, reg, 5); 127 128 /* Switch direction to PHY->host, without a clock transition. */ 129 MWRITE(MDIRHOST); 130 131 /* Turnaround clock. */ 132 MWRITE(MDIRHOST | MDC); 133 MWRITE(MDIRHOST); 134 135 /* Check for error. */ 136 error = MREAD & MDI; 137 138 /* Idle clock. */ 139 MWRITE(MDIRHOST | MDC); 140 MWRITE(MDIRHOST); 141 142 val = 0; 143 for (i = 0; i < 16; i++) { 144 val <<= 1; 145 /* Read data prior to clock low-high transition. */ 146 if (error == 0 && (MREAD & MDI) != 0) 147 val |= 1; 148 149 MWRITE(MDIRHOST | MDC); 150 MWRITE(MDIRHOST); 151 } 152 153 /* Set direction to host->PHY, without a clock transition. */ 154 MWRITE(MDIRPHY); 155 156 return (error != 0 ? 0 : val); 157 } 158 159 /* 160 * mii_bitbang_writereg: 161 * 162 * Write a PHY register by bit-bang'ing the MII. 163 */ 164 void 165 mii_bitbang_writereg(device_t dev, mii_bitbang_ops_t ops, int phy, int reg, 166 int val) 167 { 168 169 mii_bitbang_sync(dev, ops); 170 171 mii_bitbang_sendbits(dev, ops, MII_COMMAND_START, 2); 172 mii_bitbang_sendbits(dev, ops, MII_COMMAND_WRITE, 2); 173 mii_bitbang_sendbits(dev, ops, phy, 5); 174 mii_bitbang_sendbits(dev, ops, reg, 5); 175 mii_bitbang_sendbits(dev, ops, MII_COMMAND_ACK, 2); 176 mii_bitbang_sendbits(dev, ops, val, 16); 177 178 MWRITE(MDIRPHY); 179 } 180