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