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