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 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.12 2008/05/04 17:06:09 xtraeme 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) \ |
47 | do { \ |
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 | */ |
65 | static void |
66 | mii_bitbang_sync(device_t sc, mii_bitbang_ops_t ops) |
67 | { |
68 | int i; |
69 | u_int32_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 | */ |
85 | static void |
86 | mii_bitbang_sendbits(device_t sc, mii_bitbang_ops_t ops, uint32_t data, |
87 | int nbits) |
88 | { |
89 | int i; |
90 | u_int32_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 | */ |
111 | int |
112 | mii_bitbang_readreg(device_t sc, mii_bitbang_ops_t ops, int phy, int reg) |
113 | { |
114 | int val = 0, err = 0, i; |
115 | |
116 | mii_bitbang_sync(sc, ops); |
117 | |
118 | mii_bitbang_sendbits(sc, ops, MII_COMMAND_START, 2); |
119 | mii_bitbang_sendbits(sc, ops, MII_COMMAND_READ, 2); |
120 | mii_bitbang_sendbits(sc, ops, phy, 5); |
121 | mii_bitbang_sendbits(sc, ops, reg, 5); |
122 | |
123 | /* Switch direction to PHY->host, without a clock transition. */ |
124 | WRITE(MDIRHOST); |
125 | |
126 | /* Turnaround clock. */ |
127 | WRITE(MDIRHOST | MDC); |
128 | WRITE(MDIRHOST); |
129 | |
130 | /* Check for error. */ |
131 | err = READ & MDI; |
132 | |
133 | /* Idle clock. */ |
134 | WRITE(MDIRHOST | MDC); |
135 | WRITE(MDIRHOST); |
136 | |
137 | for (i = 0; i < 16; i++) { |
138 | val <<= 1; |
139 | /* Read data prior to clock low-high transition. */ |
140 | if (err == 0 && (READ & MDI) != 0) |
141 | val |= 1; |
142 | |
143 | WRITE(MDIRHOST | MDC); |
144 | WRITE(MDIRHOST); |
145 | } |
146 | |
147 | /* Set direction to host->PHY, without a clock transition. */ |
148 | WRITE(MDIRPHY); |
149 | |
150 | return (err ? 0 : val); |
151 | } |
152 | |
153 | /* |
154 | * mii_bitbang_writereg: |
155 | * |
156 | * Write a PHY register by bit-bang'ing the MII. |
157 | */ |
158 | void |
159 | mii_bitbang_writereg(device_t sc, mii_bitbang_ops_t ops, int phy, |
160 | int reg, int val) |
161 | { |
162 | |
163 | mii_bitbang_sync(sc, ops); |
164 | |
165 | mii_bitbang_sendbits(sc, ops, MII_COMMAND_START, 2); |
166 | mii_bitbang_sendbits(sc, ops, MII_COMMAND_WRITE, 2); |
167 | mii_bitbang_sendbits(sc, ops, phy, 5); |
168 | mii_bitbang_sendbits(sc, ops, reg, 5); |
169 | mii_bitbang_sendbits(sc, ops, MII_COMMAND_ACK, 2); |
170 | mii_bitbang_sendbits(sc, ops, val, 16); |
171 | |
172 | WRITE(MDIRPHY); |
173 | } |
174 | |