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